首先对于RPC来讲,最主要的无非三点【SERVER IO模型】、【序列化协议】、【client连接池复用】,之前的博客大家应该对thrift有一个大致的了解了,那么我们现在来说一说如何将thrift的序列化和传输使用到生产中。先放一张作者自己写的一个rpc架构图。

分成几个主要部分:

1:server启动zk注册

2:client监听watch节点变动维护本地缓存,构建tcp连接池。

3:通过java aop代理获得接口代理实现,从而通过thrift序列化传输二进制自定义协议的字节流

4:server通过reactor主从模型来实现高性能服务端。

5:调用端数据上报,形成trace链路,数据大盘,TP99,可用率等。

先看一下使用方式

客户端有两种,第一种xml 使用

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:koalas="http://www.koalas.com/schema/ch"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.koalas.com/schema/ch
http://www.koalas.com/schema/ch.xsd"> <koalas:client id="koalasService"
serviceInterface="thrift.service.koalasService"
zkPath="127.0.0.1:2181"/> </beans>
package thrift.service;

import org.apache.thrift.TException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import thrift.domain.KoalasRequest;
import thrift.domain.koalasRespone; @Service("testService")
public class TestService { @Autowired
KoalasTestService.Iface koalastestService; public void getRemoteRpc() throws TException { KoalasRequest request= new KoalasRequest ( );
request.setxxxx1 ( 1 );
request.setxxxx2( 1 );
request.setxxxxx3 ( 1 );
request.setxxxx4 ( "你好" );
request.setxxxx5 ( 1 );
KoalastestRespone respone = koalastestService.getRPC ( request);
System.out.println (respone);
}
}

第二种使用方式 注解形式

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:koalas="http://www.koalas.com/schema/ch"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.koalas.com/schema/ch
http://www.koalas.com/schema/ch.xsd"> <koalas:annotation package="thrift.annotation.client.impl"/>
</beans>
@Service("testServiceSync")
public class TestServiceSync { @KoalasClient(zkPath = "127.0.0.1:2181",readTimeout = 5000*1000)
KoalasTestService.Iface koalastestService; public void getRemoteRpc() throws TException {
KoalasRequest request= new KoalasRequest ( );
//request.setSource ( 10 );
request.setxxxxx1 ( 1 );
request.setxxxxx2 ( 1 );
request.setxxxxx3 ( 1 );
request.setxxxxx4 ( "你好啊-我是注解实现的" );
request.setxxxxx5 ( 1 );
KoalasRespone respone = koalastestService.getRPC ( request);
System.out.println (respone);
} }

简单吧,一行xml配合一个注解,client的实现这样就完成了。。。关于服务端的使用去看我git上面的wiki吧,博客中不做多说明了,这次主要讲源码。

首先看client的主要代理类入口client.proxyfactory.KoalasClientProxy,这个类的作用是所有的client服务端通过thrift的代理都通过他来完成,放出源码如下

package client.proxyfactory;

import client.cluster.ILoadBalancer;
import client.cluster.Icluster;
import client.cluster.impl.DirectClisterImpl;
import client.cluster.impl.RandomLoadBalancer;
import client.cluster.impl.ZookeeperClisterImpl;
import client.invoker.KoalsaMothodInterceptor;
import client.invoker.LocalMockInterceptor;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.pool2.impl.AbandonedConfig;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.apache.thrift.async.TAsyncClientManager;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.protocol.TProtocolFactory;
import org.apache.thrift.transport.TNonblockingTransport;
import org.apache.thrift.transport.TTransport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import protocol.KoalasBinaryProtocol;
import transport.TKoalasFramedTransport; import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; /**
* Copyright (C) 2018
* All rights reserved
* User: yulong.zhang
* Date:2018年09月18日17:44:58
*/
public class KoalasClientProxy implements FactoryBean<Object>, ApplicationContextAware, InitializingBean {
private final static Logger logger = LoggerFactory.getLogger ( KoalasClientProxy.class );
public static final String ASYNC_IFACE = "AsyncIface";
public static final String IFACE = "Iface";
public static final String CLIENT = "Client";
public static final String ASYNC_CLIENT = "AsyncClient";
//请求体最大长度
public static final int DEFUAL_MAXLENGTH = 10 * 1024 * 1024;
//连接超时
public static final int DEFUAL_CONNTIMEOUT = 5*1000;
//读取超时
public static final int DEFUAL_READTIMEOUT = 30*1000; //client端service
private Class<?> serviceInterface;
// 方式1:zk管理的动态集群,格式192.168.3.253:6666
private String zkPath;
// 方式2:指定的server列表,逗号分隔,#分隔权重,格式192.168.3.253:6666#10,192.168.3.253:6667#10
private String serverIpPorts; //代理对象,所有client-server类型统一代理
private Object loalsServiceProxy;
//spring上下文对象
private ApplicationContext applicationContext;
// 同步还是异步,默认同步。
private boolean async = false;
//连接超时时间
private int connTimeout=DEFUAL_CONNTIMEOUT;
//读取超时时间
private int readTimeout=DEFUAL_READTIMEOUT;
//本地client测试用实现
private String localMockServiceImpl;
//重试
private boolean retryRequest = true;
private int retryTimes = 3;
private GenericObjectPoolConfig genericObjectPoolConfig;
//最大连接数
private int maxTotal=100;
//最大闲置数
private int maxIdle=50;
//最小闲置数量
private int minIdle=10;
private boolean lifo = true;
private boolean fairness = false;
private long maxWaitMillis = 30 * 1000;
//多长时间运行一次
private long timeBetweenEvictionRunsMillis = 3 * 60 * 1000;
private long minEvictableIdleTimeMillis = 5 * 60 * 1000; //对象空闲多久后逐出, 当空闲时间>该值 且 空闲连接>最大空闲数 时直接逐出,
//不再根据MinEvictableIdleTimeMillis判断 (默认逐出策略)
private long softMinEvictableIdleTimeMillis = 10 * 60 * 1000;
private int numTestsPerEvictionRun = 20;
private boolean testOnCreate = false;
private boolean testOnBorrow = false;
private boolean testOnReturn = false;
private boolean testWhileIdle = true;
private Icluster icluster;
private ILoadBalancer iLoadBalancer;
private String env="dev";
AbandonedConfig abandonedConfig;
private boolean removeAbandonedOnBorrow = true;
private boolean removeAbandonedOnMaintenance = true;
private int removeAbandonedTimeout = 30;
private int maxLength_ = DEFUAL_MAXLENGTH;
private static int cores = Runtime.getRuntime().availableProcessors();
private int asyncSelectorThreadCount = cores * 2;
private static List<TAsyncClientManager> asyncClientManagerList = null; private String privateKey;
private String publicKey; public String getPrivateKey() {
return privateKey;
} public void setPrivateKey(String privateKey) {
this.privateKey = privateKey;
} public String getPublicKey() {
return publicKey;
} public void setPublicKey(String publicKey) {
this.publicKey = publicKey;
} public int getMaxLength_() {
return maxLength_;
} public void setMaxLength_(int maxLength_) {
this.maxLength_ = maxLength_;
} public int getMaxTotal() {
return maxTotal;
} public void setMaxTotal(int maxTotal) {
this.maxTotal = maxTotal;
} public int getMaxIdle() {
return maxIdle;
} public void setMaxIdle(int maxIdle) {
this.maxIdle = maxIdle;
} public int getMinIdle() {
return minIdle;
} public void setMinIdle(int minIdle) {
this.minIdle = minIdle;
} public boolean isLifo() {
return lifo;
} public void setLifo(boolean lifo) {
this.lifo = lifo;
} public boolean isFairness() {
return fairness;
} public void setFairness(boolean fairness) {
this.fairness = fairness;
} public long getMaxWaitMillis() {
return maxWaitMillis;
} public void setMaxWaitMillis(long maxWaitMillis) {
this.maxWaitMillis = maxWaitMillis;
} public long getTimeBetweenEvictionRunsMillis() {
return timeBetweenEvictionRunsMillis;
} public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
} public long getMinEvictableIdleTimeMillis() {
return minEvictableIdleTimeMillis;
} public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
} public long getSoftMinEvictableIdleTimeMillis() {
return softMinEvictableIdleTimeMillis;
} public void setSoftMinEvictableIdleTimeMillis(long softMinEvictableIdleTimeMillis) {
this.softMinEvictableIdleTimeMillis = softMinEvictableIdleTimeMillis;
} public int getNumTestsPerEvictionRun() {
return numTestsPerEvictionRun;
} public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
this.numTestsPerEvictionRun = numTestsPerEvictionRun;
} public boolean isTestOnCreate() {
return testOnCreate;
} public void setTestOnCreate(boolean testOnCreate) {
this.testOnCreate = testOnCreate;
} public boolean isTestOnBorrow() {
return testOnBorrow;
} public void setTestOnBorrow(boolean testOnBorrow) {
this.testOnBorrow = testOnBorrow;
} public boolean isTestOnReturn() {
return testOnReturn;
} public void setTestOnReturn(boolean testOnReturn) {
this.testOnReturn = testOnReturn;
} public boolean isTestWhileIdle() {
return testWhileIdle;
} public void setTestWhileIdle(boolean testWhileIdle) {
this.testWhileIdle = testWhileIdle;
} public String getLocalMockServiceImpl() {
return localMockServiceImpl;
} public void setLocalMockServiceImpl(String localMockServiceImpl) {
this.localMockServiceImpl = localMockServiceImpl;
} public int getReadTimeout() {
return readTimeout;
} public void setReadTimeout(int readTimeout) {
this.readTimeout = readTimeout;
} public int getConnTimeout() {
return connTimeout;
} public void setConnTimeout(int connTimeout) {
this.connTimeout = connTimeout;
} public String getZkPath() {
return zkPath;
} public void setZkPath(String zkPath) {
this.zkPath = zkPath;
} public String getServerIpPorts() {
return serverIpPorts;
} public void setServerIpPorts(String serverIpPorts) {
this.serverIpPorts = serverIpPorts;
} public boolean isAsync() {
return async;
} public void setAsync(boolean async) {
this.async = async;
} public Object getLoalsServiceProxy() {
return loalsServiceProxy;
} public void setLoalsServiceProxy(Object loalsServiceProxy) {
this.loalsServiceProxy = loalsServiceProxy;
} public ApplicationContext getApplicationContext() {
return applicationContext;
} public Class<?> getServiceInterface() {
return serviceInterface;
} public void setServiceInterface(Class<?> serviceInterface) {
this.serviceInterface = serviceInterface;
} public ILoadBalancer getiLoadBalancer() {
return iLoadBalancer;
} public void setiLoadBalancer(ILoadBalancer iLoadBalancer) {
this.iLoadBalancer = iLoadBalancer;
} public boolean isRemoveAbandonedOnBorrow() {
return removeAbandonedOnBorrow;
} public void setRemoveAbandonedOnBorrow(boolean removeAbandonedOnBorrow) {
this.removeAbandonedOnBorrow = removeAbandonedOnBorrow;
} public boolean isRemoveAbandonedOnMaintenance() {
return removeAbandonedOnMaintenance;
} public void setRemoveAbandonedOnMaintenance(boolean removeAbandonedOnMaintenance) {
this.removeAbandonedOnMaintenance = removeAbandonedOnMaintenance;
} public int getRemoveAbandonedTimeout() {
return removeAbandonedTimeout;
} public void setRemoveAbandonedTimeout(int removeAbandonedTimeout) {
this.removeAbandonedTimeout = removeAbandonedTimeout;
} public boolean isRetryRequest() {
return retryRequest;
} public void setRetryRequest(boolean retryRequest) {
this.retryRequest = retryRequest;
} public int getRetryTimes() {
return retryTimes;
} public void setRetryTimes(int retryTimes) {
this.retryTimes = retryTimes;
} public String getEnv() {
return env;
}
public void setEnv(String env) {
this.env = env;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
} @Override
public Object getObject(){
if (getLoalsServiceProxy () == null) throw new RuntimeException ( "the Proxy can't be null" );
return getLoalsServiceProxy ();
} @Override
public Class<?> getObjectType() {
if (serviceInterface == null)
return null;
return getIfaceInterface ();
} private Class<?> getIfaceInterface() {
if (async)
return getAsyncIfaceInterface ();
else
return getSynIfaceInterface ();
} private Constructor<?> synConstructor;
private Constructor<?> asyncConstructor; public Object getInterfaceClientInstance(TTransport socket,String server) { if (!async) {
Class<?> clazz = getSynClientClass ();
try {
if (synConstructor == null) {
synConstructor = clazz.getDeclaredConstructor ( TProtocol.class );
}
TTransport transport = new TKoalasFramedTransport ( socket, maxLength_ );
if(this.getPrivateKey ()!=null && this.getPublicKey () != null){
((TKoalasFramedTransport) transport).setRsa ( (byte) 1 );
((TKoalasFramedTransport) transport).setPrivateKey ( this.privateKey );
((TKoalasFramedTransport) transport).setPublicKey ( this.publicKey );
} TProtocol protocol = new KoalasBinaryProtocol ( transport ); return synConstructor.newInstance ( protocol ); } catch (NoSuchMethodException e) {
logger.error ( "the clazz can't find the Constructor with TProtocol.class" );
} catch (InstantiationException e) {
logger.error ( "get InstantiationException", e );
} catch (IllegalAccessException e) {
logger.error ( "get IllegalAccessException", e );
} catch (InvocationTargetException e) {
logger.error ( "get InvocationTargetException", e );
}
} else {
if (null == asyncClientManagerList) {
synchronized (this) {
if (null == asyncClientManagerList) {
asyncClientManagerList = new ArrayList<> ();
for (int i = 0; i < asyncSelectorThreadCount; i++) {
try {
asyncClientManagerList.add(new TAsyncClientManager());
} catch (IOException e) {
e.printStackTrace ();
}
}
}
}
}
Class<?> clazz = getAsyncClientClass (); if (asyncConstructor == null) {
try {
asyncConstructor = clazz.getDeclaredConstructor ( TProtocolFactory.class, TAsyncClientManager.class, TNonblockingTransport.class );
} catch (NoSuchMethodException e) {
e.printStackTrace ();
}
} try {
return asyncConstructor.newInstance ( new KoalasBinaryProtocol.Factory (), asyncClientManagerList.get (socket.hashCode () % asyncSelectorThreadCount), socket );
} catch (InstantiationException e) {
logger.error ( "get InstantiationException", e );
} catch (IllegalAccessException e) {
logger.error ( "get IllegalAccessException", e );
} catch (InvocationTargetException e) {
logger.error ( "get InvocationTargetException", e );
} }
return null;
} private Class<?> getAsyncIfaceInterface() {
Class<?>[] classes = serviceInterface.getClasses ();
for (Class c : classes)
if (c.isMemberClass () && c.isInterface () && c.getSimpleName ().equals ( ASYNC_IFACE )) {
return c;
}
throw new IllegalArgumentException ( "can't find the interface AsyncIface,please make the service with thrift tools!" );
} private Class<?> getSynIfaceInterface() {
Class<?>[] classes = serviceInterface.getClasses ();
for (Class c : classes)
if (c.isMemberClass () && c.isInterface () && c.getSimpleName ().equals ( IFACE )) {
return c;
}
throw new IllegalArgumentException ( "can't find the interface Iface,please make the service with thrift tools" );
} private Class<?> getSynClientClass() {
Class<?>[] classes = serviceInterface.getClasses ();
for (Class c : classes)
if (c.isMemberClass () && !c.isInterface () && c.getSimpleName ().equals ( CLIENT )) {
return c;
}
throw new IllegalArgumentException ( "serviceInterface must contain Sub Class of Client" );
} private Class<?> getAsyncClientClass() {
Class<?>[] classes = serviceInterface.getClasses ();
for (Class c : classes)
if (c.isMemberClass () && !c.isInterface () && c.getSimpleName ().equals ( ASYNC_CLIENT )) {
return c;
}
throw new IllegalArgumentException ( "serviceInterface must contain Sub Class of AsyncClient" );
} @Override
public boolean isSingleton() {
return true;
} @Override
public void afterPropertiesSet(){ if(serviceInterface==null){
throw new IllegalArgumentException ( "serviceInterface can't be null" );
} if(zkPath==null && serverIpPorts==null){
throw new IllegalArgumentException ( "zkPath or serverIpPorts at least ones can't be null" );
} Class<?> _interface = null;
if (localMockServiceImpl != null && !StringUtils.isEmpty ( localMockServiceImpl.trim () )) {
LocalMockInterceptor localMockInterceptor = new LocalMockInterceptor ( localMockServiceImpl );
_interface = getIfaceInterface ();
ProxyFactory pf = new ProxyFactory ( _interface, localMockInterceptor );
setLoalsServiceProxy ( pf.getProxy () );
return;
} genericObjectPoolConfig = getGenericObjectPoolConfig ();
abandonedConfig = getAbandonedConfig (); if (!StringUtils.isEmpty ( serverIpPorts )) {
icluster = new DirectClisterImpl ( serverIpPorts, iLoadBalancer == null ? new RandomLoadBalancer () : iLoadBalancer, serviceInterface.getName (), async, connTimeout, readTimeout, genericObjectPoolConfig, abandonedConfig );
} else{
icluster = new ZookeeperClisterImpl ( zkPath ,iLoadBalancer == null ? new RandomLoadBalancer () : iLoadBalancer, serviceInterface.getName (),env,async,connTimeout,readTimeout,genericObjectPoolConfig,abandonedConfig);
} KoalsaMothodInterceptor koalsaMothodInterceptor = new KoalsaMothodInterceptor ( icluster, retryTimes, retryRequest, this,readTimeout );
_interface = getIfaceInterface (); loalsServiceProxy = new ProxyFactory ( _interface, koalsaMothodInterceptor ).getProxy (); logger.info ( "the service【{}】is start !", serviceInterface.getName () );
} private AbandonedConfig getAbandonedConfig() {
AbandonedConfig abandonedConfig = new AbandonedConfig ();
abandonedConfig.setRemoveAbandonedOnBorrow ( isRemoveAbandonedOnBorrow () );
abandonedConfig.setRemoveAbandonedOnMaintenance ( isRemoveAbandonedOnMaintenance () );
abandonedConfig.setRemoveAbandonedTimeout ( getRemoveAbandonedTimeout () );
return abandonedConfig;
} private GenericObjectPoolConfig getGenericObjectPoolConfig() {
GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig ();
genericObjectPoolConfig.setMaxTotal ( getMaxTotal () );
genericObjectPoolConfig.setMinIdle ( getMinIdle () );
genericObjectPoolConfig.setMaxIdle ( maxIdle );
genericObjectPoolConfig.setMaxWaitMillis ( getMaxWaitMillis () );
genericObjectPoolConfig.setLifo ( isLifo () );
genericObjectPoolConfig.setFairness ( isFairness () );
genericObjectPoolConfig.setMinEvictableIdleTimeMillis ( getMinEvictableIdleTimeMillis () );
genericObjectPoolConfig.setSoftMinEvictableIdleTimeMillis ( getSoftMinEvictableIdleTimeMillis () );
genericObjectPoolConfig.setNumTestsPerEvictionRun ( getNumTestsPerEvictionRun () );
genericObjectPoolConfig.setTimeBetweenEvictionRunsMillis ( getTimeBetweenEvictionRunsMillis () );
genericObjectPoolConfig.setTestOnCreate ( isTestOnCreate () );
genericObjectPoolConfig.setTestOnBorrow ( isTestOnBorrow () );
genericObjectPoolConfig.setTestOnReturn ( isTestOnReturn () );
genericObjectPoolConfig.setTestWhileIdle ( isTestWhileIdle () );
return genericObjectPoolConfig;
} public void destroy(){
if(icluster!= null) icluster.destroy ();
} public static void main(String[] args) {
String a = "192.168.3.253:6666#10#thrift,192.168.3.253:6667#10#netty";
System.out.println ( Arrays.toString ( a.split ( "[^0-9a-zA-Z_\\-\\.:#]+" ) ) );
}
}

首先这个类实现了FactoryBean和InitializingBean,FactoryBean的实现方法getObject就是这个代理类本身的实现了,返回的对象为全局的setKoalasServiceProxy,注意一下这块的代码

        koalasServiceProxy = new ProxyFactory ( _interface, koalsaMothodInterceptor ).getProxy ();

可以看出koalasServiceProxy为spring代理出来的对象,代理的接口是interface,也就是我们thrift自动生成class的 xxxxxx.iface

private Class<?> getSynIfaceInterface() {
Class<?>[] classes = serviceInterface.getClasses ();
for (Class c : classes)
if (c.isMemberClass () && c.isInterface () && c.getSimpleName ().equals ( IFACE )) {
return c;
}
throw new IllegalArgumentException ( "can't find the interface Iface,please make the service with thrift tools" );
}

这也就说为什么在我们的spring bean注入的类为 xxxxx.iface,对spring有一些知识的朋友一定会了解。(不懂的去学呗)

至于反射的实现肯定是在

        KoalsaMothodInterceptor koalsaMothodInterceptor = new KoalsaMothodInterceptor ( icluster, retryTimes, retryRequest, this,readTimeout );

里面了,里面的东西是什么,敬请期待下回分解!

https://gitee.com/a1234567891/koalas-rpc

koalas-RPC 个人作品,提供大家交流学习,有意见请私信,欢迎拍砖。客户端采用thrift协议,服务端支持netty和thrift的TThreadedSelectorServer半同步半异步线程模型,支持动态扩容,服务上下线,权重动态,可用性配置,页面流量统计等,持续为个人以及中小型公司提供可靠的RPC框架技术方案

更多学习内容请加高级java QQ群:825199617

JAVA RPC (六) 之手把手从零教你写一个生产级RPC之client的代理的更多相关文章

  1. JAVA RPC (七) 手把手从零教你写一个生产级RPC之client请求

    上节说了关于通用请求代理,实际上对spring的bean引用都是通过koalasClientProxy来实现的,那么在代理方法中才是我们实际的发送逻辑,咱们先看一下原生的thrift请求是什么样的. ...

  2. 只有20行Javascript代码!手把手教你写一个页面模板引擎

    http://www.toobug.net/article/how_to_design_front_end_template_engine.html http://barretlee.com/webs ...

  3. 半个小时教你写一个装(bi)逼(she)之地图搜租房

    半个小时教你写一个装(bi)逼(she)之地图搜租房 首先需要一个Python3环境,怎么准备我就不多说了,实在不会的出门右转看一下廖雪峰老师的博客. HTML部分 代码来自:高德API+Python ...

  4. 【vps】教你写一个属于自己的随机图API

    [vps]教你写一个自己的随机图API 前言 刚刚开始使用halo博客的时候,我就发现halo博客系统是可以使用随机图当背景的,所以也是使用了网上一些比较火的随机图API. 在上次发现了各种图片API ...

  5. 手把手教你写一个java的orm(五)

    生成sql:where 上一篇里我们实现了生成insert的sql,下面要开始实现update,delete,select的sql语句了.但是这些语句有一个比较麻烦的地方是:它们一般后面都会有wher ...

  6. 手把手教你写一个java的orm(一)

    写之前的说明 其实吧. 这个东西已经写好了,地址在:https://github.com/hjx601496320/JdbcPlus 这系列文章算是我写的过程的总结吧.(恩系列,说明我可能会写好久,╮ ...

  7. 手把手教你写一个RPC

    1.1 RPC 是什么 定义:RPC(Remote Procedure Call Protocol)--远程过程调用协议 ,RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数 ...

  8. 分布式系统中的RPC请求经常出现乱序的情况 写一个算法来将一个乱序的序列保序输出

    分布式系统中的RPC请求经常出现乱序的情况.  写一个算法来将一个乱序的序列保序输出.例如,假设起始序号是1,对于(1, 2, 5, 8, 10, 4, 3, 6, 9, 7)这个序列,输出是:  1 ...

  9. 教你写个简单到的 Redis Client 框架 - .NET Core

    目录 1,关于 Redis RESP 定义数据类型 2,定义异步消息状态机 3,定义命令发送模板 4,定义 Redis Client 5,实现简单的 RESP 解析 6,实现命令发送客户端 7,如何使 ...

随机推荐

  1. mysql收集统计信息

    一.手动  执行Analyze table innodb和myisam存储引擎都可以通过执行“Analyze table tablename”来收集表的统计信息,除非执行计划不准确,否则不要轻易执行该 ...

  2. SpringBoot配置

    多模块Maven项目 .gitignore文件 .idea *.iml targetout log tmp test 父模块pom文件 <?xml version="1.0" ...

  3. About the Mean Shift

    Mean Shift算法,一般是指一个迭代的过程.即先算出当前点的偏移均值,移动该点到其偏移均值,然后以此为新的起始点,继续移动,直到满足一定的条件结束. meanshift可以被用来做目标跟踪和图像 ...

  4. day17递归函数(二分法查找)

    递归函数: 如果函数包含了对其自身的调用,该函数就是递归的: example 1:二分法查找的实现: def find_recursion(l,aim,start=0,end=None): #end不 ...

  5. mysql 的crud操作(增删改查)

    1.mysql添加记录 --添加记录的语法(可添加单条记录或者多条记录),INTO是可以省略的,字段名也可以省略的,但是如果省略的话,后面对应的value的值就要全部填写 INSERT [INTO] ...

  6. sass进阶—函数

    /*内置函数*/ /*1)常规的rgb,rgba函数*/$color:rgb(255,255,162);body{ color: $color; background-color:rgba($colo ...

  7. 一JavaScript获取当前月份的前12个月,获取最近的12个月二js实现获取当前月份前的12个月份,格式化后放在一个数组里

    一 ,var dataArr = []; var data = new Date(); var year = data.getFullYear(); data.setMonth(data.getMon ...

  8. ionic 3 常见报错及解决办法

    用ionic 3开发也有一段时间了,现在总结下开发中遇到的报错,以及解决办法: ERROR DOMException: Failed to execute 'setAttribute' on 'Ele ...

  9. Vue 增删改查 demo

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  10. POJ 1985 Cow Marathon (模板题)(树的直径)

    <题目链接> 题目大意: 给定一颗树,求出树的直径. 解题分析:树的直径模板题,以下程序分别用树形DP和两次BFS来求解. 树形DP: #include <cstdio> #i ...