├── .travis.yml ├── .gitignore ├── navi-pbrpc-spring └── src │ ├── test │ ├── resources │ │ ├── autoevict │ │ │ ├── application.properties │ │ │ └── applicationContext.xml │ │ ├── ipportstring │ │ │ ├── application.properties │ │ │ └── applicationContext.xml │ │ ├── ipportstring_nagative │ │ │ ├── application.properties │ │ │ └── applicationContext.xml │ │ ├── ipportstring_pooled │ │ │ ├── application.properties │ │ │ └── applicationContext.xml │ │ ├── ipportlist │ │ │ ├── application.properties │ │ │ └── applicationContext.xml │ │ └── log4j.properties │ └── java │ │ └── com │ │ └── baidu │ │ └── beidou │ │ └── navi │ │ └── pbrpc │ │ ├── demo │ │ ├── Server.java │ │ ├── service │ │ │ └── DemoService.java │ │ └── Main.java │ │ └── spring │ │ ├── SpringIntegrationIpPortStringHATest.java │ │ ├── SpringIntegrationIpPortStringTest.java │ │ ├── SpringIntegrationIpPortListTest.java │ │ ├── SpringIntegrationIpPortStringAutoEvictTest.java │ │ └── SpringIntegrationIpPortStringPooledBlockingIOTest.java │ └── main │ └── java │ └── com │ └── baidu │ └── beidou │ └── navi │ └── pbrpc │ ├── spring │ ├── JavassistIntegrationProxy.java │ ├── IntegrationProxy.java │ ├── PbrpcProxyFactoryBean.java │ └── JdkDynamicIntegrationProxy.java │ ├── client │ ├── HAPbrpcServerLocator.java │ ├── IpPortShortLiveBlockingIOPbrpcServerLocator.java │ └── IpPortPooledBlockingIOPbrpcServerLocator.java │ └── annotation │ └── PbrpcMethodId.java ├── src ├── test │ └── java │ │ └── com │ │ └── baidu │ │ └── beidou │ │ └── navi │ │ └── pbrpc │ │ ├── it │ │ ├── ClientBuilder.java │ │ ├── NegativePbrpcClientTest.java │ │ ├── ShortAliveConnectionPbrpcClientTest.java │ │ ├── PooledPbrpcClientTest.java │ │ ├── BlockingIOPbrpcClientTest.java │ │ ├── BlockingIOPooledPbrpcClientTest.java │ │ └── ComplicatedResponsePbrpcClientTest.java │ │ ├── util │ │ ├── IdGeneratorTest.java │ │ └── PreconditionsTest.java │ │ ├── server │ │ ├── PbrpcServerMainTest.java │ │ ├── NegativeServiceImpl.java │ │ └── ServiceLocatorTest.java │ │ ├── demo │ │ ├── Server.java │ │ ├── service │ │ │ ├── DemoService.java │ │ │ └── impl │ │ │ │ └── DemoServiceImpl.java │ │ └── Main.java │ │ ├── codec │ │ └── impl │ │ │ └── ProtobufCodecTest.java │ │ └── client │ │ ├── HAPbrpcClientMainTest.java │ │ ├── ShortLiveConnectionPbrpcClientMainTest.java │ │ └── BlockingIOPooledPbrpcClientMainTest.java └── main │ ├── resources │ └── log4j.properties │ └── java │ └── com │ └── baidu │ └── beidou │ └── navi │ └── pbrpc │ ├── server │ ├── core │ │ ├── MethodResolver.java │ │ ├── ServiceLocator.java │ │ ├── impl │ │ │ ├── SimpleMethodResolver.java │ │ │ └── IdKeyServiceLocator.java │ │ ├── ServiceDescriptor.java │ │ └── ServiceRegistry.java │ └── PbrpcServerConfiguration.java │ ├── client │ ├── callback │ │ ├── Callback.java │ │ ├── CallbackContext.java │ │ └── CallbackPool.java │ ├── ha │ │ ├── FailStrategy.java │ │ ├── FailFastStrategy.java │ │ ├── TransportCallback.java │ │ ├── DefaultTransportCallback.java │ │ ├── IpPort.java │ │ ├── FailOverStrategy.java │ │ ├── LoadBalanceStrategy.java │ │ ├── ConnectStringParser.java │ │ └── RandomLoadBalanceStrategy.java │ ├── HeaderResolver.java │ ├── PbrpcClient.java │ ├── BlockingIOPbrpcClientSocketPool.java │ ├── PbrpcClientChannelPool.java │ ├── PbrpcClientConfiguration.java │ ├── TimeoutEvictionTimer.java │ ├── NsHeaderResolver.java │ ├── TimeoutEvictor.java │ ├── PbrpcClientChannel.java │ ├── PbrpcClientChannelFactory.java │ ├── HAPbrpcClient.java │ ├── handler │ │ └── PbrpcClientHandler.java │ └── PooledPbrpcClient.java │ ├── util │ ├── Computable.java │ ├── IdGenerator.java │ ├── PbrpcConstants.java │ ├── UnsignedSwitch.java │ ├── ReflectionUtil.java │ ├── ConcurrentCache.java │ ├── ContextHolder.java │ ├── Pool.java │ └── ByteUtil.java │ ├── codec │ ├── Codec.java │ └── impl │ │ └── ProtobufCodec.java │ ├── protocol │ └── Header.java │ ├── exception │ ├── CodecException.java │ ├── TimeoutException.java │ ├── client │ │ ├── PbrpcException.java │ │ ├── HAPbrpcException.java │ │ ├── PbrpcConnectionException.java │ │ └── OperationNotSupportException.java │ ├── CommunicationException.java │ ├── ServiceNotFoundException.java │ └── ServerExecutionException.java │ ├── error │ ├── ExceptionUtil.java │ └── ErrorCode.java │ └── transport │ ├── handler │ └── RpcServerChannelIdleHandler.java │ ├── PbrpcMessageDeserializer.java │ ├── PbrpcMessageSerializer.java │ └── PbrpcMsg.java └── README.md /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | 3 | after_success: 4 | - mvn jacoco:report coveralls:report -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /bin 3 | 4 | # Eclipse 5 | /.classpath 6 | /.project 7 | /.settings 8 | 9 | # Idea 10 | *.iml 11 | .idea -------------------------------------------------------------------------------- /navi-pbrpc-spring/src/test/resources/autoevict/application.properties: -------------------------------------------------------------------------------- 1 | pbrpc.client.server=127.0.0.1:14419,127.0.0.1:14420 2 | pbrpc.client.connect.timeout=2000 3 | pbrpc.client.read.timeout=5000 -------------------------------------------------------------------------------- /navi-pbrpc-spring/src/test/resources/ipportstring/application.properties: -------------------------------------------------------------------------------- 1 | pbrpc.client.server=127.0.0.1:14419,127.0.0.1:14420 2 | pbrpc.client.connect.timeout=2000 3 | pbrpc.client.read.timeout=5000 -------------------------------------------------------------------------------- /navi-pbrpc-spring/src/test/resources/ipportstring_nagative/application.properties: -------------------------------------------------------------------------------- 1 | pbrpc.client.server=127.0.0.1:14419,127.0.0.1:9999 2 | pbrpc.client.connect.timeout=1000 3 | pbrpc.client.read.timeout=2000 -------------------------------------------------------------------------------- /navi-pbrpc-spring/src/test/resources/ipportstring_pooled/application.properties: -------------------------------------------------------------------------------- 1 | pbrpc.client.server=127.0.0.1:14419,127.0.0.1:14420 2 | pbrpc.client.connect.timeout=2000 3 | pbrpc.client.read.timeout=12000 -------------------------------------------------------------------------------- /navi-pbrpc-spring/src/test/resources/ipportlist/application.properties: -------------------------------------------------------------------------------- 1 | pbrpc.client1.ip=127.0.0.1 2 | pbrpc.client1.port=14419 3 | 4 | pbrpc.client2.ip=127.0.0.1 5 | pbrpc.client2.port=14420 6 | 7 | pbrpc.client.connect.timeout=2000 8 | pbrpc.client.read.timeout=2000 -------------------------------------------------------------------------------- /src/test/java/com/baidu/beidou/navi/pbrpc/it/ClientBuilder.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.it; 2 | 3 | import com.baidu.beidou.navi.pbrpc.client.PbrpcClient; 4 | 5 | public interface ClientBuilder { 6 | 7 | PbrpcClient getClient(); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /navi-pbrpc-spring/src/test/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootLogger=INFO, console 2 | 3 | # navi log 4 | log4j.logger.com.baidu.beidou=DEBUG 5 | 6 | log4j.appender.console=org.apache.log4j.ConsoleAppender 7 | log4j.appender.console.encoding=gbk 8 | log4j.appender.console.layout=org.apache.log4j.PatternLayout 9 | log4j.appender.console.layout.ConversionPattern=[%p]\t%d\t[%t]\t%c{3}\t(%F:%L)\t-%m%n 10 | -------------------------------------------------------------------------------- /navi-pbrpc-spring/src/main/java/com/baidu/beidou/navi/pbrpc/spring/JavassistIntegrationProxy.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.spring; 2 | 3 | /** 4 | * Javassist字节码生成代理实例对象 5 | * 6 | * @author zhangxu 7 | */ 8 | public class JavassistIntegrationProxy implements IntegrationProxy { 9 | 10 | //TODO 11 | @Override 12 | public T createProxy(Class clazz) { 13 | return null; 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/com/baidu/beidou/navi/pbrpc/util/IdGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.util; 2 | 3 | import static org.hamcrest.Matchers.greaterThan; 4 | import static org.junit.Assert.assertThat; 5 | 6 | import org.junit.Test; 7 | 8 | public class IdGeneratorTest { 9 | 10 | @Test 11 | public void testGetId() { 12 | int id = IdGenerator.genUUID(); 13 | assertThat(id, greaterThan(0)); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootLogger=INFO, console 2 | 3 | # My logging configuration... 4 | log4j.logger.com.baidu=INFO 5 | 6 | log4j.logger.io.netty=INFO 7 | 8 | ## Console output 9 | log4j.appender.console=org.apache.log4j.ConsoleAppender 10 | log4j.appender.console.encoding=gbk 11 | log4j.appender.console.layout=org.apache.log4j.PatternLayout 12 | log4j.appender.console.layout.ConversionPattern=[%p]\t%d\t[%t]\t%c{3}\t(%F:%L)\t-%m%n 13 | -------------------------------------------------------------------------------- /src/test/java/com/baidu/beidou/navi/pbrpc/server/PbrpcServerMainTest.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.server; 2 | 3 | import com.baidu.beidou.navi.pbrpc.demo.service.impl.DemoServiceImpl; 4 | 5 | 6 | public class PbrpcServerMainTest { 7 | 8 | public static void main(String[] args) { 9 | PbrpcServer server = new PbrpcServer(8088); 10 | server.register(100, new DemoServiceImpl()); 11 | server.start(); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/server/core/MethodResolver.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.server.core; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | /** 6 | * ClassName: MethodResolver
7 | * Function: 判断方法是否为可暴露服务的接口 8 | * 9 | * @author Zhang Xu 10 | */ 11 | public interface MethodResolver { 12 | 13 | /** 14 | * 方法是否可以暴露为服务 15 | * 16 | * @param m 17 | * 方法 18 | * @return 是否可以暴露为pbrpc服务,true为可以,false为不行 19 | */ 20 | boolean isSupport(Method m); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/client/callback/Callback.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.client.callback; 2 | 3 | /** 4 | * ClassName: Callback
5 | * Function: 客户端回调接口 6 | * 7 | * @author Zhang Xu 8 | */ 9 | public interface Callback { 10 | 11 | /** 12 | * 当接受到服务端返回的数据后的处理 13 | * 14 | * @param result 15 | */ 16 | void handleResult(T result); 17 | 18 | /** 19 | * 发生异常时候的处理 20 | * 21 | * @param error 22 | */ 23 | void handleError(Throwable error); 24 | 25 | } -------------------------------------------------------------------------------- /navi-pbrpc-spring/src/main/java/com/baidu/beidou/navi/pbrpc/spring/IntegrationProxy.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.spring; 2 | 3 | /** 4 | * 配合Spring AOP中的{@link org.springframework.beans.factory.FactoryBean}来生成代理对象 5 | *

6 | * 该接口是一个通用的代理生成类,根据指定的对象类型,返回代理对象。对象的生成可以使用传统的JDK动态代理,也可以使用Javassist字节码增强技术 7 | * 8 | * @author zhangxu 9 | */ 10 | public interface IntegrationProxy { 11 | 12 | /** 13 | * 创建指定接口的实例对象 14 | * 15 | * @param clazz 类型 16 | * 17 | * @return 代理实例对象 18 | */ 19 | T createProxy(Class clazz); 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/util/Computable.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.util; 2 | 3 | import java.util.concurrent.Callable; 4 | 5 | /** 6 | * ClassName: Computable
7 | * Function: 计算类型任务的接口 8 | * 9 | * @author Xu Chen 10 | */ 11 | public interface Computable { 12 | 13 | /** 14 | * 通过关键字来计算 15 | * 16 | * @param key 17 | * 查找关键字 18 | * @param callable 19 | * # @see Callable 20 | * @return 计算结果 21 | */ 22 | V get(K key, Callable callable); 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/test/java/com/baidu/beidou/navi/pbrpc/demo/Server.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.demo; 2 | 3 | import com.baidu.beidou.navi.pbrpc.demo.service.impl.DemoServiceImpl; 4 | import com.baidu.beidou.navi.pbrpc.server.PbrpcServer; 5 | 6 | /** 7 | * ClassName: Server
8 | * Function: 测试用服务端 9 | * 10 | * @author Zhang Xu 11 | */ 12 | public class Server { 13 | 14 | /** 15 | * run 16 | * 17 | * @param port 18 | */ 19 | public void run(int port) { 20 | PbrpcServer server = new PbrpcServer(port); 21 | server.register(100, new DemoServiceImpl()); 22 | server.start(); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /navi-pbrpc-spring/src/test/java/com/baidu/beidou/navi/pbrpc/demo/Server.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.demo; 2 | 3 | import com.baidu.beidou.navi.pbrpc.demo.service.impl.DemoServiceImpl; 4 | import com.baidu.beidou.navi.pbrpc.server.PbrpcServer; 5 | 6 | /** 7 | * ClassName: Server
8 | * Function: 测试用服务端 9 | * 10 | * @author Zhang Xu 11 | */ 12 | public class Server { 13 | 14 | /** 15 | * run 16 | * 17 | * @param port 18 | */ 19 | public void run(int port) { 20 | PbrpcServer server = new PbrpcServer(port); 21 | server.register(100, new DemoServiceImpl()); 22 | server.start(); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/com/baidu/beidou/navi/pbrpc/server/NegativeServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.server; 2 | 3 | import com.baidu.beidou.navi.pbrpc.demo.proto.Demo.DemoRequest; 4 | import com.baidu.beidou.navi.pbrpc.demo.proto.Demo.DemoResponse; 5 | 6 | public class NegativeServiceImpl { 7 | 8 | public Integer m1(Object arg1, Integer arg2) { 9 | return null; 10 | } 11 | 12 | public DemoResponse m2(Object arg1) { 13 | return null; 14 | } 15 | 16 | public void m3(DemoRequest arg1) { 17 | return; 18 | } 19 | 20 | public DemoResponse m4(DemoRequest arg1, Object arg2) { 21 | return null; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/client/ha/FailStrategy.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.client.ha; 2 | 3 | /** 4 | * ClassName: FailStrategy
5 | * Function: 失败处理策略 6 | * 7 | * @author Zhang Xu 8 | */ 9 | public interface FailStrategy { 10 | 11 | /** 12 | * 失败后是否立即退出 13 | * 14 | * @param currentRetryTime 15 | * 当前已经重试的次数,从0开始 16 | * @param clientSize 17 | * 客户端IP:PORT的可用数量 18 | * @return 是否立即退出 19 | */ 20 | boolean isQuitImmediately(int currentRetryTime, int clientSize); 21 | 22 | /** 23 | * 获取最大的重试次数 24 | * 25 | * @return 26 | */ 27 | int getMaxRetryTimes(); 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/com/baidu/beidou/navi/pbrpc/server/ServiceLocatorTest.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.server; 2 | 3 | import static org.hamcrest.Matchers.nullValue; 4 | import static org.junit.Assert.assertThat; 5 | 6 | import org.junit.Test; 7 | 8 | import com.baidu.beidou.navi.pbrpc.server.core.ServiceLocator; 9 | import com.baidu.beidou.navi.pbrpc.server.core.impl.IdKeyServiceLocator; 10 | 11 | public class ServiceLocatorTest { 12 | 13 | @Test 14 | public void testNegative() { 15 | ServiceLocator sl = new IdKeyServiceLocator(); 16 | sl.regiserService(0, new NegativeServiceImpl()); 17 | assertThat(sl.getServiceDescriptor(0), nullValue()); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/util/IdGenerator.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.util; 2 | 3 | import java.util.UUID; 4 | 5 | /** 6 | * ClassName: IdGenerator
7 | * Function: id生成器 8 | * 9 | * @author Zhang Xu 10 | */ 11 | public class IdGenerator { 12 | 13 | /** 14 | * 生成一个Unique ID, 默认使用JDK自带的UUID 15 | *

16 | * 也可以使用: 17 | * 18 | *

19 |      * return UUIDGenerator.getInstance().generateTimeBasedUUID().toString();
20 |      * return Math.abs(new Random(System.currentTimeMillis()).nextInt());
21 |      * 
22 | * 23 | * @return 24 | */ 25 | public static int genUUID() { 26 | return Math.abs(UUID.randomUUID().toString().hashCode()); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/client/ha/FailFastStrategy.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.client.ha; 2 | 3 | /** 4 | * ClassName: FailFastStrategy
5 | * Function: 失败立即退出策略 6 | * 7 | * @author Zhang Xu 8 | */ 9 | public class FailFastStrategy implements FailStrategy { 10 | 11 | /** 12 | * @see com.baidu.beidou.navi.pbrpc.client.ha.FailStrategy#isQuitImmediately(int, int) 13 | */ 14 | @Override 15 | public boolean isQuitImmediately(int currentRetryTime, int clientSize) { 16 | return true; 17 | } 18 | 19 | /** 20 | * @see com.baidu.beidou.navi.pbrpc.client.ha.FailStrategy#getMaxRetryTimes() 21 | */ 22 | @Override 23 | public int getMaxRetryTimes() { 24 | return 1; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/util/PbrpcConstants.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.util; 2 | 3 | 4 | /** 5 | * ClassName: PbrpcConstants
6 | * Function: 一些默认的常量 7 | * 8 | * @author Zhang Xu 9 | */ 10 | public class PbrpcConstants { 11 | 12 | /** 13 | * 默认客户端连接超时时间,单位毫秒 14 | */ 15 | public static final int DEFAULT_CLIENT_CONN_TIMEOUT = 5000; 16 | 17 | /** 18 | * 默认客户端调用读超时时间,单位毫秒 19 | */ 20 | public static final int DEFAULT_CLIENT_READ_TIMEOUT = 60000; 21 | 22 | /** 23 | * 默认客户端超时调用检测器启动时间,单位毫秒 24 | */ 25 | public static int CLIENT_TIMEOUT_EVICTOR_DELAY_START_TIME = 5000; 26 | 27 | /** 28 | * 默认客户端超时调用检测器检测间隔,单位毫秒 29 | */ 30 | public static int CLIENT_TIMEOUT_EVICTOR_CHECK_INTERVAL = 5000; 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/server/core/ServiceLocator.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.server.core; 2 | 3 | /** 4 | * ClassName: ServiceLocator
5 | * Function: 服务定位器,用于注入服务到运行容器,同时结合netty handler路由到指定方法,另外还可以发布服务,例如到zookeeper中。 6 | * 7 | * @author Zhang Xu 8 | */ 9 | public interface ServiceLocator { 10 | 11 | /** 12 | * 根据服务标示获取服务描述 13 | * 14 | * @param key 15 | * @return 16 | */ 17 | ServiceDescriptor getServiceDescriptor(KEY key); 18 | 19 | /** 20 | * 注入服务 21 | * 22 | * @param key 23 | * @param serviceBean 24 | * @return 25 | */ 26 | boolean regiserService(KEY key, Object serviceBean); 27 | 28 | /** 29 | * 整体发布服务 30 | * 31 | * @return 32 | */ 33 | boolean publishService(); 34 | 35 | } 36 | -------------------------------------------------------------------------------- /navi-pbrpc-spring/src/main/java/com/baidu/beidou/navi/pbrpc/client/HAPbrpcServerLocator.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.client; 2 | 3 | import com.baidu.beidou.navi.pbrpc.client.ha.LoadBalanceStrategy; 4 | 5 | /** 6 | * 高可用Pbrpc远程服务的定位器,一般用于基于一个标示(例如,IP:PORT串、或者LDAP名称)来获取远程服务实际IP:PORT列表 7 | * 8 | * @author zhangxu 9 | */ 10 | public interface HAPbrpcServerLocator { 11 | 12 | /** 13 | * 标示(例如,IP:PORT串、或者LDAP名称)来获取远程服务实际IP:PORT列表,进而构造一个高可用的Pbrpc调用客户端 14 | * 15 | * @param serverSign 标示(例如,IP:PORT串、或者LDAP名称) 16 | * @param connTimeout 连接超时 17 | * @param readTimeout 读超时 18 | * @param lb 负载均衡策略 19 | * 20 | * @return 高可用Pbrpc客户端 21 | */ 22 | HAPbrpcClient factory(String serverSign, int connTimeout, int readTimeout, 23 | LoadBalanceStrategy lb); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /navi-pbrpc-spring/src/main/java/com/baidu/beidou/navi/pbrpc/annotation/PbrpcMethodId.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | /** 10 | * 一般标识在客户端的接口类上,便于在{@link com.baidu.beidou.navi.pbrpc.spring.IntegrationProxy}实现类内部做{@link com.baidu.beidou.navi 11 | * .pbrpc.transport.PbrpcMsg}中的serviceId填充 12 | * 13 | * @author zhangxu 14 | */ 15 | @Target({ElementType.METHOD}) 16 | @Retention(RetentionPolicy.RUNTIME) 17 | @Documented 18 | public @interface PbrpcMethodId { 19 | 20 | /** 21 | * Pbprc header头中的serviceId,a.k.a methodId 22 | * 23 | * @return methodId 24 | */ 25 | int value() default 0; 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/codec/Codec.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.codec; 2 | 3 | import com.baidu.beidou.navi.pbrpc.exception.CodecException; 4 | 5 | /** 6 | * ClassName: Codec
7 | * Function: 编码接口 8 | * 9 | * @author Zhang Xu 10 | */ 11 | public interface Codec { 12 | 13 | /** 14 | * 反序列化 15 | * 16 | * @param clazz 17 | * 反序列化后的类定义 18 | * @param bytes 19 | * 字节码 20 | * @return 反序列化后的对象 21 | * @throws CodecException 22 | */ 23 | Object decode(Class clazz, byte[] bytes) throws CodecException; 24 | 25 | /** 26 | * 序列化 27 | * 28 | * @param clazz 29 | * 待序列化的类定义 30 | * @param object 31 | * 待序列化的对象 32 | * @return 字节码 33 | * @throws CodecException 34 | */ 35 | byte[] encode(Class clazz, Object object) throws CodecException; 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/protocol/Header.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.protocol; 2 | 3 | /** 4 | * ClassName: Header
5 | * Function: 通用头,用于RPC通讯消息属于header+body方式的交互 6 | * 7 | * @author Zhang Xu 8 | */ 9 | public interface Header { 10 | 11 | /** 12 | * 头固定字节长度 13 | * 14 | * @return 15 | */ 16 | int getFixedHeaderLen(); 17 | 18 | /** 19 | * 消息body体长度 20 | * 21 | * @param bodyLen 22 | */ 23 | void setBodyLen(long bodyLen); 24 | 25 | /** 26 | * 获取消息body体长度 27 | * 28 | * @return 29 | */ 30 | long getBodyLen(); 31 | 32 | /** 33 | * 从字节码构造头 34 | * 35 | * @param input 36 | */ 37 | void wrap(byte[] input); 38 | 39 | /** 40 | * 头序列化为字节码 41 | * 42 | * @return 43 | * @throws RuntimeException 44 | */ 45 | byte[] toBytes() throws RuntimeException; 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/client/ha/TransportCallback.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.client.ha; 2 | 3 | import java.util.List; 4 | 5 | import com.baidu.beidou.navi.pbrpc.client.PbrpcClient; 6 | 7 | /** 8 | * 在{@link LoadBalanceStrategy}中使用,用作调用成功、失败的回调 9 | * 10 | * @author zhangxu 11 | */ 12 | public interface TransportCallback { 13 | 14 | /** 15 | * 客户端调用成功后的回调 16 | * 17 | * @param currClient 当前调用成功的客户端引用 18 | * @param clientList 当前整个{@link com.baidu.beidou.navi.pbrpc.client.HAPbrpcClient}托管的客户端列表 19 | */ 20 | void onSuccess(PbrpcClient currClient, List clientList); 21 | 22 | /** 23 | * 客户端调用失败后的回调 24 | * 25 | * @param currClient 当前调用成功的客户端引用 26 | * @param clientList 当前整个{@link com.baidu.beidou.navi.pbrpc.client.HAPbrpcClient}托管的客户端列表 27 | * @param e 调用错误异常 28 | */ 29 | void onFail(PbrpcClient currClient, List clientList, Exception e); 30 | 31 | } 32 | -------------------------------------------------------------------------------- /navi-pbrpc-spring/src/main/java/com/baidu/beidou/navi/pbrpc/client/IpPortShortLiveBlockingIOPbrpcServerLocator.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.client; 2 | 3 | import com.baidu.beidou.navi.pbrpc.client.ha.LoadBalanceStrategy; 4 | 5 | /** 6 | * 基于IP:PORT地址串的服务定位器 7 | * 8 | * @author zhangxu 9 | */ 10 | public class IpPortShortLiveBlockingIOPbrpcServerLocator implements HAPbrpcServerLocator { 11 | 12 | /** 13 | * 标示(例如,IP:PORT串、或者LDAP名称)来获取远程服务实际IP:PORT列表,进而构造一个高可用的Pbrpc调用客户端 14 | * 15 | * @param serverSign 标示(例如,IP:PORT串、或者LDAP名称) 16 | * @param connTimeout 连接超时 17 | * @param readTimeout 读超时 18 | * @param lb 负载均衡策略 19 | * 20 | * @return 高可用Pbrpc客户端 21 | */ 22 | @Override 23 | public HAPbrpcClient factory(String serverSign, int connTimeout, int readTimeout, 24 | LoadBalanceStrategy lb) { 25 | return HAPbrpcClientFactory.buildShortLiveBlockingIOConnection(new PbrpcClientConfiguration(), serverSign, 26 | connTimeout, readTimeout, lb); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/util/UnsignedSwitch.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.util; 2 | 3 | /** 4 | * ClassName: UnsignedSwitch
5 | * Function: 有符号-无符号转换工具 6 | * 7 | * @author Zhang Xu 8 | */ 9 | public class UnsignedSwitch { 10 | 11 | /** 12 | * 无符号int到long 13 | * 14 | * @param x 15 | * @return 16 | */ 17 | public static long uintToLong(int x) { 18 | return x & 0xffffffffL; 19 | } 20 | 21 | /** 22 | * 无符号short到int 23 | * 24 | * @param x 25 | * @return 26 | */ 27 | public static int uShortToInt(short x) { 28 | return (int) (x & 0xffff); 29 | } 30 | 31 | /** 32 | * long到无符号int 33 | * 34 | * @param x 35 | * @return 36 | */ 37 | public static int longToUint(long x) { 38 | return (int) (x & 0xffffffff); 39 | } 40 | 41 | /** 42 | * int到无符号short 43 | * 44 | * @param x 45 | * @return 46 | */ 47 | public static short intToUshort(int x) { 48 | return (short) (x & 0xffff); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/client/ha/DefaultTransportCallback.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.client.ha; 2 | 3 | import java.util.List; 4 | 5 | import com.baidu.beidou.navi.pbrpc.client.PbrpcClient; 6 | 7 | /** 8 | * 在{@link LoadBalanceStrategy}中使用,用作调用成功、失败的默认回调 9 | * 10 | * @author zhangxu 11 | */ 12 | public class DefaultTransportCallback implements TransportCallback { 13 | 14 | /** 15 | * 客户端调用成功后的回调,默认什么都不做 16 | * 17 | * @param currClient 当前调用成功的客户端引用 18 | * @param clientList 当前整个{@link com.baidu.beidou.navi.pbrpc.client.HAPbrpcClient}托管的客户端列表 19 | */ 20 | @Override 21 | public void onSuccess(PbrpcClient currClient, List clientList) { 22 | 23 | } 24 | 25 | /** 26 | * 客户端调用失败后的回调,默认什么都不做 27 | * 28 | * @param currClient 当前调用成功的客户端引用 29 | * @param clientList 当前整个{@link com.baidu.beidou.navi.pbrpc.client.HAPbrpcClient}托管的客户端列表 30 | * @param e 调用错误异常 31 | */ 32 | @Override 33 | public void onFail(PbrpcClient currClient, List clientList, Exception e) { 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/com/baidu/beidou/navi/pbrpc/demo/service/DemoService.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.demo.service; 2 | 3 | import com.baidu.beidou.navi.pbrpc.demo.proto.Demo.DemoBatchRequest; 4 | import com.baidu.beidou.navi.pbrpc.demo.proto.Demo.DemoBatchResponse; 5 | import com.baidu.beidou.navi.pbrpc.demo.proto.Demo.DemoRequest; 6 | import com.baidu.beidou.navi.pbrpc.demo.proto.Demo.DemoResponse; 7 | 8 | /** 9 | * ClassName: DemoService
10 | * Function: demo服务端接口 11 | * 12 | * @author Zhang Xu 13 | */ 14 | public interface DemoService { 15 | 16 | /** 17 | * 干点什么 18 | * 19 | * @param req 20 | * 请求 21 | * @return 响应 22 | */ 23 | DemoResponse doSmth(DemoRequest req); 24 | 25 | /** 26 | * 用于测试批量干点什么 27 | * 28 | * @param req 29 | * 请求 30 | * @return 响应 31 | */ 32 | DemoBatchResponse doSmthBatch(DemoBatchRequest req); 33 | 34 | /** 35 | * 干点什么,内部sleep一定时间,模拟超时 36 | * 37 | * @param req 38 | * 请求 39 | * @return 响应 40 | */ 41 | DemoResponse doSmthTimeout(DemoRequest req); 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/client/ha/IpPort.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.client.ha; 2 | 3 | /** 4 | * ClassName: IpPort
5 | * Function: IP端口类 6 | * 7 | * @author Zhang Xu 8 | */ 9 | public class IpPort { 10 | 11 | /** 12 | * ip 13 | */ 14 | private String ip; 15 | 16 | /** 17 | * 端口 18 | */ 19 | private int port; 20 | 21 | /** 22 | * Creates a new instance of IpPort. 23 | * 24 | * @param ip 25 | * @param port 26 | */ 27 | public IpPort(String ip, int port) { 28 | super(); 29 | this.ip = ip; 30 | this.port = port; 31 | } 32 | 33 | /** 34 | * @see java.lang.Object#toString() 35 | */ 36 | @Override 37 | public String toString() { 38 | return ip + ":" + port; 39 | } 40 | 41 | public String getIp() { 42 | return ip; 43 | } 44 | 45 | public void setIp(String ip) { 46 | this.ip = ip; 47 | } 48 | 49 | public int getPort() { 50 | return port; 51 | } 52 | 53 | public void setPort(int port) { 54 | this.port = port; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/client/HeaderResolver.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.client; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | 6 | import com.baidu.beidou.navi.pbrpc.protocol.Header; 7 | import com.baidu.beidou.navi.pbrpc.transport.PbrpcMsg; 8 | 9 | /** 10 | * ClassName: HeaderResolver
11 | * Function: 头解析构造器,仅用户blocking io半双工场景 12 | * 13 | * @author Zhang Xu 14 | */ 15 | public interface HeaderResolver { 16 | 17 | /** 18 | * 从响应头中解析头 19 | * 20 | * @param in 21 | * @return 22 | * @throws IOException 23 | */ 24 | Header resolveResHeader(InputStream in) throws IOException; 25 | 26 | /** 27 | * 根据头信息以及响应流读取响应体 28 | * 29 | * @param header 30 | * @param in 31 | * @return 32 | * @throws IOException 33 | */ 34 | byte[] resolveResBodyByResHeader(Header header, InputStream in) throws IOException; 35 | 36 | /** 37 | * 构造发送请求的头和体 38 | * 39 | * @param pbrpcMsg 40 | * @return 41 | * @throws IOException 42 | */ 43 | byte[] packReqHeaderAndBody(PbrpcMsg pbrpcMsg) throws IOException; 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/exception/CodecException.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.exception; 2 | 3 | /** 4 | * ClassName: CodecException
5 | * Function: 编解码异常 6 | * 7 | * @author Zhang Xu 8 | */ 9 | public class CodecException extends RuntimeException { 10 | 11 | /** 12 | * serialVersionUID 13 | */ 14 | private static final long serialVersionUID = 5196421433506179782L; 15 | 16 | /** 17 | * Creates a new instance of CodecException. 18 | */ 19 | public CodecException() { 20 | super(); 21 | } 22 | 23 | /** 24 | * Creates a new instance of CodecException. 25 | * 26 | * @param arg0 27 | * @param arg1 28 | */ 29 | public CodecException(String arg0, Throwable arg1) { 30 | super(arg0, arg1); 31 | } 32 | 33 | /** 34 | * Creates a new instance of CodecException. 35 | * 36 | * @param arg0 37 | */ 38 | public CodecException(String arg0) { 39 | super(arg0); 40 | } 41 | 42 | /** 43 | * Creates a new instance of CodecException. 44 | * 45 | * @param arg0 46 | */ 47 | public CodecException(Throwable arg0) { 48 | super(arg0); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/exception/TimeoutException.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.exception; 2 | 3 | /** 4 | * ClassName: TimeoutException
5 | * Function: 客户端调用超时异常 6 | * 7 | * @author Zhang Xu 8 | */ 9 | public class TimeoutException extends RuntimeException { 10 | 11 | /** 12 | * serialVersionUID 13 | */ 14 | private static final long serialVersionUID = 5196421433506179782L; 15 | 16 | /** 17 | * Creates a new instance of TimeoutException. 18 | */ 19 | public TimeoutException() { 20 | super(); 21 | } 22 | 23 | /** 24 | * Creates a new instance of TimeoutException. 25 | * 26 | * @param arg0 27 | * @param arg1 28 | */ 29 | public TimeoutException(String arg0, Throwable arg1) { 30 | super(arg0, arg1); 31 | } 32 | 33 | /** 34 | * Creates a new instance of TimeoutException. 35 | * 36 | * @param arg0 37 | */ 38 | public TimeoutException(String arg0) { 39 | super(arg0); 40 | } 41 | 42 | /** 43 | * Creates a new instance of TimeoutException. 44 | * 45 | * @param arg0 46 | */ 47 | public TimeoutException(Throwable arg0) { 48 | super(arg0); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/exception/client/PbrpcException.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.exception.client; 2 | 3 | /** 4 | * ClassName: PbrpcException
5 | * Function: 客户端通用的关于Pbprc的异常 6 | * 7 | * @author Zhang Xu 8 | */ 9 | public class PbrpcException extends RuntimeException { 10 | 11 | /** 12 | * serialVersionUID 13 | */ 14 | private static final long serialVersionUID = 5196421433506179782L; 15 | 16 | /** 17 | * Creates a new instance of PbrpcException. 18 | */ 19 | public PbrpcException() { 20 | super(); 21 | } 22 | 23 | /** 24 | * Creates a new instance of PbrpcException. 25 | * 26 | * @param arg0 27 | * @param arg1 28 | */ 29 | public PbrpcException(String arg0, Throwable arg1) { 30 | super(arg0, arg1); 31 | } 32 | 33 | /** 34 | * Creates a new instance of PbrpcException. 35 | * 36 | * @param arg0 37 | */ 38 | public PbrpcException(String arg0) { 39 | super(arg0); 40 | } 41 | 42 | /** 43 | * Creates a new instance of PbrpcException. 44 | * 45 | * @param arg0 46 | */ 47 | public PbrpcException(Throwable arg0) { 48 | super(arg0); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/exception/client/HAPbrpcException.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.exception.client; 2 | 3 | /** 4 | * ClassName: HAPbrpcException
5 | * Function: 高可用的客户端异常 6 | * 7 | * @author Zhang Xu 8 | */ 9 | public class HAPbrpcException extends RuntimeException { 10 | 11 | /** 12 | * serialVersionUID 13 | */ 14 | private static final long serialVersionUID = 5196421433506179782L; 15 | 16 | /** 17 | * Creates a new instance of HAPbrpcException. 18 | */ 19 | public HAPbrpcException() { 20 | super(); 21 | } 22 | 23 | /** 24 | * Creates a new instance of HAPbrpcException. 25 | * 26 | * @param arg0 27 | * @param arg1 28 | */ 29 | public HAPbrpcException(String arg0, Throwable arg1) { 30 | super(arg0, arg1); 31 | } 32 | 33 | /** 34 | * Creates a new instance of HAPbrpcException. 35 | * 36 | * @param arg0 37 | */ 38 | public HAPbrpcException(String arg0) { 39 | super(arg0); 40 | } 41 | 42 | /** 43 | * Creates a new instance of HAPbrpcException. 44 | * 45 | * @param arg0 46 | */ 47 | public HAPbrpcException(Throwable arg0) { 48 | super(arg0); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /navi-pbrpc-spring/src/test/java/com/baidu/beidou/navi/pbrpc/demo/service/DemoService.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.demo.service; 2 | 3 | import com.baidu.beidou.navi.pbrpc.annotation.PbrpcMethodId; 4 | import com.baidu.beidou.navi.pbrpc.demo.proto.Demo.DemoBatchRequest; 5 | import com.baidu.beidou.navi.pbrpc.demo.proto.Demo.DemoBatchResponse; 6 | import com.baidu.beidou.navi.pbrpc.demo.proto.Demo.DemoRequest; 7 | import com.baidu.beidou.navi.pbrpc.demo.proto.Demo.DemoResponse; 8 | 9 | /** 10 | * ClassName: DemoService
11 | * Function: demo服务端接口 12 | * 13 | * @author Zhang Xu 14 | */ 15 | public interface DemoService { 16 | 17 | /** 18 | * 干点什么 19 | * 20 | * @param req 21 | * 请求 22 | * @return 响应 23 | */ 24 | @PbrpcMethodId(100) 25 | DemoResponse doSmth(DemoRequest req); 26 | 27 | /** 28 | * 用于测试批量干点什么 29 | * 30 | * @param req 31 | * 请求 32 | * @return 响应 33 | */ 34 | @PbrpcMethodId(102) 35 | DemoBatchResponse doSmthBatch(DemoBatchRequest req); 36 | 37 | /** 38 | * 干点什么,内部sleep一定时间,模拟超时 39 | * 40 | * @param req 41 | * 请求 42 | * @return 响应 43 | */ 44 | @PbrpcMethodId(101) 45 | DemoResponse doSmthTimeout(DemoRequest req); 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/client/ha/FailOverStrategy.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.client.ha; 2 | 3 | /** 4 | * ClassName: FailOverStrategy
5 | * Function: 失败重试策略 6 | * 7 | * @author Zhang Xu 8 | */ 9 | public class FailOverStrategy implements FailStrategy { 10 | 11 | /** 12 | * 最大重试次数,默认为2 13 | */ 14 | private int maxRetryTimes = 2; 15 | 16 | public FailOverStrategy() { 17 | } 18 | 19 | /** 20 | * Creates a new instance of FailOverStrategy. 21 | * 22 | * @param maxRetryTimes 23 | */ 24 | public FailOverStrategy(int maxRetryTimes) { 25 | this.maxRetryTimes = maxRetryTimes; 26 | } 27 | 28 | /** 29 | * @see com.baidu.beidou.navi.pbrpc.client.ha.FailStrategy#isQuitImmediately(int, int) 30 | */ 31 | @Override 32 | public boolean isQuitImmediately(int currentRetryTime, int clientSize) { 33 | if (currentRetryTime + 1 == getMaxRetryTimes() || currentRetryTime + 1 == clientSize) { 34 | return true; 35 | } 36 | return false; 37 | } 38 | 39 | /** 40 | * @see com.baidu.beidou.navi.pbrpc.client.ha.FailStrategy#getMaxRetryTimes() 41 | */ 42 | @Override 43 | public int getMaxRetryTimes() { 44 | return maxRetryTimes; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/exception/CommunicationException.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.exception; 2 | 3 | /** 4 | * ClassName: CommunicationException
5 | * Function: 服务端和客户端通信交互中发生的异常 6 | * 7 | * @author Zhang Xu 8 | */ 9 | public class CommunicationException extends RuntimeException { 10 | 11 | /** 12 | * serialVersionUID 13 | */ 14 | private static final long serialVersionUID = 5196421433506179782L; 15 | 16 | /** 17 | * Creates a new instance of CommunicationException. 18 | */ 19 | public CommunicationException() { 20 | super(); 21 | } 22 | 23 | /** 24 | * Creates a new instance of CommunicationException. 25 | * 26 | * @param arg0 27 | * @param arg1 28 | */ 29 | public CommunicationException(String arg0, Throwable arg1) { 30 | super(arg0, arg1); 31 | } 32 | 33 | /** 34 | * Creates a new instance of CommunicationException. 35 | * 36 | * @param arg0 37 | */ 38 | public CommunicationException(String arg0) { 39 | super(arg0); 40 | } 41 | 42 | /** 43 | * Creates a new instance of CommunicationException. 44 | * 45 | * @param arg0 46 | */ 47 | public CommunicationException(Throwable arg0) { 48 | super(arg0); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/exception/ServiceNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.exception; 2 | 3 | /** 4 | * ClassName: ServiceNotFoundException
5 | * Function: 服务端暴露未找到服务异常 6 | * 7 | * @author Zhang Xu 8 | */ 9 | public class ServiceNotFoundException extends RuntimeException { 10 | 11 | /** 12 | * serialVersionUID 13 | */ 14 | private static final long serialVersionUID = 5196421433506179782L; 15 | 16 | /** 17 | * Creates a new instance of ServiceNotFoundException. 18 | */ 19 | public ServiceNotFoundException() { 20 | super(); 21 | } 22 | 23 | /** 24 | * Creates a new instance of ServiceNotFoundException. 25 | * 26 | * @param arg0 27 | * @param arg1 28 | */ 29 | public ServiceNotFoundException(String arg0, Throwable arg1) { 30 | super(arg0, arg1); 31 | } 32 | 33 | /** 34 | * Creates a new instance of ServiceNotFoundException. 35 | * 36 | * @param arg0 37 | */ 38 | public ServiceNotFoundException(String arg0) { 39 | super(arg0); 40 | } 41 | 42 | /** 43 | * Creates a new instance of ServiceNotFoundException. 44 | * 45 | * @param arg0 46 | */ 47 | public ServiceNotFoundException(Throwable arg0) { 48 | super(arg0); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/exception/client/PbrpcConnectionException.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.exception.client; 2 | 3 | /** 4 | * ClassName: PbrpcConnectionException
5 | * Function: 客户端连接服务端是否发生的连接异常 6 | * 7 | * @author Zhang Xu 8 | */ 9 | public class PbrpcConnectionException extends RuntimeException { 10 | 11 | /** 12 | * serialVersionUID 13 | */ 14 | private static final long serialVersionUID = 5196421433506179782L; 15 | 16 | /** 17 | * Creates a new instance of PbrpcConnectionException. 18 | */ 19 | public PbrpcConnectionException() { 20 | super(); 21 | } 22 | 23 | /** 24 | * Creates a new instance of PbrpcConnectionException. 25 | * 26 | * @param arg0 27 | * @param arg1 28 | */ 29 | public PbrpcConnectionException(String arg0, Throwable arg1) { 30 | super(arg0, arg1); 31 | } 32 | 33 | /** 34 | * Creates a new instance of PbrpcConnectionException. 35 | * 36 | * @param arg0 37 | */ 38 | public PbrpcConnectionException(String arg0) { 39 | super(arg0); 40 | } 41 | 42 | /** 43 | * Creates a new instance of PbrpcConnectionException. 44 | * 45 | * @param arg0 46 | */ 47 | public PbrpcConnectionException(Throwable arg0) { 48 | super(arg0); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/exception/ServerExecutionException.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.exception; 2 | 3 | /** 4 | * ClassName: ServerExecutionException
5 | * Function: 服务端执行异常,当通过反射调用本地方法时抛出异常或者发生其他未知异常抛出 6 | * 7 | * @author Zhang Xu 8 | */ 9 | public class ServerExecutionException extends RuntimeException { 10 | 11 | /** 12 | * serialVersionUID 13 | */ 14 | private static final long serialVersionUID = 5196421433506179782L; 15 | 16 | /** 17 | * Creates a new instance of ServerExecutionException. 18 | */ 19 | public ServerExecutionException() { 20 | super(); 21 | } 22 | 23 | /** 24 | * Creates a new instance of ServerExecutionException. 25 | * 26 | * @param arg0 27 | * @param arg1 28 | */ 29 | public ServerExecutionException(String arg0, Throwable arg1) { 30 | super(arg0, arg1); 31 | } 32 | 33 | /** 34 | * Creates a new instance of ServerExecutionException. 35 | * 36 | * @param arg0 37 | */ 38 | public ServerExecutionException(String arg0) { 39 | super(arg0); 40 | } 41 | 42 | /** 43 | * Creates a new instance of ServerExecutionException. 44 | * 45 | * @param arg0 46 | */ 47 | public ServerExecutionException(Throwable arg0) { 48 | super(arg0); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/exception/client/OperationNotSupportException.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.exception.client; 2 | 3 | /** 4 | * ClassName: OperationNotSupportException
5 | * Function: 不允许操作异常 6 | * 7 | * @author Zhang Xu 8 | */ 9 | public class OperationNotSupportException extends RuntimeException { 10 | 11 | /** 12 | * serialVersionUID 13 | */ 14 | private static final long serialVersionUID = 5196421433506179782L; 15 | 16 | /** 17 | * Creates a new instance of OperationNotSupportException. 18 | */ 19 | public OperationNotSupportException() { 20 | super(); 21 | } 22 | 23 | /** 24 | * Creates a new instance of OperationNotSupportException. 25 | * 26 | * @param arg0 27 | * @param arg1 28 | */ 29 | public OperationNotSupportException(String arg0, Throwable arg1) { 30 | super(arg0, arg1); 31 | } 32 | 33 | /** 34 | * Creates a new instance of OperationNotSupportException. 35 | * 36 | * @param arg0 37 | */ 38 | public OperationNotSupportException(String arg0) { 39 | super(arg0); 40 | } 41 | 42 | /** 43 | * Creates a new instance of OperationNotSupportException. 44 | * 45 | * @param arg0 46 | */ 47 | public OperationNotSupportException(Throwable arg0) { 48 | super(arg0); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/client/ha/LoadBalanceStrategy.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.client.ha; 2 | 3 | import java.util.List; 4 | 5 | import com.baidu.beidou.navi.pbrpc.client.PbrpcClient; 6 | import com.baidu.beidou.navi.pbrpc.client.callback.CallFuture; 7 | import com.baidu.beidou.navi.pbrpc.transport.PbrpcMsg; 8 | import com.google.protobuf.GeneratedMessage; 9 | 10 | /** 11 | * ClassName: LoadBalanceStrategy
12 | * Function: 负载均衡器 13 | * 14 | * @author Zhang Xu 15 | */ 16 | public interface LoadBalanceStrategy { 17 | 18 | /** 19 | * 根据客户端的连接采用负载均衡策略调用,异步调用 20 | * 21 | * @param clientList 22 | * 客户端列表 23 | * @param responseClazz 24 | * 返回对象的类型 25 | * @param pbrpcMsg 26 | * pbrpc消息 27 | * @return 调用future 28 | */ 29 | CallFuture doAsyncTransport(List clientList, 30 | Class responseClazz, PbrpcMsg pbrpcMsg); 31 | 32 | /** 33 | * 根据客户端的连接采用负载均衡策略调用,同步调用 34 | * 35 | * @param clientList 36 | * 客户端列表 37 | * @param responseClazz 38 | * 返回对象的类型 39 | * @param pbrpcMsg 40 | * pbrpc消息 41 | * @return 调用结果 42 | */ 43 | T doSyncTransport(List clientList, 44 | Class responseClazz, PbrpcMsg pbrpcMsg); 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/test/java/com/baidu/beidou/navi/pbrpc/demo/Main.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.demo; 2 | 3 | /** 4 | * ClassName: Main
5 | * Function: 压测用的Main入口 6 | * 7 | * @author Zhang Xu 8 | */ 9 | public class Main { 10 | 11 | /** 12 | * main
13 | * 启用服务命令: 14 | * 15 | *
16 |      * java Main 8088
17 |      * 
18 | * 19 | * 没有第二个参数表示启动服务端。
20 | * 启动测试客户端命令: 21 | * 22 | *
23 |      * java Main 8088 8 10000 20 500
24 |      * 
25 | * 26 | * 标示调用本地8088端口,8个病房,10000个请求总计,返回请求的数据大小等于20*500=10k 27 | * 28 | * @param args 29 | * @throws Exception 30 | */ 31 | public static void main(String[] args) throws Exception { 32 | if (args.length < 1) { 33 | System.out.println("args invalid"); 34 | System.exit(-1); 35 | } 36 | int port = Integer.parseInt(args[0]); 37 | if (args.length == 1) { 38 | Server server = new Server(); 39 | server.run(port); 40 | } else { 41 | int multiSize = Integer.parseInt(args[1]); 42 | int invokeNum = Integer.parseInt(args[2]); 43 | int size = Integer.parseInt(args[3]); 44 | int textLength = Integer.parseInt(args[4]); 45 | Client client = new Client(); 46 | client.run(port, multiSize, invokeNum, size, textLength); 47 | } 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /navi-pbrpc-spring/src/test/java/com/baidu/beidou/navi/pbrpc/demo/Main.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.demo; 2 | 3 | /** 4 | * ClassName: Main
5 | * Function: 压测用的Main入口 6 | * 7 | * @author Zhang Xu 8 | */ 9 | public class Main { 10 | 11 | /** 12 | * main
13 | * 启用服务命令: 14 | * 15 | *
16 |      * java Main 8088
17 |      * 
18 | * 19 | * 没有第二个参数表示启动服务端。
20 | * 启动测试客户端命令: 21 | * 22 | *
23 |      * java Main 8088 8 10000 20 500
24 |      * 
25 | * 26 | * 标示调用本地8088端口,8个病房,10000个请求总计,返回请求的数据大小等于20*500=10k 27 | * 28 | * @param args 29 | * @throws Exception 30 | */ 31 | public static void main(String[] args) throws Exception { 32 | if (args.length < 1) { 33 | System.out.println("args invalid"); 34 | System.exit(-1); 35 | } 36 | int port = Integer.parseInt(args[0]); 37 | if (args.length == 1) { 38 | Server server = new Server(); 39 | server.run(port); 40 | } else { 41 | int multiSize = Integer.parseInt(args[1]); 42 | int invokeNum = Integer.parseInt(args[2]); 43 | int size = Integer.parseInt(args[3]); 44 | int textLength = Integer.parseInt(args[4]); 45 | Client client = new Client(); 46 | client.run(port, multiSize, invokeNum, size, textLength); 47 | } 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /navi-pbrpc-spring/src/main/java/com/baidu/beidou/navi/pbrpc/client/IpPortPooledBlockingIOPbrpcServerLocator.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.client; 2 | 3 | import com.baidu.beidou.navi.pbrpc.client.ha.LoadBalanceStrategy; 4 | 5 | /** 6 | * 基于IP:PORT地址串的服务定位器,使用BlockingIO短连接 7 | * 8 | * @author zhangxu 9 | */ 10 | public class IpPortPooledBlockingIOPbrpcServerLocator implements HAPbrpcServerLocator { 11 | 12 | /** 13 | * 连接池配置,为空启用默认配置 14 | */ 15 | private PooledConfiguration pooledConfiguration; 16 | 17 | /** 18 | * 标示(例如,IP:PORT串、或者LDAP名称)来获取远程服务实际IP:PORT列表,进而构造一个高可用的Pbrpc调用客户端 19 | * 20 | * @param serverSign 标示(例如,IP:PORT串、或者LDAP名称) 21 | * @param connTimeout 连接超时 22 | * @param readTimeout 读超时 23 | * @param lb 负载均衡策略 24 | * 25 | * @return 高可用Pbrpc客户端 26 | */ 27 | @Override 28 | public HAPbrpcClient factory(String serverSign, int connTimeout, int readTimeout, 29 | LoadBalanceStrategy lb) { 30 | return HAPbrpcClientFactory.buildPooledBlockingIOConnection( 31 | pooledConfiguration == null ? new PooledConfiguration() : pooledConfiguration, 32 | new PbrpcClientConfiguration(), serverSign, 33 | connTimeout, readTimeout, lb); 34 | } 35 | 36 | public void setPooledConfiguration(PooledConfiguration pooledConfiguration) { 37 | this.pooledConfiguration = pooledConfiguration; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/client/PbrpcClient.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.client; 2 | 3 | import io.netty.channel.ChannelFuture; 4 | 5 | import com.baidu.beidou.navi.pbrpc.client.callback.CallFuture; 6 | import com.baidu.beidou.navi.pbrpc.transport.PbrpcMsg; 7 | import com.google.protobuf.GeneratedMessage; 8 | 9 | /** 10 | * ClassName: PbrpcClient
11 | * Function: Pbrpc客户端通用调用接口 12 | * 13 | * @author Zhang Xu 14 | */ 15 | public interface PbrpcClient { 16 | 17 | /** 18 | * 连接远程服务器 19 | * 20 | * @return ChannelFuture netty nio方式连接后的future回调 21 | */ 22 | ChannelFuture connect(); 23 | 24 | /** 25 | * 关闭客户端的远程连接 26 | */ 27 | void shutdown(); 28 | 29 | /** 30 | * 异步调用 31 | * 32 | * @param responseClazz 33 | * 调用待返回的对象类型,T为对象的Class类型 34 | * @param pbrpcMsg 35 | * Pbrpc调用的消息对象 36 | * @return future回调,带有泛型T标示待返回对象类型 37 | */ 38 | CallFuture asyncTransport(Class responseClazz, 39 | PbrpcMsg pbrpcMsg); 40 | 41 | /** 42 | * 同步调用 43 | * 44 | * @param responseClazz 45 | * 调用待返回的对象类型,T为对象的Class类型 46 | * @param pbrpcMsg 47 | * Pbrpc调用的消息对象 48 | * @return 调用返回的protobuf对象 49 | */ 50 | T syncTransport(Class responseClazz, PbrpcMsg pbrpcMsg); 51 | 52 | /** 53 | * 返回描述信息 54 | * 55 | * @return 客户端信息 56 | */ 57 | String getInfo(); 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/client/BlockingIOPbrpcClientSocketPool.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.client; 2 | 3 | import org.apache.commons.pool.impl.GenericObjectPool.Config; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import com.baidu.beidou.navi.pbrpc.codec.Codec; 8 | import com.baidu.beidou.navi.pbrpc.util.Pool; 9 | 10 | /** 11 | * ClassName: BlockingIOPbrpcClientSocketPool
12 | * Function: 客户端连接池,也叫做socket池,转为blocking io使用 13 | * 14 | * @author Zhang Xu 15 | */ 16 | public class BlockingIOPbrpcClientSocketPool extends Pool { 17 | 18 | private static final Logger LOG = LoggerFactory 19 | .getLogger(BlockingIOPbrpcClientSocketPool.class); 20 | 21 | /** 22 | * Creates a new instance of BlockingIOPbrpcClientSocketPool. 23 | * 24 | * @param poolConfig 25 | * @param clientConfig 26 | * @param host 27 | * @param port 28 | * @param connTimeout 29 | * @param readTimeout 30 | * @param codec 31 | * @param headerResolver 32 | */ 33 | public BlockingIOPbrpcClientSocketPool(final Config poolConfig, 34 | final PbrpcClientConfiguration clientConfig, final String host, int port, 35 | int connTimeout, int readTimeout, Codec codec, HeaderResolver headerResolver) { 36 | super(poolConfig, new BlockingIOPbrpcClientSocketFactory(clientConfig, host, port, 37 | connTimeout, readTimeout, codec, headerResolver)); 38 | LOG.info("Init connection pool done but connections will not be established until you start using the pool"); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/util/ReflectionUtil.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.util; 2 | 3 | import java.lang.reflect.Method; 4 | import java.lang.reflect.Modifier; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * ClassName: ReflectionUtil
10 | * Function: 反射工具类 11 | * 12 | * @author Zhang Xu 13 | */ 14 | public class ReflectionUtil { 15 | 16 | /** 17 | * 获取某个类的所有实例方法 18 | * 19 | * @param clazz 20 | * @return 21 | */ 22 | public static Method[] getAllInstanceMethods(final Class clazz) { 23 | if (clazz == null) { 24 | return null; 25 | } 26 | 27 | List methods = new ArrayList(); 28 | for (Class itr = clazz; hasSuperClass(itr);) { 29 | for (Method method : itr.getDeclaredMethods()) { 30 | if (!Modifier.isStatic(method.getModifiers())) { 31 | methods.add(method); 32 | } 33 | } 34 | itr = itr.getSuperclass(); 35 | } 36 | 37 | return methods.toArray(new Method[methods.size()]); 38 | 39 | } 40 | 41 | /** 42 | * 判断某个类是否含有父类或者接口 43 | * 44 | * @param clazz 45 | * @return 46 | */ 47 | public static boolean hasSuperClass(Class clazz) { 48 | return (clazz != null) && !clazz.equals(Object.class); 49 | } 50 | 51 | /** 52 | * 判断某个类是否是void类型 53 | * 54 | * @param cls 55 | * @return 56 | */ 57 | public static boolean isVoid(Class cls) { 58 | if (cls == void.class) { 59 | return true; 60 | } 61 | return false; 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /navi-pbrpc-spring/src/main/java/com/baidu/beidou/navi/pbrpc/spring/PbrpcProxyFactoryBean.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.spring; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.beans.factory.FactoryBean; 6 | import org.springframework.beans.factory.InitializingBean; 7 | 8 | /** 9 | * 和Spring集成起来使用的动态代理工厂bean,用于生成Pbrpc接口的代理实例对象 10 | * 11 | * @author zhangxu 12 | */ 13 | public class PbrpcProxyFactoryBean implements FactoryBean, InitializingBean { 14 | 15 | private static final Logger LOG = LoggerFactory.getLogger(PbrpcProxyFactoryBean.class); 16 | 17 | /** 18 | * 代理实例对象生成器 19 | */ 20 | private IntegrationProxy integrationProxy; 21 | 22 | /** 23 | * 调用接口 24 | */ 25 | private Class serviceInterface; 26 | 27 | @Override 28 | public Object getObject() throws Exception { 29 | return integrationProxy.createProxy(serviceInterface); 30 | } 31 | 32 | @Override 33 | public Class getObjectType() { 34 | return serviceInterface; 35 | } 36 | 37 | @Override 38 | public boolean isSingleton() { 39 | return true; 40 | } 41 | 42 | @Override 43 | public void afterPropertiesSet() throws Exception { 44 | LOG.info("Create integration rpc proxy bean " + getClass().getSimpleName() + " for interface " 45 | + serviceInterface); 46 | } 47 | 48 | public void setIntegrationProxy(IntegrationProxy integrationProxy) { 49 | this.integrationProxy = integrationProxy; 50 | } 51 | 52 | public void setServiceInterface(Class serviceInterface) { 53 | this.serviceInterface = serviceInterface; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/test/java/com/baidu/beidou/navi/pbrpc/codec/impl/ProtobufCodecTest.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.codec.impl; 2 | 3 | import static org.hamcrest.Matchers.is; 4 | import static org.hamcrest.Matchers.notNullValue; 5 | import static org.junit.Assert.assertThat; 6 | 7 | import org.junit.Test; 8 | 9 | import com.baidu.beidou.navi.pbrpc.codec.Codec; 10 | import com.baidu.beidou.navi.pbrpc.demo.proto.Demo.DemoResponse; 11 | import com.baidu.beidou.navi.pbrpc.demo.proto.Demo.DemoResponse.GenderType; 12 | 13 | public class ProtobufCodecTest { 14 | 15 | private Codec codec = new ProtobufCodec(); 16 | 17 | @Test 18 | public void testEncodeDecode() throws Exception { 19 | long start = System.currentTimeMillis(); 20 | // codec = new ProtobufCodec(); 21 | DemoResponse.Builder builder = DemoResponse.newBuilder(); 22 | builder.setUserId(100); 23 | builder.setUserName("neoRemind"); 24 | builder.setGenderType(GenderType.MALE); 25 | DemoResponse res = builder.build(); 26 | System.out.println("origin:\n" + res); 27 | byte[] data = codec.encode(DemoResponse.class, res); 28 | System.out.println("encode using " + (System.currentTimeMillis() - start) + "ms"); 29 | start = System.currentTimeMillis(); 30 | // codec = new ProtobufCodec(); 31 | DemoResponse res2 = (DemoResponse) codec.decode(DemoResponse.class, data); 32 | System.out.println("decode using " + (System.currentTimeMillis() - start) + "ms"); 33 | System.out.println("after:\n" + res2); 34 | assertThat(res2, notNullValue()); 35 | assertThat(res2.getUserId(), is(100)); 36 | assertThat(res2.getUserName(), is("neoRemind")); 37 | assertThat(res2.getGenderType(), is(GenderType.MALE)); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/error/ExceptionUtil.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.error; 2 | 3 | import com.baidu.beidou.navi.pbrpc.exception.CodecException; 4 | import com.baidu.beidou.navi.pbrpc.exception.CommunicationException; 5 | import com.baidu.beidou.navi.pbrpc.exception.ServerExecutionException; 6 | import com.baidu.beidou.navi.pbrpc.exception.ServiceNotFoundException; 7 | import com.baidu.beidou.navi.pbrpc.protocol.NsHead; 8 | 9 | /** 10 | * ClassName: ExceptionUtil
11 | * Function: 客户端构造异常工具 12 | * 13 | * @author Zhang Xu 14 | */ 15 | public class ExceptionUtil { 16 | 17 | /** 18 | * 根据{@link NsHead}中保存的flags中定义的errorCode构造异常 19 | * 20 | * @param errorCode 21 | * @return 22 | */ 23 | public static RuntimeException buildFromErrorCode(ErrorCode errorCode) { 24 | if (errorCode == ErrorCode.PROTOBUF_CODEC_ERROR) { 25 | return new CodecException( 26 | "Serialization failed at server, please check proto compatiblity"); 27 | } else if (errorCode == ErrorCode.SERVICE_NOT_FOUND) { 28 | return new ServiceNotFoundException( 29 | "Service not found, please check serviceId specified"); 30 | } else if (errorCode == ErrorCode.INVOCATION_TARGET_EXCEPTION 31 | || errorCode == ErrorCode.UNEXPECTED_ERROR) { 32 | return new ServerExecutionException( 33 | "Exception occurred at server, and cause can be only get from server"); 34 | } else if (errorCode == ErrorCode.COMMUNICATION_ERROR) { 35 | return new CommunicationException(); 36 | } else { 37 | return new RuntimeException( 38 | "Failed to specify server error though there is error happened"); 39 | } 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/transport/handler/RpcServerChannelIdleHandler.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.transport.handler; 2 | 3 | import io.netty.channel.ChannelDuplexHandler; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.handler.timeout.IdleState; 6 | import io.netty.handler.timeout.IdleStateEvent; 7 | 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | /** 12 | * ClassName: RpcServerChannelIdleHandler
13 | * Function: 处理一些空闲的连接闭关它们,防止占用服务端资源 14 | * 15 | * @author Zhang Xu 16 | */ 17 | public class RpcServerChannelIdleHandler extends ChannelDuplexHandler { 18 | 19 | private static final Logger LOG = LoggerFactory.getLogger(RpcServerChannelIdleHandler.class); 20 | 21 | /** 22 | * Creates a new instance of RpcServerChannelIdleHandler. 23 | */ 24 | public RpcServerChannelIdleHandler() { 25 | 26 | } 27 | 28 | /** 29 | * @see io.netty.channel.ChannelInboundHandlerAdapter#userEventTriggered(io.netty.channel.ChannelHandlerContext, 30 | * java.lang.Object) 31 | */ 32 | @Override 33 | public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { 34 | if (evt instanceof IdleStateEvent) { 35 | IdleStateEvent e = (IdleStateEvent) evt; 36 | if (e.state() == IdleState.WRITER_IDLE) { 37 | LOG.warn("Write idle on channel:" + ctx.channel() + " is timeout"); 38 | } else if (e.state() == IdleState.READER_IDLE) { 39 | LOG.warn("Read idle on channel:" + ctx.channel() + " is timeout on " 40 | + ctx.channel().remoteAddress() + ", so close it"); 41 | // ctx.fireExceptionCaught(ReadTimeoutException.INSTANCE); 42 | ctx.close(); 43 | } 44 | } 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/client/PbrpcClientChannelPool.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.client; 2 | 3 | import org.apache.commons.pool.impl.GenericObjectPool.Config; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import com.baidu.beidou.navi.pbrpc.util.Pool; 8 | 9 | /** 10 | * ClassName: PbrpcClientChannelPool
11 | * Function: 客户端连接池,也叫做信道池 12 | * 13 | * @author Zhang Xu 14 | */ 15 | public class PbrpcClientChannelPool extends Pool { 16 | 17 | private static final Logger LOG = LoggerFactory.getLogger(PbrpcClientChannelPool.class); 18 | 19 | /** 20 | * Creates a new instance of PbrpcClientConnectionPool. 21 | * 22 | * @param poolConfig 23 | * @param clientConfig 24 | * @param host 25 | * @param port 26 | * @param connTimeout 27 | * @param readTimeout 28 | */ 29 | public PbrpcClientChannelPool(final Config poolConfig, 30 | final PbrpcClientConfiguration clientConfig, final String host, int port, 31 | int connTimeout, int readTimeout) { 32 | super(poolConfig, new PbrpcClientChannelFactory(clientConfig, host, port, connTimeout, 33 | readTimeout)); 34 | LOG.info("Init connection pool done but connections will not be established until you start using the pool"); 35 | } 36 | 37 | /** 38 | * @see com.baidu.beidou.navi.pbrpc.util.Pool#returnBrokenResource(java.lang.Object) 39 | */ 40 | public void returnBrokenResource(final PbrpcClientChannel resource) { 41 | returnBrokenResourceObject(resource); 42 | } 43 | 44 | /** 45 | * @see com.baidu.beidou.navi.pbrpc.util.Pool#returnResource(java.lang.Object) 46 | */ 47 | public void returnResource(final PbrpcClientChannel resource) { 48 | returnResourceObject(resource); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/test/java/com/baidu/beidou/navi/pbrpc/it/NegativePbrpcClientTest.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.it; 2 | 3 | import org.junit.Test; 4 | 5 | import com.baidu.beidou.navi.pbrpc.client.PbrpcClient; 6 | import com.baidu.beidou.navi.pbrpc.client.PbrpcClientFactory; 7 | import com.baidu.beidou.navi.pbrpc.exception.CodecException; 8 | import com.baidu.beidou.navi.pbrpc.exception.ServerExecutionException; 9 | import com.baidu.beidou.navi.pbrpc.exception.ServiceNotFoundException; 10 | import com.baidu.beidou.navi.pbrpc.transport.PbrpcMsg; 11 | 12 | public class NegativePbrpcClientTest extends BaseTest { 13 | 14 | @Test 15 | public void testMethodNotFoundException() throws Exception { 16 | PbrpcMsg msg = getPbrpcMsg(1).setServiceId(-1); 17 | asyncCall(new ClientBuilder() { 18 | @Override 19 | public PbrpcClient getClient() { 20 | return PbrpcClientFactory.buildPooledConnection(IP, PORT); 21 | } 22 | }, msg, new ServiceNotFoundException(), false); 23 | } 24 | 25 | @Test 26 | public void testServerExecutionException() throws Exception { 27 | PbrpcMsg msg = getPbrpcMsg(9999); 28 | asyncCall(new ClientBuilder() { 29 | @Override 30 | public PbrpcClient getClient() { 31 | return PbrpcClientFactory.buildPooledConnection(IP, PORT); 32 | } 33 | }, msg, new ServerExecutionException(), false); 34 | } 35 | 36 | @Test 37 | public void testCodecException() throws Exception { 38 | PbrpcMsg msg = getPbrpcMsg(1).setData(new String("xyz").getBytes()); 39 | asyncCall(new ClientBuilder() { 40 | @Override 41 | public PbrpcClient getClient() { 42 | return PbrpcClientFactory.buildPooledConnection(IP, PORT); 43 | } 44 | }, msg, new CodecException(), false); 45 | } 46 | 47 | } -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/client/ha/ConnectStringParser.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.client.ha; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.baidu.beidou.navi.pbrpc.exception.client.HAPbrpcException; 7 | import com.baidu.beidou.navi.pbrpc.util.StringPool; 8 | 9 | /** 10 | * ClassName: ConnectStringParser
11 | * Function: 连接字符串的解析器,用于解析例如1.1.1.1:8080,2.2.2.2:9999类似的参数并且转换为{@link IpPort}对象列表 12 | * 13 | * @author Zhang Xu 14 | */ 15 | public class ConnectStringParser { 16 | 17 | /** 18 | * 解析连接字符串,例如1.1.1.1:8080,2.2.2.2:9999类似的参数,转换为{@link IpPort}对象列表 19 | * 20 | * @param connectString 21 | * @return List 22 | */ 23 | public static List resolveConnectString(String connectString) { 24 | if (connectString == null || connectString.length() == 0 || connectString.equals("")) { 25 | throw new HAPbrpcException("connect string should not be empty"); 26 | } 27 | List ret = new ArrayList(8); 28 | String[] pairs = connectString.split(StringPool.Symbol.COMMA); 29 | for (String pair : pairs) { 30 | String[] arr = pair.split(StringPool.Symbol.COLON); 31 | if (arr.length != 2) { 32 | throw new HAPbrpcException( 33 | "connect string is invalid, string should be split by comma like 1.1.1.1:8088,2.2.2.2:8099"); 34 | } 35 | String ip = arr[0]; 36 | int port = 0; 37 | try { 38 | port = Integer.parseInt(arr[1]); 39 | } catch (NumberFormatException e) { 40 | throw new HAPbrpcException("connect string is invalid, port should be a number"); 41 | } 42 | 43 | IpPort ipPort = new IpPort(ip, port); 44 | ret.add(ipPort); 45 | } 46 | return ret; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/util/ConcurrentCache.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.util; 2 | 3 | import java.util.concurrent.Callable; 4 | import java.util.concurrent.ConcurrentHashMap; 5 | import java.util.concurrent.ConcurrentMap; 6 | import java.util.concurrent.Future; 7 | import java.util.concurrent.FutureTask; 8 | 9 | /** 10 | * ClassName: ConcurrentCache
11 | * Function: 此类不用额外使用自旋锁或者同步器,可保证并发时线程安全,在并发情况下具有高性能 12 | * 13 | * @author Xu Chen, Zhang Xu 14 | */ 15 | public class ConcurrentCache implements Computable { 16 | 17 | /** 18 | * 并发安全Map 19 | */ 20 | private final ConcurrentMap> concurrentMap; 21 | 22 | /** 23 | * Creates a new instance of ConcurrentCache. 24 | */ 25 | public ConcurrentCache() { 26 | concurrentMap = new ConcurrentHashMap>(); 27 | } 28 | 29 | /** 30 | * 静态方法返回计算接口 31 | * 32 | * @return 33 | */ 34 | public static Computable createComputable() { 35 | return new ConcurrentCache(); 36 | } 37 | 38 | /** 39 | * 通过关键字获取数据,如果存在则直接返回,如果不存在,则通过计算callable来生成 40 | * 41 | * @param key 42 | * 查找关键字 43 | * @param callable 44 | * # @see Callable 45 | * @return 计算结果 46 | */ 47 | public V get(K key, Callable callable) { 48 | Future future = concurrentMap.get(key); 49 | if (future == null) { 50 | FutureTask futureTask = new FutureTask(callable); 51 | future = concurrentMap.putIfAbsent(key, futureTask); 52 | if (future == null) { 53 | future = futureTask; 54 | futureTask.run(); 55 | } 56 | } 57 | try { 58 | // 此时阻塞 59 | return future.get(); 60 | } catch (Exception e) { 61 | concurrentMap.remove(key); 62 | return null; 63 | } 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/test/java/com/baidu/beidou/navi/pbrpc/it/ShortAliveConnectionPbrpcClientTest.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.it; 2 | 3 | import io.netty.channel.ConnectTimeoutException; 4 | 5 | import org.junit.Test; 6 | 7 | import com.baidu.beidou.navi.pbrpc.client.PbrpcClient; 8 | import com.baidu.beidou.navi.pbrpc.client.PbrpcClientFactory; 9 | import com.baidu.beidou.navi.pbrpc.exception.TimeoutException; 10 | import com.baidu.beidou.navi.pbrpc.transport.PbrpcMsg; 11 | 12 | public class ShortAliveConnectionPbrpcClientTest extends BaseTest { 13 | 14 | @Test 15 | public void testAsyncCall() throws Exception { 16 | asyncCall(new ClientBuilder() { 17 | @Override 18 | public PbrpcClient getClient() { 19 | return PbrpcClientFactory.buildShortLiveConnection(IP, PORT); 20 | } 21 | }); 22 | } 23 | 24 | @Test 25 | public void testSyncCall() throws Exception { 26 | syncCall(new ClientBuilder() { 27 | @Override 28 | public PbrpcClient getClient() { 29 | return PbrpcClientFactory.buildShortLiveConnection(IP, PORT, 2000, 5000); 30 | } 31 | }); 32 | } 33 | 34 | @Test 35 | public void testSyncCallTimeout() throws Exception { 36 | PbrpcMsg msg = getPbrpcMsg(1).setServiceId(101); 37 | asyncCall(new ClientBuilder() { 38 | @Override 39 | public PbrpcClient getClient() { 40 | return PbrpcClientFactory.buildShortLiveConnection(IP, PORT, 500); 41 | } 42 | }, msg, new TimeoutException(), false); 43 | } 44 | 45 | @Test 46 | public void testNegativeConnectCall() throws Exception { 47 | asyncCall(new ClientBuilder() { 48 | @Override 49 | public PbrpcClient getClient() { 50 | return PbrpcClientFactory.buildShortLiveConnection("9.9.9.9", 9999); 51 | } 52 | }, new ConnectTimeoutException(), false); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/client/PbrpcClientConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.client; 2 | 3 | import io.netty.channel.ChannelOption; 4 | 5 | /** 6 | * ClassName: PbrpcClientConfiguration
7 | * Function: 客户端配置 8 | * 9 | * @author Zhang Xu 10 | */ 11 | public class PbrpcClientConfiguration { 12 | 13 | /** 14 | * keep alive 15 | * 16 | * @see ChannelOption#SO_KEEPALIVE 17 | */ 18 | private boolean soKeepalive = true; 19 | 20 | /** 21 | * reuse addr 22 | * 23 | * @see ChannelOption#SO_REUSEADDR 24 | */ 25 | private boolean soReuseaddr = true; 26 | 27 | /** 28 | * tcp nodelay 29 | * 30 | * @see ChannelOption#TCP_NODELAY 31 | */ 32 | private boolean tcpNodelay = true; 33 | 34 | /** 35 | * receive buf size 36 | * 37 | * @see ChannelOption#SO_RCVBUF 38 | */ 39 | private int soRcvbuf = 1024 * 128; 40 | 41 | /** 42 | * send buf size 43 | * 44 | * @see ChannelOption#SO_SNDBUF 45 | */ 46 | private int soSndbuf = 1024 * 128; 47 | 48 | public boolean isSoKeepalive() { 49 | return soKeepalive; 50 | } 51 | 52 | public void setSoKeepalive(boolean soKeepalive) { 53 | this.soKeepalive = soKeepalive; 54 | } 55 | 56 | public boolean isSoReuseaddr() { 57 | return soReuseaddr; 58 | } 59 | 60 | public void setSoReuseaddr(boolean soReuseaddr) { 61 | this.soReuseaddr = soReuseaddr; 62 | } 63 | 64 | public boolean isTcpNodelay() { 65 | return tcpNodelay; 66 | } 67 | 68 | public void setTcpNodelay(boolean tcpNodelay) { 69 | this.tcpNodelay = tcpNodelay; 70 | } 71 | 72 | public int getSoRcvbuf() { 73 | return soRcvbuf; 74 | } 75 | 76 | public void setSoRcvbuf(int soRcvbuf) { 77 | this.soRcvbuf = soRcvbuf; 78 | } 79 | 80 | public int getSoSndbuf() { 81 | return soSndbuf; 82 | } 83 | 84 | public void setSoSndbuf(int soSndbuf) { 85 | this.soSndbuf = soSndbuf; 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /src/test/java/com/baidu/beidou/navi/pbrpc/it/PooledPbrpcClientTest.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.it; 2 | 3 | import org.junit.Test; 4 | 5 | import com.baidu.beidou.navi.pbrpc.client.PbrpcClient; 6 | import com.baidu.beidou.navi.pbrpc.client.PbrpcClientFactory; 7 | import com.baidu.beidou.navi.pbrpc.client.PooledConfiguration; 8 | import com.baidu.beidou.navi.pbrpc.exception.TimeoutException; 9 | import com.baidu.beidou.navi.pbrpc.exception.client.PbrpcConnectionException; 10 | import com.baidu.beidou.navi.pbrpc.transport.PbrpcMsg; 11 | 12 | public class PooledPbrpcClientTest extends BaseTest { 13 | 14 | @Test 15 | public void testAsyncCall() throws Exception { 16 | asyncCall(new ClientBuilder() { 17 | @Override 18 | public PbrpcClient getClient() { 19 | return PbrpcClientFactory.buildPooledConnection(IP, PORT); 20 | } 21 | }); 22 | } 23 | 24 | @Test 25 | public void testSyncCall() throws Exception { 26 | syncCall(new ClientBuilder() { 27 | @Override 28 | public PbrpcClient getClient() { 29 | return PbrpcClientFactory.buildPooledConnection(new PooledConfiguration(), IP, 30 | PORT, 2000, 10000); 31 | } 32 | }); 33 | } 34 | 35 | @Test 36 | public void testSyncCallTimeout() throws Exception { 37 | PbrpcMsg msg = getPbrpcMsg(1).setServiceId(101); 38 | syncCall(new ClientBuilder() { 39 | @Override 40 | public PbrpcClient getClient() { 41 | return PbrpcClientFactory.buildPooledConnection(IP, PORT, 500); 42 | } 43 | }, msg, new TimeoutException(), false); 44 | } 45 | 46 | @Test 47 | public void testNegativeConnectCall() throws Exception { 48 | asyncCall(new ClientBuilder() { 49 | @Override 50 | public PbrpcClient getClient() { 51 | return PbrpcClientFactory.buildPooledConnection("9.9.9.9", 9999); 52 | } 53 | }, new PbrpcConnectionException(), true); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/server/core/impl/SimpleMethodResolver.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.server.core.impl; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import com.baidu.beidou.navi.pbrpc.server.core.MethodResolver; 9 | import com.baidu.beidou.navi.pbrpc.util.ReflectionUtil; 10 | import com.google.protobuf.GeneratedMessage; 11 | 12 | /** 13 | * ClassName: SimpleMethodResolver
14 | * Function: 默认的简单服务暴露判断类 15 | * 16 | * @author Zhang Xu 17 | */ 18 | public class SimpleMethodResolver implements MethodResolver { 19 | 20 | private static final Logger LOG = LoggerFactory.getLogger(SimpleMethodResolver.class); 21 | 22 | /** 23 | * 判断某个方法是否可以暴露为服务,这里的判断条件是满足以下 24 | *
    25 | *
  • 1)参数只有一个
  • 26 | *
  • 2)参数必须是protoc自动生成的GeneratedMessage类型的子类
  • 27 | *
  • 3)返回不能为void
  • 28 | *
  • 4)返回必须是protoc自动生成的GeneratedMessage类型的子类
  • 29 | *
30 | * 31 | * @see com.baidu.beidou.navi.pbrpc.server.core.MethodResolver#isSupport(java.lang.reflect.Method) 32 | */ 33 | @Override 34 | public boolean isSupport(Method m) { 35 | Class[] paramTypes = m.getParameterTypes(); 36 | Class returnType = m.getReturnType(); 37 | if (paramTypes.length != 1) { 38 | LOG.warn("Pbrpc only supports one parameter, skip " + m.getName()); 39 | return false; 40 | } 41 | if (paramTypes[0].isAssignableFrom(GeneratedMessage.class)) { 42 | LOG.warn("Method argument type is not GeneratedMessage, skip " + m.getName()); 43 | return false; 44 | } 45 | if (ReflectionUtil.isVoid(returnType)) { 46 | LOG.warn("Method return type should not be void, skip " + m.getName()); 47 | return false; 48 | } 49 | if (returnType.isAssignableFrom(GeneratedMessage.class)) { 50 | LOG.warn("Method return type is not GeneratedMessage, skip " + m.getName()); 51 | return false; 52 | } 53 | 54 | return true; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/test/java/com/baidu/beidou/navi/pbrpc/it/BlockingIOPbrpcClientTest.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.it; 2 | 3 | import org.junit.Test; 4 | 5 | import com.baidu.beidou.navi.pbrpc.client.PbrpcClient; 6 | import com.baidu.beidou.navi.pbrpc.client.PbrpcClientFactory; 7 | import com.baidu.beidou.navi.pbrpc.exception.client.OperationNotSupportException; 8 | import com.baidu.beidou.navi.pbrpc.exception.client.PbrpcConnectionException; 9 | import com.baidu.beidou.navi.pbrpc.exception.client.PbrpcException; 10 | import com.baidu.beidou.navi.pbrpc.transport.PbrpcMsg; 11 | 12 | public class BlockingIOPbrpcClientTest extends BaseTest { 13 | 14 | @Test 15 | public void testSyncCall() throws Exception { 16 | syncCall(new ClientBuilder() { 17 | @Override 18 | public PbrpcClient getClient() { 19 | return PbrpcClientFactory.buildShortLiveBlockingIOConnection(IP, PORT); 20 | } 21 | }); 22 | } 23 | 24 | @Test 25 | public void testSyncCallTimeout() throws Exception { 26 | PbrpcMsg msg = getPbrpcMsg(1).setServiceId(101); 27 | syncCall(new ClientBuilder() { 28 | @Override 29 | public PbrpcClient getClient() { 30 | return PbrpcClientFactory.buildShortLiveBlockingIOConnection(IP, PORT, 1000); 31 | } 32 | }, msg, new PbrpcException(), true); 33 | } 34 | 35 | @Test 36 | public void testNegativeConnectCall() throws Exception { 37 | syncCall(new ClientBuilder() { 38 | @Override 39 | public PbrpcClient getClient() { 40 | return PbrpcClientFactory.buildShortLiveBlockingIOConnection("9.9.9.9", 9999); 41 | } 42 | }, new PbrpcConnectionException(), true); 43 | } 44 | 45 | @Test 46 | public void testNegativeASyncCall() throws Exception { 47 | asyncCall(new ClientBuilder() { 48 | @Override 49 | public PbrpcClient getClient() { 50 | return PbrpcClientFactory.buildShortLiveBlockingIOConnection(IP, PORT, 2000, 10000); 51 | } 52 | }, new OperationNotSupportException(), true); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/test/java/com/baidu/beidou/navi/pbrpc/it/BlockingIOPooledPbrpcClientTest.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.it; 2 | 3 | import org.junit.Test; 4 | 5 | import com.baidu.beidou.navi.pbrpc.client.PbrpcClient; 6 | import com.baidu.beidou.navi.pbrpc.client.PbrpcClientFactory; 7 | import com.baidu.beidou.navi.pbrpc.client.PooledConfiguration; 8 | import com.baidu.beidou.navi.pbrpc.exception.client.OperationNotSupportException; 9 | import com.baidu.beidou.navi.pbrpc.exception.client.PbrpcException; 10 | import com.baidu.beidou.navi.pbrpc.transport.PbrpcMsg; 11 | 12 | public class BlockingIOPooledPbrpcClientTest extends BaseTest { 13 | 14 | @Test 15 | public void testSyncCall() throws Exception { 16 | syncCall(new ClientBuilder() { 17 | @Override 18 | public PbrpcClient getClient() { 19 | return PbrpcClientFactory.buildPooledBlockingIOConnection(IP, PORT); 20 | } 21 | }); 22 | } 23 | 24 | @Test 25 | public void testSyncCallTimeout() throws Exception { 26 | PbrpcMsg msg = getPbrpcMsg(1).setServiceId(101); 27 | syncCall(new ClientBuilder() { 28 | @Override 29 | public PbrpcClient getClient() { 30 | return PbrpcClientFactory.buildPooledBlockingIOConnection(IP, PORT, 2000); 31 | } 32 | }, msg, new PbrpcException(), true); 33 | } 34 | 35 | @Test 36 | public void testNegativeConnectCall() throws Exception { 37 | syncCall(new ClientBuilder() { 38 | @Override 39 | public PbrpcClient getClient() { 40 | return PbrpcClientFactory.buildPooledBlockingIOConnection("9.9.9.9", 9999); 41 | } 42 | }, new PbrpcException(), true); 43 | } 44 | 45 | @Test 46 | public void testNegativeASyncCall() throws Exception { 47 | asyncCall(new ClientBuilder() { 48 | @Override 49 | public PbrpcClient getClient() { 50 | return PbrpcClientFactory.buildPooledBlockingIOConnection( 51 | new PooledConfiguration(), IP, PORT, 2000, 5000); 52 | } 53 | }, new OperationNotSupportException(), true); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/error/ErrorCode.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.error; 2 | 3 | import com.baidu.beidou.navi.pbrpc.protocol.NsHead; 4 | 5 | /** 6 | * ClassName: ErrorCode
7 | * Function: 常见错误信息枚举,用于填充{@link NsHead}内的flagsusigned short(4),用于服务端和客户端的错误信息交换。
8 | * 这里注意一般情况希望错误返回信息包括errCode、returnCode等由业务逻辑维护,这里是针对Pbprc这个框架做的异常,如果业务逻辑没有处理自己的异常,那么实际客户端是没有办法知道详细信息的,只会有一个笼统的未知异常告知客户端 9 | * 10 | * @author Zhang Xu 11 | */ 12 | public enum ErrorCode { 13 | 14 | SERVICE_NOT_FOUND(0x7f, "Service not found "), PROTOBUF_CODEC_ERROR(0x7e, 15 | "Protobuf codec failed "), INVOCATION_TARGET_EXCEPTION(0x7d, 16 | "Invocation method on target bean failed "), UNEXPECTED_ERROR(0x7c, 17 | "Unexpected error occurred which should not happen "), COMMUNICATION_ERROR(0x7b, 18 | "Communication error occurred "); 19 | 20 | /** 21 | * 错误码 22 | */ 23 | private int value = 0; 24 | 25 | /** 26 | * 错误消息 27 | */ 28 | private String message = ""; 29 | 30 | /** 31 | * Creates a new instance of ErrorCode. 32 | * 33 | * @param value 34 | * @param message 35 | */ 36 | private ErrorCode(int value, String message) { 37 | this.value = value; 38 | this.message = message; 39 | } 40 | 41 | /** 42 | * 根据错误码返回错误枚举 43 | * 44 | * @param errorCode 45 | * @return 46 | */ 47 | public static ErrorCode get(int errorCode) { 48 | if (SERVICE_NOT_FOUND.getValue() == errorCode) { 49 | return SERVICE_NOT_FOUND; 50 | } else if (PROTOBUF_CODEC_ERROR.getValue() == errorCode) { 51 | return PROTOBUF_CODEC_ERROR; 52 | } else if (INVOCATION_TARGET_EXCEPTION.getValue() == errorCode) { 53 | return INVOCATION_TARGET_EXCEPTION; 54 | } else if (UNEXPECTED_ERROR.getValue() == errorCode) { 55 | return UNEXPECTED_ERROR; 56 | } else if (COMMUNICATION_ERROR.getValue() == errorCode) { 57 | return COMMUNICATION_ERROR; 58 | } 59 | return null; 60 | } 61 | 62 | public int getValue() { 63 | return value; 64 | } 65 | 66 | public String getMessage() { 67 | return message; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/transport/PbrpcMessageDeserializer.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.transport; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.handler.codec.ByteToMessageDecoder; 6 | 7 | import java.util.List; 8 | 9 | import com.baidu.beidou.navi.pbrpc.protocol.NsHead; 10 | import com.baidu.beidou.navi.pbrpc.util.ContextHolder; 11 | 12 | /** 13 | * ClassName: PbrpcMessageDeserializer
14 | * Function: 反序列化handler 15 | * 16 | * @author Zhang Xu 17 | */ 18 | public class PbrpcMessageDeserializer extends ByteToMessageDecoder { 19 | 20 | // private static final Logger LOG = LoggerFactory.getLogger(PbrpcMessageDeserializer.class); 21 | 22 | /** 23 | * @see io.netty.handler.codec.ByteToMessageDecoder#decode(io.netty.channel.ChannelHandlerContext, 24 | * io.netty.buffer.ByteBuf, java.util.List) 25 | */ 26 | @Override 27 | protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { 28 | // 解决半包问题,此时Nshead还没有接收全,channel中留存的字节流不做处理 29 | if (in.readableBytes() < NsHead.NSHEAD_LEN) { 30 | return; 31 | } 32 | 33 | in.markReaderIndex(); 34 | 35 | byte[] bytes = new byte[NsHead.NSHEAD_LEN]; 36 | in.readBytes(bytes, 0, NsHead.NSHEAD_LEN); 37 | 38 | NsHead nsHead = new NsHead(); 39 | nsHead.wrap(bytes); 40 | 41 | // 解决半包问题,此时body还没有接收全,channel中留存的字节流不做处理,重置readerIndex 42 | if (in.readableBytes() < (int) nsHead.getBodyLen()) { 43 | in.resetReaderIndex(); 44 | return; 45 | } 46 | 47 | // 此时接受到了足够的一个包,开始处理 48 | in.markReaderIndex(); 49 | 50 | byte[] totalBytes = new byte[(int) nsHead.getBodyLen()]; 51 | in.readBytes(totalBytes, 0, (int) nsHead.getBodyLen()); 52 | 53 | PbrpcMsg decoded = PbrpcMsg.of(nsHead).setData(totalBytes); 54 | ContextHolder.putContext("_logid", nsHead.getLogId()); // TODO 55 | 56 | if (decoded != null) { 57 | out.add(decoded); 58 | } 59 | // LOG.info("Deser data " + nsHead.getLogId() + " is" + decoded + " and using " 60 | // + (System.nanoTime() - start) / 1000 + "us"); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/test/java/com/baidu/beidou/navi/pbrpc/it/ComplicatedResponsePbrpcClientTest.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.it; 2 | 3 | import static org.hamcrest.Matchers.is; 4 | import static org.junit.Assert.assertThat; 5 | 6 | import org.junit.Test; 7 | 8 | import com.baidu.beidou.navi.pbrpc.client.PbrpcClientFactory; 9 | import com.baidu.beidou.navi.pbrpc.client.callback.CallFuture; 10 | import com.baidu.beidou.navi.pbrpc.demo.proto.Demo.DemoBatchRequest; 11 | import com.baidu.beidou.navi.pbrpc.demo.proto.Demo.DemoBatchResponse; 12 | import com.baidu.beidou.navi.pbrpc.transport.PbrpcMsg; 13 | 14 | public class ComplicatedResponsePbrpcClientTest extends BaseTest { 15 | 16 | @Test 17 | public void testComplicatedCall() throws Exception { 18 | System.out.println("============================"); 19 | System.out.println("async call test starts ..."); 20 | System.out.println("============================"); 21 | 22 | CLIENT = PbrpcClientFactory.buildShortLiveConnection(IP, PORT); 23 | System.out.println(CLIENT.getInfo()); 24 | 25 | // async 26 | for (int i = 1; i <= 2; i++) { 27 | System.out.println("call-" + i + " starts..."); 28 | long start = System.currentTimeMillis(); 29 | DemoBatchResponse res = null; 30 | CallFuture f = CLIENT.asyncTransport(DemoBatchResponse.class, 31 | getPbrpcMsg()); 32 | res = f.get(); 33 | System.out.println("----\n" + res); 34 | assertThat(res.getTextsList().size(), is(5)); 35 | assertThat(res.getTextsList().get(0).getText(), is("abcdefg")); 36 | System.out.println("Call-" + i + " ends using " + (System.currentTimeMillis() - start) 37 | + "ms"); 38 | } 39 | } 40 | 41 | public PbrpcMsg getPbrpcMsg() { 42 | PbrpcMsg msg = new PbrpcMsg(); 43 | msg.setServiceId(102); 44 | msg.setProvider("beidou"); 45 | msg.setData(getData(5, "abcdefg")); 46 | return msg; 47 | } 48 | 49 | public byte[] getData(int size, String text) { 50 | DemoBatchRequest.Builder req = DemoBatchRequest.newBuilder(); 51 | req.setRequestSize(size); 52 | req.setText(text); 53 | byte[] data = req.build().toByteArray(); 54 | return data; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/test/java/com/baidu/beidou/navi/pbrpc/util/PreconditionsTest.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.util; 2 | 3 | import org.junit.Test; 4 | 5 | public class PreconditionsTest { 6 | 7 | @Test 8 | public void testCheckArgument() { 9 | try { 10 | int i = -1; 11 | Preconditions.checkArgument(i >= 0, "Argument was %s but expected nonnegative", i); 12 | } catch (Exception e) { 13 | // TODO: handle exception 14 | } 15 | try { 16 | int i = -1; 17 | Preconditions.checkArgument(i >= 0); 18 | } catch (Exception e) { 19 | // TODO: handle exception 20 | } 21 | 22 | try { 23 | int i = -1; 24 | Preconditions.checkArgument(i >= 0, "Argument expected nonnegative"); 25 | } catch (Exception e) { 26 | // TODO: handle exception 27 | } 28 | } 29 | 30 | @Test 31 | public void testCheckNotNull() { 32 | try { 33 | Object obj = null; 34 | Preconditions.checkNotNull(obj, "Argument was %s but expected not null", obj); 35 | } catch (Exception e) { 36 | // TODO: handle exception 37 | } 38 | 39 | try { 40 | Object obj = null; 41 | Preconditions.checkNotNull(obj); 42 | } catch (Exception e) { 43 | // TODO: handle exception 44 | } 45 | 46 | try { 47 | Object obj = null; 48 | Preconditions.checkNotNull(obj, "Argument expected not null"); 49 | } catch (Exception e) { 50 | // TODO: handle exception 51 | } 52 | } 53 | 54 | @Test 55 | public void testCheckState() { 56 | try { 57 | int x = 1; 58 | Preconditions.checkState(x == 5, "Argument was %s but expected 5", x); 59 | } catch (Exception e) { 60 | // TODO: handle exception 61 | } 62 | 63 | try { 64 | int x = 1; 65 | Preconditions.checkState(x == 5); 66 | } catch (Exception e) { 67 | // TODO: handle exception 68 | } 69 | 70 | try { 71 | int x = 1; 72 | Preconditions.checkState(x == 5, "Argument expected 5"); 73 | } catch (Exception e) { 74 | // TODO: handle exception 75 | } 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/test/java/com/baidu/beidou/navi/pbrpc/client/HAPbrpcClientMainTest.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.client; 2 | 3 | import com.baidu.beidou.navi.pbrpc.client.callback.CallFuture; 4 | import com.baidu.beidou.navi.pbrpc.client.ha.FailOverStrategy; 5 | import com.baidu.beidou.navi.pbrpc.client.ha.RandomLoadBalanceStrategy; 6 | import com.baidu.beidou.navi.pbrpc.demo.proto.Demo.DemoRequest; 7 | import com.baidu.beidou.navi.pbrpc.demo.proto.Demo.DemoResponse; 8 | import com.baidu.beidou.navi.pbrpc.transport.PbrpcMsg; 9 | 10 | public class HAPbrpcClientMainTest { 11 | 12 | public static void main(String[] args) throws Exception { 13 | PbrpcClient client = HAPbrpcClientFactory.buildShortLiveConnection("127.0.0.1:8088,1.1.1.1:9999", 14 | new RandomLoadBalanceStrategy(new FailOverStrategy(2))); 15 | 16 | PbrpcMsg msg = new PbrpcMsg(); 17 | msg.setServiceId(100); 18 | msg.setProvider("beidou"); 19 | 20 | for (int i = 0; i < 10; i++) { 21 | long start = System.currentTimeMillis(); 22 | msg.setData(getData(1)); 23 | CallFuture future = client.asyncTransport(DemoResponse.class, msg); 24 | DemoResponse res = future.get(); 25 | System.out.println("----\n" + res); 26 | System.out.println("Invoke using " + (System.currentTimeMillis() - start) + "ms"); 27 | } 28 | 29 | // async 30 | long start = System.currentTimeMillis(); 31 | msg.setData(getData(1)); 32 | CallFuture future = client.asyncTransport(DemoResponse.class, msg); 33 | DemoResponse res = future.get(); 34 | System.out.println("----\n" + res); 35 | System.out.println("Invoke using " + (System.currentTimeMillis() - start) + "ms"); 36 | // 37 | // // sync 38 | // start = System.currentTimeMillis(); 39 | // msg.setData(getData(5)); 40 | // res = client.syncTransport(DemoResponse.class, msg); 41 | // System.out.println("----\n" + res); 42 | // System.out.println("Invoke using " + (System.currentTimeMillis() - start) + "ms"); 43 | 44 | } 45 | 46 | private static byte[] getData(int userId) { 47 | DemoRequest.Builder req = DemoRequest.newBuilder(); 48 | req.setUserId(userId); 49 | byte[] data = req.build().toByteArray(); 50 | return data; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/client/TimeoutEvictionTimer.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.client; 2 | 3 | import java.util.Timer; 4 | import java.util.TimerTask; 5 | import java.util.concurrent.atomic.AtomicInteger; 6 | 7 | /** 8 | * ClassName: TimeoutEvictionTimer
9 | * Function: 客户端超时调用检测器,对于超时的客户端回调后抛出异常{@link com.baidu.beidou.navi.pbrpc.exception.TimeoutException} 10 | * 11 | * @author Zhang Xu 12 | */ 13 | public class TimeoutEvictionTimer { 14 | 15 | /** 16 | * timer 17 | */ 18 | private static Timer timer; 19 | 20 | /** 21 | * 计数器 22 | */ 23 | private static AtomicInteger usageCount = new AtomicInteger(0); 24 | 25 | /** 26 | * Creates a new instance of TimeoutEvictionTimer. 27 | */ 28 | private TimeoutEvictionTimer() { 29 | // Hide the default constuctor 30 | } 31 | 32 | /** 33 | * Add the specified eviction task to the timer. Tasks that are added with a call to this method *must* call 34 | * {@link #cancel(TimerTask)} to cancel the task to prevent memory and/or thread leaks in application server 35 | * environments. 36 | * 37 | * @param task 38 | * Task to be scheduled 39 | * @param evictorDelayCheckMilliSeconds 40 | * Delay in milliseconds before task is executed 41 | * @param evictorCheckPeriodMilliSeconds 42 | * Time in milliseconds between executions 43 | */ 44 | public static synchronized void schedule(TimerTask task, int evictorDelayCheckMilliSeconds, 45 | int evictorCheckPeriodMilliSeconds) { 46 | if (null == timer) { 47 | timer = new Timer(true); 48 | } 49 | usageCount.incrementAndGet(); 50 | timer.schedule(task, evictorDelayCheckMilliSeconds, evictorCheckPeriodMilliSeconds); 51 | } 52 | 53 | /** 54 | * Remove the specified eviction task from the timer. 55 | * 56 | * @param task 57 | * Task to be scheduled 58 | */ 59 | public static synchronized void cancel(TimerTask task) { 60 | if (task == null) { 61 | return; 62 | } 63 | task.cancel(); 64 | usageCount.decrementAndGet(); 65 | if (usageCount.get() == 0) { 66 | timer.cancel(); 67 | timer = null; 68 | } 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/test/java/com/baidu/beidou/navi/pbrpc/client/ShortLiveConnectionPbrpcClientMainTest.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.client; 2 | 3 | import com.baidu.beidou.navi.pbrpc.client.callback.CallFuture; 4 | import com.baidu.beidou.navi.pbrpc.demo.proto.Demo.DemoRequest; 5 | import com.baidu.beidou.navi.pbrpc.demo.proto.Demo.DemoResponse; 6 | import com.baidu.beidou.navi.pbrpc.transport.PbrpcMsg; 7 | 8 | public class ShortLiveConnectionPbrpcClientMainTest { 9 | 10 | public static void main(String[] args) throws Exception { 11 | PbrpcClient client = PbrpcClientFactory.buildPooledConnection("127.0.0.1", 8088, 60000); 12 | 13 | PbrpcMsg msg = new PbrpcMsg(); 14 | msg.setServiceId(100); 15 | msg.setProvider("beidou"); 16 | // 17 | // for (int i = 0; i < 10000; i++) { 18 | // Thread.sleep(5000); 19 | // System.out.println("got here"); 20 | // // async 21 | // long start = System.currentTimeMillis(); 22 | // msg.setData(getData(1)); 23 | // try { 24 | // CallFuture future = client.asyncTransport(DemoResponse.class, msg); 25 | // DemoResponse res = future.get(); 26 | // System.out.println("----\n" + res); 27 | // System.out.println("Invoke using " + (System.currentTimeMillis() - start) + "ms"); 28 | // 29 | // } catch (Exception e) { 30 | // e.printStackTrace(); 31 | // } 32 | // } 33 | 34 | // async 35 | long start = System.currentTimeMillis(); 36 | msg.setData(getData(1)); 37 | CallFuture future = client.asyncTransport(DemoResponse.class, msg); 38 | DemoResponse res = future.get(); 39 | System.out.println("----\n" + res); 40 | System.out.println("Invoke using " + (System.currentTimeMillis() - start) + "ms"); 41 | 42 | // sync 43 | start = System.currentTimeMillis(); 44 | msg.setData(getData(5)); 45 | res = client.syncTransport(DemoResponse.class, msg); 46 | System.out.println("----\n" + res); 47 | System.out.println("Invoke using " + (System.currentTimeMillis() - start) + "ms"); 48 | 49 | } 50 | 51 | private static byte[] getData(int userId) { 52 | DemoRequest.Builder req = DemoRequest.newBuilder(); 53 | req.setUserId(userId); 54 | byte[] data = req.build().toByteArray(); 55 | return data; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/server/PbrpcServerConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.server; 2 | 3 | import io.netty.channel.ChannelOption; 4 | 5 | /** 6 | * ClassName: PbrpcServerConfiguration
7 | * Function: 服务端配置 8 | * 9 | * @author Zhang Xu 10 | */ 11 | public class PbrpcServerConfiguration { 12 | 13 | /** 14 | * keep alive 15 | * 16 | * @see ChannelOption#SO_KEEPALIVE 17 | */ 18 | private boolean soKeepalive = true; 19 | 20 | /** 21 | * tcp nodelay 22 | * 23 | * @see ChannelOption#TCP_NODELAY 24 | */ 25 | private boolean tcpNodelay = true; 26 | 27 | /** 28 | * so linger 29 | * 30 | * @see ChannelOption#SO_LINGER 31 | */ 32 | private int soLinger = 2; 33 | 34 | /** 35 | * so backlog 36 | * 37 | * @see ChannelOption#SO_BACKLOG 38 | */ 39 | private int soBacklog = 128; 40 | 41 | /** 42 | * receive buf size 43 | * 44 | * @see ChannelOption#SO_RCVBUF 45 | */ 46 | private int soRcvbuf = 1024 * 64; 47 | 48 | /** 49 | * send buf size 50 | * 51 | * @see ChannelOption#SO_SNDBUF 52 | */ 53 | private int soSndbuf = 1024 * 64; 54 | 55 | public boolean isSoKeepalive() { 56 | return soKeepalive; 57 | } 58 | 59 | public void setSoKeepalive(boolean soKeepalive) { 60 | this.soKeepalive = soKeepalive; 61 | } 62 | 63 | public boolean isTcpNodelay() { 64 | return tcpNodelay; 65 | } 66 | 67 | public void setTcpNodelay(boolean tcpNodelay) { 68 | this.tcpNodelay = tcpNodelay; 69 | } 70 | 71 | public int getSoLinger() { 72 | return soLinger; 73 | } 74 | 75 | public void setSoLinger(int soLinger) { 76 | this.soLinger = soLinger; 77 | } 78 | 79 | public int getSoBacklog() { 80 | return soBacklog; 81 | } 82 | 83 | public void setSoBacklog(int soBacklog) { 84 | this.soBacklog = soBacklog; 85 | } 86 | 87 | public int getSoRcvbuf() { 88 | return soRcvbuf; 89 | } 90 | 91 | public void setSoRcvbuf(int soRcvbuf) { 92 | this.soRcvbuf = soRcvbuf; 93 | } 94 | 95 | public int getSoSndbuf() { 96 | return soSndbuf; 97 | } 98 | 99 | public void setSoSndbuf(int soSndbuf) { 100 | this.soSndbuf = soSndbuf; 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /navi-pbrpc-spring/src/test/java/com/baidu/beidou/navi/pbrpc/spring/SpringIntegrationIpPortStringHATest.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.spring; 2 | 3 | import static org.hamcrest.Matchers.is; 4 | import static org.junit.Assert.assertThat; 5 | import static org.junit.Assert.fail; 6 | 7 | import org.junit.AfterClass; 8 | import org.junit.BeforeClass; 9 | import org.junit.Test; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.test.context.ContextConfiguration; 12 | import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests; 13 | 14 | import com.baidu.beidou.navi.pbrpc.demo.proto.Demo; 15 | import com.baidu.beidou.navi.pbrpc.demo.service.DemoService; 16 | import com.baidu.beidou.navi.pbrpc.demo.service.impl.DemoServiceImpl; 17 | import com.baidu.beidou.navi.pbrpc.server.PbrpcServer; 18 | 19 | /** 20 | * @author zhangxu 21 | */ 22 | @ContextConfiguration(locations = {"classpath*:ipportstring_nagative/applicationContext.xml"}) 23 | public class SpringIntegrationIpPortStringHATest extends AbstractJUnit4SpringContextTests { 24 | 25 | @Autowired 26 | private DemoService demoService; 27 | 28 | @Test 29 | public void testDoSmth() { 30 | Demo.DemoRequest.Builder req = Demo.DemoRequest.newBuilder(); 31 | req.setUserId(1); 32 | Demo.DemoResponse response = demoService.doSmth(req.build()); 33 | System.out.println(response); 34 | assertThat(response.getUserId(), is(1)); 35 | } 36 | 37 | protected static PbrpcServer SERVER = null; 38 | protected static PbrpcServer SERVER_HA = null; 39 | 40 | protected static int PORT = 14419; 41 | protected static int PORT_HA = 14420; 42 | 43 | @BeforeClass 44 | public static void setUp() { 45 | System.out.println("Start server now..."); 46 | SERVER = new PbrpcServer(PORT); 47 | SERVER.register(100, new DemoServiceImpl()); 48 | SERVER.start(); 49 | 50 | SERVER_HA = new PbrpcServer(PORT_HA); 51 | SERVER_HA.register(100, new DemoServiceImpl()); 52 | SERVER_HA.start(); 53 | } 54 | 55 | @AfterClass 56 | public static void tearDown() { 57 | if (SERVER != null) { 58 | SERVER.shutdown(); 59 | } 60 | if (SERVER_HA != null) { 61 | SERVER_HA.shutdown(); 62 | } 63 | try { 64 | Thread.sleep(1000); 65 | } catch (Exception e) { 66 | // TODO: handle exception 67 | } 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/client/NsHeaderResolver.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.client; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.nio.ByteBuffer; 6 | 7 | import com.baidu.beidou.navi.pbrpc.protocol.Header; 8 | import com.baidu.beidou.navi.pbrpc.protocol.NsHead; 9 | import com.baidu.beidou.navi.pbrpc.transport.PbrpcMsg; 10 | import com.baidu.beidou.navi.pbrpc.util.ByteUtil; 11 | import com.baidu.beidou.navi.pbrpc.util.IdGenerator; 12 | 13 | /** 14 | * ClassName: NsHeaderResolver
15 | * Function: NsHead头解析构造器 16 | * 17 | * @author Zhang Xu 18 | */ 19 | public class NsHeaderResolver implements HeaderResolver { 20 | 21 | /** 22 | * @see com.baidu.beidou.navi.pbrpc.client.HeaderResolver#resolveResHeader(java.io.InputStream) 23 | */ 24 | @Override 25 | public Header resolveResHeader(InputStream in) throws IOException { 26 | NsHead nsHead = new NsHead(); 27 | byte[] nsHeadBytes = new byte[nsHead.getFixedHeaderLen()]; 28 | ByteUtil.read(nsHeadBytes, in); 29 | nsHead.wrap(nsHeadBytes); 30 | return nsHead; 31 | } 32 | 33 | /** 34 | * @see com.baidu.beidou.navi.pbrpc.client.HeaderResolver#resolveResBodyByResHeader(com.baidu.beidou.navi.pbrpc.protocol.Header, 35 | * java.io.InputStream) 36 | */ 37 | @Override 38 | public byte[] resolveResBodyByResHeader(Header header, InputStream in) throws IOException { 39 | byte[] bodyBytes = new byte[(int) header.getBodyLen()]; 40 | ByteUtil.read(bodyBytes, in); 41 | return bodyBytes; 42 | } 43 | 44 | /** 45 | * @see com.baidu.beidou.navi.pbrpc.client.HeaderResolver#packReqHeaderAndBody(com.baidu.beidou.navi.pbrpc.transport.PbrpcMsg) 46 | */ 47 | @Override 48 | public byte[] packReqHeaderAndBody(PbrpcMsg pbrpcMsg) throws IOException { 49 | NsHead nsHead = new NsHead(); 50 | nsHead.setLogId(IdGenerator.genUUID()); 51 | nsHead.setMethodId(pbrpcMsg.getServiceId()); 52 | nsHead.setProvider(pbrpcMsg.getProvider()); 53 | nsHead.setBodyLen(pbrpcMsg.getData().length); 54 | byte[] headerBytes = nsHead.toBytes(); 55 | 56 | ByteBuffer buffer = ByteBuffer.allocate(nsHead.getFixedHeaderLen() 57 | + pbrpcMsg.getData().length); 58 | buffer.put(headerBytes).put(pbrpcMsg.getData()); 59 | buffer.flip(); 60 | 61 | byte[] packet = new byte[buffer.remaining()]; 62 | buffer.get(packet); 63 | 64 | return packet; 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/server/core/ServiceDescriptor.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.server.core; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | /** 6 | * ClassName: ServiceDescriptor
7 | * Function: 一个暴露的rpc服务的描述 8 | * 9 | * @author Zhang Xu 10 | */ 11 | public class ServiceDescriptor { 12 | 13 | /** 14 | * 服务的id,唯一标示 15 | */ 16 | private KEY serviceId; 17 | 18 | /** 19 | * 服务缓存的method 20 | */ 21 | private Method method; 22 | 23 | /** 24 | * 服务具体的实现bean对象 25 | */ 26 | private Object target; 27 | 28 | /** 29 | * 服务输入参数对象 30 | */ 31 | private Class argumentClass; 32 | 33 | /** 34 | * 服务输出参数对象 35 | */ 36 | private Class returnClass; 37 | 38 | /** 39 | * @see java.lang.Object#toString() 40 | */ 41 | @Override 42 | public String toString() { 43 | StringBuilder sb = new StringBuilder(); 44 | sb.append("ServiceId="); 45 | sb.append(serviceId); 46 | sb.append(", "); 47 | sb.append(returnClass.getSimpleName()); 48 | sb.append(" "); 49 | sb.append(target.getClass().getSimpleName()); 50 | sb.append("."); 51 | sb.append(method.getName()); 52 | sb.append("("); 53 | sb.append(argumentClass.getClass().getSimpleName()); 54 | sb.append(")"); 55 | return sb.toString(); 56 | } 57 | 58 | public KEY getServiceId() { 59 | return serviceId; 60 | } 61 | 62 | public ServiceDescriptor setServiceId(KEY serviceId) { 63 | this.serviceId = serviceId; 64 | return this; 65 | } 66 | 67 | public Method getMethod() { 68 | return method; 69 | } 70 | 71 | public ServiceDescriptor setMethod(Method method) { 72 | this.method = method; 73 | return this; 74 | } 75 | 76 | public Object getTarget() { 77 | return target; 78 | } 79 | 80 | public ServiceDescriptor setTarget(Object target) { 81 | this.target = target; 82 | return this; 83 | } 84 | 85 | public Class getArgumentClass() { 86 | return argumentClass; 87 | } 88 | 89 | public ServiceDescriptor setArgumentClass(Class argumentClass) { 90 | this.argumentClass = argumentClass; 91 | return this; 92 | } 93 | 94 | public Class getReturnClass() { 95 | return returnClass; 96 | } 97 | 98 | public ServiceDescriptor setReturnClass(Class returnClass) { 99 | this.returnClass = returnClass; 100 | return this; 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/util/ContextHolder.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.util; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * ClassName: ContextHolder
8 | * Function: 线程执行上下文,封装threadlocal 9 | * 10 | * @author Zhang Xu 11 | */ 12 | public class ContextHolder { 13 | 14 | /** 15 | * 线程上下文变量的持有者 16 | */ 17 | private static final ThreadLocal> CTX_HOLDER = new ThreadLocal>(); 18 | 19 | /** 20 | * 添加内容到线程上下文中 21 | * 22 | * @param key 23 | * @param value 24 | */ 25 | public static final void putContext(String key, Object value) { 26 | Map ctx = CTX_HOLDER.get(); 27 | if (ctx == null) { 28 | ctx = new HashMap(); 29 | CTX_HOLDER.set(ctx); 30 | } 31 | ctx.put(key, value); 32 | } 33 | 34 | /** 35 | * 从线程上下文中获取内容 36 | * 37 | * @param key 38 | */ 39 | @SuppressWarnings("unchecked") 40 | public static final T getContext(String key) { 41 | Map ctx = CTX_HOLDER.get(); 42 | if (ctx == null) { 43 | return null; 44 | } 45 | return (T) ctx.get(key); 46 | } 47 | 48 | /** 49 | * 获取线程上下文 50 | * 51 | * @param key 52 | */ 53 | public static final Map getContext() { 54 | Map ctx = CTX_HOLDER.get(); 55 | if (ctx == null) { 56 | return null; 57 | } 58 | return ctx; 59 | } 60 | 61 | /** 62 | * 删除上下文中的key 63 | * 64 | * @param key 65 | */ 66 | public static final void remove(String key) { 67 | Map ctx = CTX_HOLDER.get(); 68 | if (ctx != null) { 69 | ctx.remove(key); 70 | } 71 | } 72 | 73 | /** 74 | * 上下文中是否包含此key 75 | * 76 | * @param key 77 | * @return 78 | */ 79 | public static final boolean contains(String key) { 80 | Map ctx = CTX_HOLDER.get(); 81 | if (ctx != null) { 82 | return ctx.containsKey(key); 83 | } 84 | return false; 85 | } 86 | 87 | /** 88 | * 清空线程上下文 89 | */ 90 | public static final void clean() { 91 | CTX_HOLDER.set(null); 92 | } 93 | 94 | /** 95 | * 初始化线程上下文 96 | */ 97 | public static final void init() { 98 | CTX_HOLDER.set(new HashMap()); 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/server/core/ServiceRegistry.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.server.core; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import com.baidu.beidou.navi.pbrpc.util.Preconditions; 10 | 11 | /** 12 | * ClassName: ServiceRegistry
13 | * Function: 服务注册对象,常驻内存的缓存,使用单例访问,缓存了服务的描述
14 | * 泛型KEY为服务的唯一标示 15 | * 16 | * @author Zhang Xu 17 | */ 18 | @SuppressWarnings("rawtypes") 19 | public class ServiceRegistry { 20 | 21 | private static final Logger LOG = LoggerFactory.getLogger(ServiceRegistry.class); 22 | 23 | /** 24 | * 服务注册的字典
25 | * 键为服务标示KEY,值为服务具体描述 26 | * 27 | * @see ServiceDescriptor 28 | */ 29 | private Map> serviceDescriptors; 30 | 31 | /** 32 | * 注册单例引用 33 | */ 34 | private static ServiceRegistry instance; 35 | 36 | /** 37 | * 获取服务注册对象 38 | * 39 | * @return 40 | */ 41 | @SuppressWarnings("unchecked") 42 | public static ServiceRegistry getInstance() { 43 | if (instance == null) { 44 | synchronized (ServiceRegistry.class) { 45 | if (instance == null) { 46 | instance = new ServiceRegistry(); 47 | } 48 | } 49 | } 50 | return instance; 51 | } 52 | 53 | /** 54 | * Creates a new instance of ServiceRegistry. 55 | */ 56 | private ServiceRegistry() { 57 | serviceDescriptors = new HashMap>(); 58 | } 59 | 60 | /** 61 | * 根据标示KEY获取服务描述 62 | * 63 | * @param key 64 | * 服务的唯一标示 65 | * @return 服务描述 66 | * @throws IllegalStateException 67 | */ 68 | public ServiceDescriptor getServiceDescriptorByKey(KEY key) throws IllegalStateException { 69 | Preconditions.checkNotNull(key, "Key cannot be null"); 70 | Preconditions.checkState(instance != null, "ServiceRegistry not init yet"); 71 | return serviceDescriptors.get(key); 72 | } 73 | 74 | /** 75 | * 加入服务描述 76 | * 77 | * @param key 78 | * 服务的唯一标示 79 | * @param serviceDescriptor 80 | * 服务描述 81 | */ 82 | public void addServiceDescriptor(KEY key, ServiceDescriptor serviceDescriptor) { 83 | Preconditions.checkNotNull(key, "Key cannot be null"); 84 | Preconditions.checkState(instance != null, "ServiceRegistry not init yet"); 85 | if (serviceDescriptors.containsKey(key)) { 86 | LOG.warn("Key=" + key + " will be override with " + serviceDescriptor); 87 | } 88 | this.serviceDescriptors.put(key, serviceDescriptor); 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/transport/PbrpcMessageSerializer.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.transport; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.buffer.Unpooled; 5 | import io.netty.channel.ChannelHandlerContext; 6 | import io.netty.handler.codec.MessageToMessageEncoder; 7 | 8 | import java.util.List; 9 | 10 | import com.baidu.beidou.navi.pbrpc.error.ErrorCode; 11 | import com.baidu.beidou.navi.pbrpc.protocol.NsHead; 12 | import com.baidu.beidou.navi.pbrpc.util.ByteUtil; 13 | import com.baidu.beidou.navi.pbrpc.util.IdGenerator; 14 | import com.baidu.beidou.navi.pbrpc.util.StringPool; 15 | 16 | /** 17 | * ClassName: PbrpcMessageSerializer
18 | * Function: 序列化的Handler 19 | * 20 | * @author Zhang Xu 21 | */ 22 | public class PbrpcMessageSerializer extends MessageToMessageEncoder { 23 | 24 | // private static final Logger LOG = LoggerFactory.getLogger(PbrpcMessageSerializer.class); 25 | 26 | /** 27 | * @see io.netty.handler.codec.MessageToMessageEncoder#encode(io.netty.channel.ChannelHandlerContext, 28 | * java.lang.Object, java.util.List) 29 | */ 30 | @Override 31 | protected void encode(ChannelHandlerContext ctx, PbrpcMsg pbrpcMsg, List out) 32 | throws Exception { 33 | byte[] bodyBytes = ByteUtil.getNonEmptyBytes(pbrpcMsg.getData()); 34 | NsHead nsHead = contructNsHead(pbrpcMsg.getServiceId(), pbrpcMsg.getErrorCode(), 35 | pbrpcMsg.getLogId(), pbrpcMsg.getData(), pbrpcMsg.getProvider()); 36 | byte[] nsHeadBytes = nsHead.toBytes(); 37 | ByteBuf encoded = Unpooled.copiedBuffer(nsHeadBytes, bodyBytes); 38 | out.add(encoded); 39 | // LOG.info("Send total byte size=" + (nsHeadBytes.length + bodyBytes.length) + ", body size=" 40 | // + bodyBytes.length); 41 | } 42 | 43 | /** 44 | * 构建NsHead 45 | * 46 | * @param serviceId 47 | * @param errorCode 48 | * @param logId 49 | * @param data 50 | * @param provider 51 | * @return NsHead 52 | */ 53 | private NsHead contructNsHead(int serviceId, ErrorCode errorCode, long logId, byte[] data, 54 | String provider) { 55 | NsHead nsHead = new NsHead(); 56 | nsHead.setMethodId(serviceId); 57 | if (logId != 0L) { 58 | nsHead.setLogId(logId); 59 | } else { 60 | nsHead.setLogId(IdGenerator.genUUID()); 61 | } 62 | if (errorCode != null) { 63 | nsHead.setFlags(errorCode.getValue()); 64 | } 65 | if (data != null) { 66 | nsHead.setBodyLen(data.length); 67 | } else { 68 | nsHead.setBodyLen(0); 69 | } 70 | if (provider == null) { 71 | nsHead.setProvider(StringPool.Symbol.EMPTY); 72 | } else { 73 | nsHead.setProvider(provider); 74 | } 75 | return nsHead; 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /navi-pbrpc-spring/src/test/java/com/baidu/beidou/navi/pbrpc/spring/SpringIntegrationIpPortStringTest.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.spring; 2 | 3 | import static org.hamcrest.Matchers.is; 4 | import static org.junit.Assert.assertThat; 5 | import static org.junit.Assert.fail; 6 | 7 | import org.junit.AfterClass; 8 | import org.junit.BeforeClass; 9 | import org.junit.Test; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.test.context.ContextConfiguration; 12 | import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests; 13 | 14 | import com.baidu.beidou.navi.pbrpc.demo.proto.Demo; 15 | import com.baidu.beidou.navi.pbrpc.demo.service.DemoService; 16 | import com.baidu.beidou.navi.pbrpc.demo.service.impl.DemoServiceImpl; 17 | import com.baidu.beidou.navi.pbrpc.server.PbrpcServer; 18 | 19 | /** 20 | * @author zhangxu 21 | */ 22 | @ContextConfiguration(locations = {"classpath*:ipportstring/applicationContext.xml"}) 23 | public class SpringIntegrationIpPortStringTest extends AbstractJUnit4SpringContextTests { 24 | 25 | @Autowired 26 | private DemoService demoService; 27 | 28 | @Test 29 | public void testDoSmth() { 30 | Demo.DemoRequest.Builder req = Demo.DemoRequest.newBuilder(); 31 | req.setUserId(1); 32 | Demo.DemoResponse response = demoService.doSmth(req.build()); 33 | System.out.println(response); 34 | assertThat(response.getUserId(), is(1)); 35 | } 36 | 37 | @Test 38 | public void testDoSmthTimeout() { 39 | try { 40 | Demo.DemoRequest.Builder req = Demo.DemoRequest.newBuilder(); 41 | req.setUserId(1); 42 | Demo.DemoResponse response = demoService.doSmthTimeout(req.build()); 43 | System.out.println(response); 44 | } catch (Exception e) { 45 | assertThat(e.getClass().getSimpleName(), is("HAPbrpcException")); 46 | assertThat(e.getCause().getMessage(), is("java.io.IOException: Read timed out")); 47 | return; 48 | } 49 | fail(); 50 | } 51 | 52 | protected static PbrpcServer SERVER = null; 53 | protected static PbrpcServer SERVER_HA = null; 54 | 55 | protected static int PORT = 14419; 56 | protected static int PORT_HA = 14420; 57 | 58 | @BeforeClass 59 | public static void setUp() { 60 | System.out.println("Start server now..."); 61 | SERVER = new PbrpcServer(PORT); 62 | SERVER.register(100, new DemoServiceImpl()); 63 | SERVER.start(); 64 | 65 | SERVER_HA = new PbrpcServer(PORT_HA); 66 | SERVER_HA.register(100, new DemoServiceImpl()); 67 | SERVER_HA.start(); 68 | } 69 | 70 | @AfterClass 71 | public static void tearDown() { 72 | if (SERVER != null) { 73 | SERVER.shutdown(); 74 | } 75 | if (SERVER_HA != null) { 76 | SERVER_HA.shutdown(); 77 | } 78 | try { 79 | Thread.sleep(1000); 80 | } catch (Exception e) { 81 | // TODO: handle exception 82 | } 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/client/callback/CallbackContext.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.client.callback; 2 | 3 | import io.netty.channel.Channel; 4 | 5 | import com.google.protobuf.GeneratedMessage; 6 | 7 | /** 8 | * ClassName: CallbackContext
9 | * Function: 回调上下文,用于定位回调,计算超时、关闭channel等辅助功能 10 | * 11 | * @author Zhang Xu 12 | */ 13 | public class CallbackContext { 14 | 15 | /** 16 | * 用于标示某个回调的id,用NsHead头中的logId来标示 17 | */ 18 | private final int logId; 19 | 20 | /** 21 | * 调用起始时间 22 | */ 23 | private final long startTime; 24 | 25 | /** 26 | * 客户端调用是否为短连接 27 | */ 28 | private boolean isShortAliveConn; 29 | 30 | /** 31 | * 客户端调用用的channel,如果是长连接可以为空,只有配合{@link #isShortAliveConn}为true时候,才会再回调中关闭 32 | */ 33 | private Channel channel; 34 | 35 | /** 36 | * 调用结束时间 37 | */ 38 | private final int timeout; 39 | 40 | /** 41 | * 期望服务返回的pb类型 42 | */ 43 | private final Class resClazz; 44 | 45 | /** 46 | * 回调 47 | */ 48 | private final Callback callback; 49 | 50 | /** 51 | * Creates a new instance of CallbackContext. 52 | * 53 | * @param logId 54 | * @param startTime 55 | * @param timeout 56 | * @param isShortAliveConn 57 | * @param channel 58 | * @param resClazz 59 | * @param callback 60 | */ 61 | public CallbackContext(int logId, long startTime, int timeout, boolean isShortAliveConn, 62 | Channel channel, Class resClazz, 63 | Callback callback) { 64 | super(); 65 | this.logId = logId; 66 | this.startTime = startTime; 67 | this.timeout = timeout; 68 | this.isShortAliveConn = isShortAliveConn; 69 | this.channel = channel; 70 | this.resClazz = resClazz; 71 | this.callback = callback; 72 | } 73 | 74 | public long getStartTime() { 75 | return startTime; 76 | } 77 | 78 | public int getTimeout() { 79 | return timeout; 80 | } 81 | 82 | public int getLogId() { 83 | return logId; 84 | } 85 | 86 | public Class getResClazz() { 87 | return resClazz; 88 | } 89 | 90 | public Callback getCallback() { 91 | return callback; 92 | } 93 | 94 | public boolean isShortAliveConn() { 95 | return isShortAliveConn; 96 | } 97 | 98 | public void setShortAliveConn(boolean isShortAliveConn) { 99 | this.isShortAliveConn = isShortAliveConn; 100 | } 101 | 102 | public Channel getChannel() { 103 | return channel; 104 | } 105 | 106 | public void setChannel(Channel channel) { 107 | this.channel = channel; 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /navi-pbrpc-spring/src/test/java/com/baidu/beidou/navi/pbrpc/spring/SpringIntegrationIpPortListTest.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.spring; 2 | 3 | import static org.hamcrest.Matchers.is; 4 | import static org.junit.Assert.assertThat; 5 | import static org.junit.Assert.fail; 6 | 7 | import org.junit.AfterClass; 8 | import org.junit.BeforeClass; 9 | import org.junit.Test; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.test.context.ContextConfiguration; 12 | import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests; 13 | 14 | import com.baidu.beidou.navi.pbrpc.client.PbrpcClient; 15 | import com.baidu.beidou.navi.pbrpc.demo.proto.Demo; 16 | import com.baidu.beidou.navi.pbrpc.demo.service.DemoService; 17 | import com.baidu.beidou.navi.pbrpc.demo.service.impl.DemoServiceImpl; 18 | import com.baidu.beidou.navi.pbrpc.server.PbrpcServer; 19 | import com.baidu.beidou.navi.pbrpc.util.PbrpcConstants; 20 | 21 | /** 22 | * @author zhangxu 23 | */ 24 | @ContextConfiguration(locations = {"classpath*:ipportlist/applicationContext.xml"}) 25 | public class SpringIntegrationIpPortListTest extends AbstractJUnit4SpringContextTests { 26 | 27 | @Autowired 28 | private DemoService demoService; 29 | 30 | @Test 31 | public void testDoSmth() { 32 | Demo.DemoRequest.Builder req = Demo.DemoRequest.newBuilder(); 33 | req.setUserId(1); 34 | Demo.DemoResponse response = demoService.doSmth(req.build()); 35 | System.out.println(response); 36 | assertThat(response.getUserId(), is(1)); 37 | } 38 | 39 | @Test 40 | public void testDoSmthTimeout() { 41 | try { 42 | Demo.DemoRequest.Builder req = Demo.DemoRequest.newBuilder(); 43 | req.setUserId(1); 44 | Demo.DemoResponse response = demoService.doSmthTimeout(req.build()); 45 | System.out.println(response); 46 | } catch (Exception e) { 47 | assertThat(e.getClass().getSimpleName(), is("HAPbrpcException")); 48 | assertThat(e.getCause().getMessage(), is("java.io.IOException: Read timed out")); 49 | return; 50 | } 51 | fail(); 52 | } 53 | 54 | protected static PbrpcServer SERVER = null; 55 | protected static PbrpcServer SERVER_HA = null; 56 | 57 | protected static int PORT = 14419; 58 | protected static int PORT_HA = 14420; 59 | 60 | @BeforeClass 61 | public static void setUp() { 62 | System.out.println("Start server now..."); 63 | SERVER = new PbrpcServer(PORT); 64 | SERVER.register(100, new DemoServiceImpl()); 65 | SERVER.start(); 66 | 67 | SERVER_HA = new PbrpcServer(PORT_HA); 68 | SERVER_HA.register(100, new DemoServiceImpl()); 69 | SERVER_HA.start(); 70 | } 71 | 72 | @AfterClass 73 | public static void tearDown() { 74 | if (SERVER != null) { 75 | SERVER.shutdown(); 76 | } 77 | if (SERVER_HA != null) { 78 | SERVER_HA.shutdown(); 79 | } 80 | try { 81 | Thread.sleep(1000); 82 | } catch (Exception e) { 83 | // TODO: handle exception 84 | } 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/client/TimeoutEvictor.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.client; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.TimerTask; 6 | import java.util.concurrent.ConcurrentMap; 7 | 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | import com.baidu.beidou.navi.pbrpc.client.callback.CallbackContext; 12 | import com.baidu.beidou.navi.pbrpc.client.callback.CallbackPool; 13 | import com.baidu.beidou.navi.pbrpc.exception.TimeoutException; 14 | 15 | /** 16 | * ClassName: TimeoutEvictor
17 | * Function: 检测连接超时的客户端,回调抛出异常{@link com.baidu.beidou.navi.pbrpc.exception.TimeoutException} 18 | * 19 | * @author Zhang Xu 20 | */ 21 | public class TimeoutEvictor extends TimerTask { 22 | 23 | private static final Logger LOG = LoggerFactory.getLogger(TimeoutEvictor.class); 24 | 25 | /** 26 | * 运行超时检测器 27 | * 28 | * @see java.util.TimerTask#run() 29 | */ 30 | @Override 31 | public void run() { 32 | try { 33 | detectTimetout(); 34 | } catch (Exception e) { 35 | // ignored 36 | } 37 | } 38 | 39 | /** 40 | * 检测超时 41 | */ 42 | @SuppressWarnings("unused") 43 | private synchronized void detectTimetout() { 44 | long start = System.nanoTime(); 45 | try { 46 | int totalScanned = 0; 47 | int totalTimeouted = 0; 48 | ConcurrentMap map = CallbackPool.getCALLBACK_MAP(); 49 | if (map != null && !map.isEmpty()) { 50 | List list = new ArrayList(map.values()); 51 | for (CallbackContext cc : list) { 52 | if (System.currentTimeMillis() - cc.getStartTime() > cc.getTimeout()) { 53 | cc.getCallback().handleError( 54 | new TimeoutException("Client call timeout, request logId=" 55 | + cc.getLogId())); 56 | CallbackContext context = CallbackPool.getContext(cc.getLogId()); 57 | if (context != null && context.isShortAliveConn()) { 58 | if (context.getChannel() != null) { 59 | LOG.info(String.format("Close channel %s, logId=%s", 60 | context.getChannel(), context.getLogId())); 61 | context.getChannel().close(); 62 | } 63 | } 64 | CallbackPool.remove(cc.getLogId()); 65 | totalTimeouted++; 66 | } 67 | } 68 | totalScanned = list.size(); 69 | } 70 | // LOG.info("Detecting timeout done using " + (System.nanoTime() - start) / 1000 71 | // + "us, totalScanned=" + totalScanned + " ,totalTimeouted=" + totalTimeouted); 72 | } catch (Exception e) { 73 | LOG.warn("Exception occurred when detecting timeout callbacks", e); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/client/PbrpcClientChannel.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.client; 2 | 3 | import io.netty.channel.ChannelFuture; 4 | 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import com.baidu.beidou.navi.pbrpc.client.callback.CallFuture; 9 | import com.baidu.beidou.navi.pbrpc.client.callback.CallbackPool; 10 | import com.baidu.beidou.navi.pbrpc.exception.client.PbrpcException; 11 | import com.baidu.beidou.navi.pbrpc.transport.PbrpcMsg; 12 | import com.baidu.beidou.navi.pbrpc.util.IdGenerator; 13 | import com.google.protobuf.GeneratedMessage; 14 | 15 | /** 16 | * ClassName: PbrpcClientChannel
17 | * Function: 客户端连接池内的对象封装 18 | * 19 | * @author Zhang Xu 20 | */ 21 | public class PbrpcClientChannel { 22 | 23 | private static final Logger LOG = LoggerFactory.getLogger(PbrpcClientChannel.class); 24 | 25 | /** 26 | * netty连接channel的future引用 27 | */ 28 | private ChannelFuture channelFuture; 29 | 30 | /** 31 | * 异步调用 32 | * 33 | * @param responseClazz 34 | * @param pbrpcMsg 35 | * @param readTimeout 36 | * 客户端调用超时时间 37 | * @return 38 | * @throws Exception 39 | */ 40 | public CallFuture asyncTransport(Class responseClazz, 41 | PbrpcMsg pbrpcMsg, int readTimeout) throws Exception { 42 | if (channelFuture != null) { 43 | try { 44 | int uuid = IdGenerator.genUUID(); 45 | pbrpcMsg.setLogId(uuid); 46 | CallFuture future = CallFuture.newInstance(); 47 | CallbackPool.put(uuid, readTimeout, false, null, responseClazz, future); 48 | // long start = System.currentTimeMillis(); 49 | channelFuture.channel().writeAndFlush(pbrpcMsg); 50 | // LOG.info("Send message " + pbrpcMsg + " done using " + (System.currentTimeMillis() - start) + "ms"); 51 | return future; 52 | } catch (Exception e) { 53 | LOG.error( 54 | "Failed to transport to " + channelFuture.channel() + " due to " 55 | + e.getMessage(), e); 56 | throw new PbrpcException(e); 57 | } 58 | } else { 59 | LOG.error("Socket channel is not well established, so failed to transport"); 60 | throw new PbrpcException( 61 | "ChannelFuture is null! Socket channel is not well established, so failed to transport"); 62 | } 63 | 64 | } 65 | 66 | /** 67 | * 同步调用 68 | * 69 | * @param responseClazz 70 | * @param pbrpcMsg 71 | * @param readTimeout 72 | * 客户端调用超时时间 73 | * @return 74 | * @throws Exception 75 | */ 76 | public T syncTransport(Class responseClazz, PbrpcMsg pbrpcMsg, 77 | int readTimeout) throws Exception { 78 | return asyncTransport(responseClazz, pbrpcMsg, readTimeout).get(); 79 | } 80 | 81 | public ChannelFuture getChannelFuture() { 82 | return channelFuture; 83 | } 84 | 85 | public void setChannelFuture(ChannelFuture channelFuture) { 86 | this.channelFuture = channelFuture; 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/client/PbrpcClientChannelFactory.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.client; 2 | 3 | import io.netty.channel.Channel; 4 | import io.netty.channel.ChannelFuture; 5 | 6 | import org.apache.commons.pool.BasePoolableObjectFactory; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | /** 11 | * ClassName: ClientConnectionFactory
12 | * Function: 连接池对象构造工厂 13 | * 14 | * @author Zhang Xu 15 | */ 16 | public class PbrpcClientChannelFactory extends BasePoolableObjectFactory { 17 | 18 | private static final Logger LOG = LoggerFactory.getLogger(PbrpcClientChannelFactory.class); 19 | 20 | /** 21 | * pbrpc客户端连接 22 | */ 23 | private PbrpcClient pbrpcClient; 24 | 25 | /** 26 | * Creates a new instance of ClientConnectionFactory. 27 | * 28 | * @param clientConfig 29 | * @param ip 30 | * @param port 31 | * @param connTimeout 32 | * @param readTimeout 33 | */ 34 | public PbrpcClientChannelFactory(PbrpcClientConfiguration clientConfig, String ip, int port, 35 | int connTimeout, int readTimeout) { 36 | pbrpcClient = new SimplePbrpcClient(clientConfig, false, ip, port, connTimeout, readTimeout); 37 | } 38 | 39 | /** 40 | * @see org.apache.commons.pool.BasePoolableObjectFactory#makeObject() 41 | */ 42 | public Object makeObject() throws Exception { 43 | PbrpcClientChannel ch = new PbrpcClientChannel(); 44 | 45 | ChannelFuture future = pbrpcClient.connect(); 46 | 47 | future.awaitUninterruptibly(); 48 | if (!future.isSuccess()) { 49 | LOG.warn("Making new connection on " + pbrpcClient.getInfo() + " not success", 50 | future.cause()); 51 | } 52 | 53 | LOG.info("Making new connection on " + pbrpcClient.getInfo() + " and adding to pool done"); 54 | ch.setChannelFuture(future); 55 | 56 | return ch; 57 | } 58 | 59 | /** 60 | * @see org.apache.commons.pool.BasePoolableObjectFactory#destroyObject(java.lang.Object) 61 | */ 62 | public void destroyObject(final Object obj) throws Exception { 63 | if (obj instanceof PbrpcClientChannel) { 64 | final PbrpcClientChannel ch = (PbrpcClientChannel) obj; 65 | Channel channel = ch.getChannelFuture().channel(); 66 | if (channel.isOpen() && channel.isActive()) { 67 | channel.close(); 68 | } 69 | LOG.info("Closing channel and destroy connection from pool done"); 70 | } 71 | } 72 | 73 | /** 74 | * @see org.apache.commons.pool.BasePoolableObjectFactory#validateObject(java.lang.Object) 75 | */ 76 | public boolean validateObject(Object obj) { 77 | if (obj instanceof PbrpcClientChannel) { 78 | final PbrpcClientChannel ch = (PbrpcClientChannel) obj; 79 | Channel channel = ch.getChannelFuture().channel(); 80 | return channel.isOpen() && channel.isActive(); 81 | } 82 | return false; 83 | } 84 | 85 | public PbrpcClient getPbrpcClient() { 86 | return pbrpcClient; 87 | } 88 | 89 | public void setPbrpcClient(PbrpcClient pbrpcClient) { 90 | this.pbrpcClient = pbrpcClient; 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/codec/impl/ProtobufCodec.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.codec.impl; 2 | 3 | import java.lang.reflect.Method; 4 | import java.util.concurrent.Callable; 5 | 6 | import com.baidu.beidou.navi.pbrpc.codec.Codec; 7 | import com.baidu.beidou.navi.pbrpc.exception.CodecException; 8 | import com.baidu.beidou.navi.pbrpc.util.Computable; 9 | import com.baidu.beidou.navi.pbrpc.util.ConcurrentCache; 10 | import com.google.protobuf.GeneratedMessage; 11 | 12 | /** 13 | * ClassName: ProtobufCodec
14 | * Function: protobuf序列化器,利用反射缓存method来进行调用 15 | * 16 | * @author Zhang Xu 17 | */ 18 | public class ProtobufCodec implements Codec { 19 | 20 | /** 21 | * Protobuf生成原生Java代码中的方法解码方法名称 22 | */ 23 | private static final String METHOD_NAME_PARSEFROM = "parseFrom"; 24 | 25 | /** 26 | * Protobuf生成原生Java代码中的方法编码方法名称 27 | */ 28 | private static final String METHOD_NAME_TOBYTE = "toByteArray"; 29 | 30 | /** 31 | * 方法缓存,用于Protobuf生成原生Java代码中的某些编解码方法。 缓存的方法包括: 32 | *

33 | *

    34 | *
  • parseFrom(byte[] bytes)
  • 35 | *
  • toByteArray()
  • 36 | *
37 | * 38 | * @see com.baidu.beidou.navi.pbrpc.util.ConcurrentCache 39 | * @see com.baidu.beidou.navi.pbrpc.util.Computable 40 | */ 41 | private static final Computable PROTOBUF_METHOD_CACHE = new ConcurrentCache(); 42 | 43 | /** 44 | * @see com.baidu.beidou.navi.pbrpc.codec.Codec#decode(java.lang.Class, byte[]) 45 | */ 46 | @Override 47 | public Object decode(final Class clazz, byte[] data) throws CodecException { 48 | try { 49 | if (data == null || data.length == 0) { 50 | return null; 51 | } 52 | Method m = PROTOBUF_METHOD_CACHE.get(clazz.getName() + METHOD_NAME_PARSEFROM, 53 | new Callable() { 54 | @Override 55 | public Method call() throws Exception { 56 | return clazz.getMethod(METHOD_NAME_PARSEFROM, byte[].class); 57 | } 58 | }); 59 | GeneratedMessage msg = (GeneratedMessage) m.invoke(clazz, data); 60 | return msg; 61 | } catch (Exception e) { 62 | throw new CodecException("Decode failed due to " + e.getMessage(), e); 63 | } 64 | } 65 | 66 | /** 67 | * @see com.baidu.beidou.navi.pbrpc.codec.Codec#encode(java.lang.Class, java.lang.Object) 68 | */ 69 | @Override 70 | public byte[] encode(final Class clazz, Object object) throws CodecException { 71 | try { 72 | Method m = PROTOBUF_METHOD_CACHE.get(clazz.getName() + METHOD_NAME_TOBYTE, 73 | new Callable() { 74 | @Override 75 | public Method call() throws Exception { 76 | return clazz.getMethod(METHOD_NAME_TOBYTE); 77 | } 78 | }); 79 | byte[] data = (byte[]) m.invoke(object); 80 | return data; 81 | } catch (Exception e) { 82 | throw new CodecException("Encode failed due to " + e.getMessage(), e); 83 | } 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/test/java/com/baidu/beidou/navi/pbrpc/client/BlockingIOPooledPbrpcClientMainTest.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.client; 2 | 3 | import java.util.Random; 4 | import java.util.concurrent.Callable; 5 | import java.util.concurrent.CompletionService; 6 | import java.util.concurrent.ExecutorCompletionService; 7 | import java.util.concurrent.ExecutorService; 8 | import java.util.concurrent.Executors; 9 | 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | import com.baidu.beidou.navi.pbrpc.demo.proto.Demo; 14 | import com.baidu.beidou.navi.pbrpc.demo.proto.Demo.DemoRequest; 15 | import com.baidu.beidou.navi.pbrpc.demo.proto.Demo.DemoResponse; 16 | import com.baidu.beidou.navi.pbrpc.transport.PbrpcMsg; 17 | 18 | public class BlockingIOPooledPbrpcClientMainTest { 19 | 20 | private static final Logger LOG = LoggerFactory.getLogger(PooledPbrpcClientMainTest.class); 21 | 22 | public static void main(String[] args) throws Exception { 23 | BlockingIOPooledPbrpcClientMainTest test = new BlockingIOPooledPbrpcClientMainTest(); 24 | test.testPool(); 25 | // test.testPoolBatch(); 26 | } 27 | 28 | public void testPool() throws Exception { 29 | PbrpcClient client = PbrpcClientFactory.buildPooledConnection(new PooledConfiguration(), 30 | "127.0.0.1", 8088, 4000); 31 | 32 | PbrpcMsg msg; 33 | msg = new PbrpcMsg(); 34 | msg.setServiceId(100); 35 | msg.setProvider("beidou"); 36 | msg.setData(getData(1)); 37 | DemoResponse res = client.asyncTransport(DemoResponse.class, msg).get(); 38 | System.out.println(res); 39 | 40 | int multiSize = 12; 41 | int totalRequestSize = 100000; 42 | ExecutorService pool = Executors.newFixedThreadPool(multiSize); 43 | CompletionService completionService = new ExecutorCompletionService( 44 | pool); 45 | 46 | Invoker invoker = new Invoker(client); 47 | long time = System.currentTimeMillis(); 48 | for (int i = 0; i < totalRequestSize; i++) { 49 | completionService.submit(invoker); 50 | } 51 | 52 | for (int i = 0; i < totalRequestSize; i++) { 53 | completionService.take().get(); 54 | } 55 | 56 | long timetook = System.currentTimeMillis() - time; 57 | LOG.info("Total using " + timetook + "ms"); 58 | LOG.info("QPS:" + 1000f / ((timetook) / (1.0f * totalRequestSize))); 59 | } 60 | 61 | private static byte[] getData(int userId) { 62 | DemoRequest.Builder req = DemoRequest.newBuilder(); 63 | req.setUserId(userId); 64 | byte[] data = req.build().toByteArray(); 65 | return data; 66 | } 67 | 68 | private class Invoker implements Callable { 69 | 70 | private PbrpcClient client; 71 | 72 | public Invoker(PbrpcClient client) { 73 | this.client = client; 74 | } 75 | 76 | @Override 77 | public DemoResponse call() throws Exception { 78 | PbrpcMsg msg; 79 | msg = new PbrpcMsg(); 80 | msg.setServiceId(100); 81 | msg.setProvider("beidou"); 82 | msg.setData(getData(1)); 83 | DemoResponse res = client.asyncTransport(DemoResponse.class, msg).get(); 84 | return res; 85 | } 86 | 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /navi-pbrpc-spring/src/test/resources/ipportstring/applicationContext.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 18 | 19 | 20 | 21 | 22 | 23 | classpath:ipportstring/application.properties 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 39 | 40 | 41 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | com.baidu.beidou.navi.pbrpc.demo.service.DemoService 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/server/core/impl/IdKeyServiceLocator.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.server.core.impl; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import com.baidu.beidou.navi.pbrpc.server.core.MethodResolver; 9 | import com.baidu.beidou.navi.pbrpc.server.core.ServiceDescriptor; 10 | import com.baidu.beidou.navi.pbrpc.server.core.ServiceLocator; 11 | import com.baidu.beidou.navi.pbrpc.server.core.ServiceRegistry; 12 | import com.baidu.beidou.navi.pbrpc.util.Preconditions; 13 | import com.baidu.beidou.navi.pbrpc.util.ReflectionUtil; 14 | 15 | /** 16 | * ClassName: IdKeyServiceLocator
17 | * Function: 利用methodId或者也可以叫做serviceId来做服务标示的定位器 18 | * 19 | * @author Zhang Xu 20 | */ 21 | public class IdKeyServiceLocator implements ServiceLocator { 22 | 23 | private static final Logger LOG = LoggerFactory.getLogger(IdKeyServiceLocator.class); 24 | 25 | /** 26 | * 服务描述的缓存,内部可以按照服务标示查找 27 | */ 28 | private ServiceRegistry serviceRegistry; 29 | 30 | /** 31 | * 判断方法是否为可暴露为服务的解析工具类 32 | */ 33 | private MethodResolver methodResolver; 34 | 35 | /** 36 | * Creates a new instance of IdKeyServiceLocator. 37 | */ 38 | public IdKeyServiceLocator() { 39 | serviceRegistry = ServiceRegistry.getInstance(); 40 | methodResolver = new SimpleMethodResolver(); 41 | } 42 | 43 | /** 44 | * @see com.baidu.beidou.navi.pbrpc.server.core.ServiceLocator#getServiceDescriptor(java.lang.Object) 45 | */ 46 | @Override 47 | public ServiceDescriptor getServiceDescriptor(Integer key) { 48 | Preconditions.checkNotNull(key, "Key cannot be null"); 49 | return serviceRegistry.getServiceDescriptorByKey(key); 50 | } 51 | 52 | /** 53 | * 注册serviceBean,暴露接口。
54 | * 如果serviceBean有多个方法接口,则在key的基础上+1,依次递增方法id,也就是说这个key只是一个起始值。 55 | * 56 | * @see com.baidu.beidou.navi.pbrpc.server.core.ServiceLocator#regiserService(java.lang.Object, java.lang.Object) 57 | */ 58 | @Override 59 | public boolean regiserService(Integer key, Object serviceBean) { 60 | Method[] ms = ReflectionUtil.getAllInstanceMethods(serviceBean.getClass()); 61 | int incr = 0; 62 | for (Method m : ms) { 63 | if (methodResolver.isSupport(m)) { 64 | ServiceDescriptor desc = new ServiceDescriptor(); 65 | desc.setServiceId(key).setMethod(m).setTarget(serviceBean) 66 | .setArgumentClass(m.getParameterTypes()[0]) 67 | .setReturnClass(m.getReturnType()); 68 | int realKey = key + incr; 69 | serviceRegistry.addServiceDescriptor(realKey, desc); 70 | LOG.info(String.format("Register service key=[%d], %s %s#%s(%s) successfully", 71 | realKey, m.getReturnType().getSimpleName(), serviceBean.getClass() 72 | .getName(), m.getName(), m.getParameterTypes()[0].getSimpleName())); 73 | incr++; 74 | } 75 | } 76 | return false; 77 | } 78 | 79 | /** 80 | * @see com.baidu.beidou.navi.pbrpc.server.core.ServiceLocator#publishService() 81 | */ 82 | @Override 83 | public boolean publishService() { 84 | LOG.info("Service publishing is disabled right now"); 85 | return true; 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /navi-pbrpc-spring/src/test/resources/ipportstring_pooled/applicationContext.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 18 | 19 | 20 | 21 | 22 | 23 | classpath:ipportstring_pooled/application.properties 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 39 | 40 | 41 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | com.baidu.beidou.navi.pbrpc.demo.service.DemoService 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /navi-pbrpc-spring/src/test/resources/ipportstring_nagative/applicationContext.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 18 | 19 | 20 | 21 | 22 | 23 | classpath:ipportstring_nagative/application.properties 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 39 | 40 | 41 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | com.baidu.beidou.navi.pbrpc.demo.service.DemoService 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/util/Pool.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.util; 2 | 3 | import org.apache.commons.pool.PoolableObjectFactory; 4 | import org.apache.commons.pool.impl.GenericObjectPool; 5 | 6 | import com.baidu.beidou.navi.pbrpc.exception.client.PbrpcConnectionException; 7 | import com.baidu.beidou.navi.pbrpc.exception.client.PbrpcException; 8 | 9 | /** 10 | * ClassName: Pool
11 | * Function: 封装commons-pool的抽象对象池 12 | * 13 | * @author Zhang Xu 14 | */ 15 | public abstract class Pool { 16 | 17 | /** 18 | * 对象池 19 | */ 20 | private final GenericObjectPool internalPool; 21 | 22 | /** 23 | * Creates a new instance of Pool. 24 | * 25 | * @param poolConfig 26 | * @param factory 27 | */ 28 | public Pool(final GenericObjectPool.Config poolConfig, PoolableObjectFactory factory) { 29 | this.internalPool = new GenericObjectPool(factory, poolConfig); 30 | } 31 | 32 | /** 33 | * 从对象池获取一个可用对象 34 | * 35 | * @return 36 | */ 37 | @SuppressWarnings("unchecked") 38 | public T getResource() { 39 | try { 40 | return (T) internalPool.borrowObject(); 41 | } catch (Exception e) { 42 | throw new PbrpcConnectionException("Could not get a resource from the pool", e); 43 | } 44 | } 45 | 46 | /** 47 | * 返回对象到池中 48 | * 49 | * @param resource 50 | */ 51 | public void returnResourceObject(final Object resource) { 52 | try { 53 | internalPool.returnObject(resource); 54 | } catch (Exception e) { 55 | throw new PbrpcException("Could not return the resource to the pool", e); 56 | } 57 | } 58 | 59 | /** 60 | * 返回一个调用失败的对象到池中 61 | * 62 | * @param resource 63 | */ 64 | public void returnBrokenResource(final T resource) { 65 | returnBrokenResourceObject(resource); 66 | } 67 | 68 | /** 69 | * 返回对象到池中 70 | * 71 | * @param resource 72 | */ 73 | public void returnResource(final T resource) { 74 | returnResourceObject(resource); 75 | } 76 | 77 | /** 78 | * 返回一个调用失败的对象到池中 79 | * 80 | * @param resource 81 | */ 82 | protected void returnBrokenResourceObject(final Object resource) { 83 | try { 84 | internalPool.invalidateObject(resource); 85 | } catch (Exception e) { 86 | throw new PbrpcException("Could not return the resource to the pool", e); 87 | } 88 | } 89 | 90 | /** 91 | * 获取活跃的池中对象数量 92 | * 93 | * @return 94 | */ 95 | public int getNumActive() { 96 | if (this.internalPool == null || this.internalPool.isClosed()) { 97 | return -1; 98 | } 99 | 100 | return this.internalPool.getNumActive(); 101 | } 102 | 103 | /** 104 | * 获取暂时idle的对象数量 105 | * 106 | * @return 107 | */ 108 | public int getNumIdle() { 109 | if (this.internalPool == null || this.internalPool.isClosed()) { 110 | return -1; 111 | } 112 | return internalPool.getNumIdle(); 113 | } 114 | 115 | /** 116 | * 销毁对象池 117 | */ 118 | public void destroy() { 119 | try { 120 | internalPool.close(); 121 | } catch (Exception e) { 122 | throw new PbrpcException("Could not destroy the pool", e); 123 | } 124 | } 125 | 126 | } 127 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/client/callback/CallbackPool.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.client.callback; 2 | 3 | import io.netty.channel.Channel; 4 | 5 | import java.util.concurrent.ConcurrentHashMap; 6 | 7 | import com.baidu.beidou.navi.pbrpc.protocol.NsHead; 8 | import com.google.protobuf.GeneratedMessage; 9 | 10 | /** 11 | * ClassName: CallbackPool
12 | * Function: 客户端回调池,用于保存调用发送请求出去的{@link CallbackContext}上下文,用于nio异步通信收到服务端响应后回调成功或者失败 13 | * 14 | * @author Zhang Xu 15 | */ 16 | public class CallbackPool { 17 | 18 | /** 19 | * Map默认键数量,全局唯一静态{@link CallbackContext}的ConcurrentHashMap初始化参数 20 | */ 21 | private static final int INITIAL_CAPACITY = 128 * 4 / 3; 22 | 23 | /** 24 | * Map的扩容装载因子,全局唯一静态{@link CallbackContext}的ConcurrentHashMap初始化参数 25 | */ 26 | private static final float LOAD_FACTOR = 0.75f; 27 | 28 | /** 29 | * Map的并发度,也就是segament数量,读不锁写锁,全局唯一静态{@link CallbackContext}的ConcurrentHashMap初始化参数 30 | */ 31 | private static final int CONCURRENCY_LEVEL = 16; 32 | 33 | /** 34 | * 保存{@link CallbackContext}的Map,键为调用的唯一标示,是{@link NsHead}头中的logId 35 | */ 36 | private static ConcurrentHashMap CALLBACK_MAP = new ConcurrentHashMap( 37 | INITIAL_CAPACITY, LOAD_FACTOR, CONCURRENCY_LEVEL); 38 | 39 | /** 40 | * 根据id标示获取上下文 41 | * 42 | * @param id 43 | * @return 44 | */ 45 | public static CallbackContext getContext(int logId) { 46 | CallbackContext callbackContext = CALLBACK_MAP.get(logId); 47 | return callbackContext == null ? null : callbackContext; 48 | } 49 | 50 | /** 51 | * 根据id标示获取上下文内的回调 52 | * 53 | * @param logId 54 | * @return 55 | */ 56 | @SuppressWarnings("unchecked") 57 | public static Callback get(int logId) { 58 | CallbackContext callbackContext = CALLBACK_MAP.get(logId); 59 | return callbackContext == null ? null : (Callback) callbackContext.getCallback(); 60 | } 61 | 62 | /** 63 | * 根据id获取上下文内的待返回对象类型 64 | * 65 | * @param logId 66 | * @return 67 | */ 68 | public static Class getResClass(int logId) { 69 | CallbackContext callbackContext = CALLBACK_MAP.get(logId); 70 | return callbackContext == null ? null : callbackContext.getResClazz(); 71 | } 72 | 73 | /** 74 | * 放入回调上下文 75 | * 76 | * @param logId 77 | * logId 78 | * @param timeout 79 | * 客户端调用超时 80 | * @param isShortAliveConn 81 | * 客户端是否为短连接 82 | * @param channel 83 | * 客户端连接的channel 84 | * @param resClazz 85 | * 客户端要返回的class类型 86 | * @param callback 87 | * 客户端句柄callback 88 | */ 89 | public static void put(int logId, int timeout, 90 | boolean isShortAliveConn, Channel channel, Class resClazz, Callback callback) { 91 | CALLBACK_MAP.putIfAbsent(logId, new CallbackContext(logId, System.currentTimeMillis(), 92 | timeout, isShortAliveConn, channel, resClazz, callback)); 93 | } 94 | 95 | /** 96 | * 移除回调上下文 97 | * 98 | * @param id 99 | */ 100 | public static void remove(int logId) { 101 | CALLBACK_MAP.remove(logId); 102 | } 103 | 104 | /** 105 | * 清理Map 106 | */ 107 | public static void clear() { 108 | CALLBACK_MAP.clear(); 109 | } 110 | 111 | /** 112 | * 获取保存回调上下文的Map 113 | * 114 | * @return 115 | */ 116 | public static ConcurrentHashMap getCALLBACK_MAP() { 117 | return CALLBACK_MAP; 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/util/ByteUtil.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.util; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.io.UnsupportedEncodingException; 6 | 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | /** 11 | * ClassName: ByteUtil
12 | * Function: 字节码工具 13 | * 14 | * @author Zhang Xu 15 | */ 16 | public class ByteUtil { 17 | 18 | private static final Logger LOG = LoggerFactory.getLogger(ByteUtil.class); 19 | 20 | 21 | /** 22 | * 默认字符编码 23 | */ 24 | private static final String STR_ENCODE = "UTF-8"; 25 | 26 | /** 27 | * 将字符串转换成UTF-8的字节码,阶段16个字节的长度 28 | * 29 | * @param input 30 | * @param length 31 | * @return 32 | */ 33 | public static byte[] convertStringToBytes(String input, int length) { 34 | byte[] tmp = convertStringToBytes(input); 35 | byte[] bytes = new byte[length]; 36 | System.arraycopy(tmp, 0, bytes, 0, tmp.length); 37 | return bytes; 38 | } 39 | 40 | /** 41 | * 将字符串转换成UTF-8的字节码 42 | * 43 | * @param input 44 | * @return byte[] 45 | */ 46 | public static byte[] convertStringToBytes(String input) { 47 | byte[] result = null; 48 | if (input != null) { 49 | try { 50 | result = input.getBytes(STR_ENCODE); 51 | } catch (UnsupportedEncodingException e) { 52 | e.printStackTrace(); 53 | } 54 | } 55 | return result; 56 | } 57 | 58 | /** 59 | * 字节码转字符串 60 | * 61 | * @param input 62 | * @return 63 | */ 64 | public static String convertBytesToString(byte[] input) { 65 | String result = null; 66 | if (input != null) { 67 | try { 68 | result = new String(input, STR_ENCODE); 69 | } catch (Exception e) { 70 | e.printStackTrace(); 71 | } 72 | } 73 | return result; 74 | } 75 | 76 | /** 77 | * 获取非空字节码 78 | * 79 | * @param data 80 | * @return 81 | */ 82 | public static byte[] getNonEmptyBytes(byte[] data) { 83 | if (data == null) { 84 | return new byte[0]; 85 | } else { 86 | return data; 87 | } 88 | } 89 | 90 | /** 91 | * read inputstream to a byte array 92 | * 93 | * @param body 94 | * @param in 95 | * @return 96 | * @throws IOException 97 | */ 98 | public static int read(byte[] body, InputStream in) throws IOException { 99 | byte[] buffer = new byte[1024 * 32]; 100 | int readlength = 0; 101 | int offset = 0; 102 | int bytesRead = -1; 103 | try { 104 | while (offset < body.length) { 105 | if ((body.length - offset) > buffer.length) { 106 | readlength = buffer.length; 107 | } else { 108 | readlength = body.length - offset; 109 | } 110 | bytesRead = in.read(buffer, 0, readlength); 111 | 112 | if (bytesRead != -1) { 113 | System.arraycopy(buffer, 0, body, offset, bytesRead); 114 | offset += bytesRead; 115 | } else { 116 | break; 117 | } 118 | 119 | } 120 | } catch (Exception e) { 121 | LOG.warn("bytesRead:" + bytesRead + "; offset:" + offset + "; BODT_length:" 122 | + body.length, e); 123 | throw new IOException(e.getMessage()); 124 | 125 | } finally { 126 | readlength = offset; 127 | } 128 | 129 | return readlength; 130 | } 131 | 132 | } 133 | -------------------------------------------------------------------------------- /navi-pbrpc-spring/src/test/resources/autoevict/applicationContext.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 18 | 19 | 20 | 21 | 22 | 23 | classpath:autoevict/application.properties 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 50 | 51 | 52 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | com.baidu.beidou.navi.pbrpc.demo.service.DemoService 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /navi-pbrpc-spring/src/test/resources/ipportlist/applicationContext.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 18 | 19 | 20 | 21 | 22 | 23 | classpath:ipportlist/application.properties 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | com.baidu.beidou.navi.pbrpc.demo.service.DemoService 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/client/HAPbrpcClient.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.client; 2 | 3 | import io.netty.channel.ChannelFuture; 4 | 5 | import java.util.List; 6 | 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import com.baidu.beidou.navi.pbrpc.client.callback.CallFuture; 11 | import com.baidu.beidou.navi.pbrpc.client.ha.LoadBalanceStrategy; 12 | import com.baidu.beidou.navi.pbrpc.transport.PbrpcMsg; 13 | import com.baidu.beidou.navi.pbrpc.util.Preconditions; 14 | import com.google.protobuf.GeneratedMessage; 15 | 16 | /** 17 | * ClassName: HAPbrpcClient
18 | * Function: 高可用的pbrpc客户端 19 | * 20 | * @author Zhang Xu 21 | */ 22 | public class HAPbrpcClient implements PbrpcClient { 23 | 24 | private static final Logger LOG = LoggerFactory.getLogger(HAPbrpcClient.class); 25 | 26 | /** 27 | * 负载均衡策略 28 | */ 29 | private LoadBalanceStrategy loadBalanceStrategy; 30 | 31 | /** 32 | * 客户端list 33 | */ 34 | private List clientList; 35 | 36 | public HAPbrpcClient() { 37 | } 38 | 39 | /** 40 | * Creates a new instance of HAPbrpcClient. 41 | * 42 | * @param clientList 43 | */ 44 | public HAPbrpcClient(List clientList) { 45 | this.clientList = clientList; 46 | } 47 | 48 | /** 49 | * @see com.baidu.beidou.navi.pbrpc.client.PbrpcClient#connect() 50 | */ 51 | @Override 52 | public ChannelFuture connect() { 53 | throw new IllegalStateException(this.getClass().getSimpleName() 54 | + " does not need to call connect"); 55 | } 56 | 57 | /** 58 | * @see com.baidu.beidou.navi.pbrpc.client.PbrpcClient#shutdown() 59 | */ 60 | @Override 61 | public void shutdown() { 62 | if (clientList != null) { 63 | for (PbrpcClient client : clientList) { 64 | LOG.info("Start to destroy " + client.getInfo()); 65 | client.shutdown(); 66 | } 67 | } 68 | } 69 | 70 | /** 71 | * @see com.baidu.beidou.navi.pbrpc.client.PbrpcClient#asyncTransport(java.lang.Class, 72 | * com.baidu.beidou.navi.pbrpc.transport.PbrpcMsg) 73 | */ 74 | @Override 75 | public CallFuture asyncTransport(Class responseClazz, 76 | PbrpcMsg pbrpcMsg) { 77 | Preconditions.checkNotNull(loadBalanceStrategy, "Load balance strategy is not init"); 78 | return loadBalanceStrategy.doAsyncTransport(clientList, responseClazz, pbrpcMsg); 79 | } 80 | 81 | /** 82 | * @see com.baidu.beidou.navi.pbrpc.client.PbrpcClient#syncTransport(java.lang.Class, 83 | * com.baidu.beidou.navi.pbrpc.transport.PbrpcMsg) 84 | */ 85 | @Override 86 | public T syncTransport(Class responseClazz, PbrpcMsg pbrpcMsg) { 87 | Preconditions.checkNotNull(loadBalanceStrategy, "Load balance strategy is not init"); 88 | return loadBalanceStrategy.doSyncTransport(clientList, responseClazz, pbrpcMsg); 89 | } 90 | 91 | /** 92 | * @see com.baidu.beidou.navi.pbrpc.client.PbrpcClient#getInfo() 93 | */ 94 | @Override 95 | public String getInfo() { 96 | StringBuilder sb = new StringBuilder(); 97 | sb.append("HA pbrpc client "); 98 | if (clientList != null) { 99 | for (PbrpcClient client : clientList) { 100 | sb.append("["); 101 | sb.append(client.getInfo()); 102 | sb.append("]"); 103 | } 104 | } 105 | return sb.toString(); 106 | } 107 | 108 | /** 109 | * 设置负载均衡器 110 | * 111 | * @param loadBalanceStrategy 112 | * 113 | * @return 114 | */ 115 | public HAPbrpcClient setLoadBalanceStrategy(LoadBalanceStrategy loadBalanceStrategy) { 116 | this.loadBalanceStrategy = loadBalanceStrategy; 117 | return this; 118 | } 119 | 120 | public void setClientList(List clientList) { 121 | this.clientList = clientList; 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /navi-pbrpc-spring/src/test/java/com/baidu/beidou/navi/pbrpc/spring/SpringIntegrationIpPortStringAutoEvictTest.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.spring; 2 | 3 | import static org.hamcrest.Matchers.is; 4 | import static org.junit.Assert.assertThat; 5 | 6 | import java.util.concurrent.Callable; 7 | import java.util.concurrent.CompletionService; 8 | import java.util.concurrent.ExecutorCompletionService; 9 | import java.util.concurrent.ExecutorService; 10 | import java.util.concurrent.Executors; 11 | 12 | import org.junit.AfterClass; 13 | import org.junit.BeforeClass; 14 | import org.junit.Test; 15 | import org.springframework.beans.factory.annotation.Autowired; 16 | import org.springframework.test.context.ContextConfiguration; 17 | import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests; 18 | 19 | import com.baidu.beidou.navi.pbrpc.demo.proto.Demo; 20 | import com.baidu.beidou.navi.pbrpc.demo.service.DemoService; 21 | import com.baidu.beidou.navi.pbrpc.demo.service.impl.DemoServiceImpl; 22 | import com.baidu.beidou.navi.pbrpc.server.PbrpcServer; 23 | 24 | /** 25 | * @author zhangxu 26 | */ 27 | @ContextConfiguration(locations = {"classpath*:autoevict/applicationContext.xml"}) 28 | public class SpringIntegrationIpPortStringAutoEvictTest extends AbstractJUnit4SpringContextTests { 29 | 30 | @Autowired 31 | private DemoService demoService; 32 | 33 | @Test 34 | public void testDoSmth() throws Exception { 35 | Demo.DemoRequest.Builder req = Demo.DemoRequest.newBuilder(); 36 | req.setUserId(1); 37 | 38 | int multiSize = 2; 39 | int totalRequestSize = 50; 40 | ExecutorService pool = Executors.newFixedThreadPool(multiSize); 41 | CompletionService completionService = new ExecutorCompletionService( 42 | pool); 43 | 44 | Invoker invoker = new Invoker(req.build()); 45 | long time = System.currentTimeMillis(); 46 | for (int i = 0; i < totalRequestSize; i++) { 47 | completionService.submit(invoker); 48 | } 49 | 50 | Thread.sleep(6000); 51 | SERVER_HA.shutdown(); 52 | 53 | for (int i = 0; i < totalRequestSize; i++) { 54 | completionService.take().get(); 55 | } 56 | 57 | long timetook = System.currentTimeMillis() - time; 58 | System.out.println("Total using " + timetook + "ms"); 59 | System.out.println("QPS:" + 1000f / ((timetook) / (1.0f * totalRequestSize))); 60 | } 61 | 62 | private class Invoker implements Callable { 63 | 64 | private Demo.DemoRequest request; 65 | 66 | public Invoker(Demo.DemoRequest request) { 67 | this.request = request; 68 | } 69 | 70 | @Override 71 | public Demo.DemoResponse call() throws Exception { 72 | Demo.DemoResponse response = demoService.doSmth(request); 73 | //System.out.println(response); 74 | assertThat(response.getUserId(), is(1)); 75 | Thread.sleep(600); 76 | return response; 77 | } 78 | 79 | } 80 | 81 | private static byte[] getData(int userId) { 82 | Demo.DemoRequest.Builder req = Demo.DemoRequest.newBuilder(); 83 | req.setUserId(userId); 84 | byte[] data = req.build().toByteArray(); 85 | return data; 86 | } 87 | 88 | protected static PbrpcServer SERVER = null; 89 | protected static PbrpcServer SERVER_HA = null; 90 | 91 | protected static int PORT = 14419; 92 | protected static int PORT_HA = 14420; 93 | 94 | @BeforeClass 95 | public static void setUp() { 96 | System.out.println("Start server now..."); 97 | SERVER = new PbrpcServer(PORT); 98 | SERVER.register(100, new DemoServiceImpl()); 99 | SERVER.start(); 100 | 101 | SERVER_HA = new PbrpcServer(PORT_HA); 102 | SERVER_HA.register(100, new DemoServiceImpl()); 103 | SERVER_HA.start(); 104 | } 105 | 106 | @AfterClass 107 | public static void tearDown() { 108 | if (SERVER != null) { 109 | SERVER.shutdown(); 110 | } 111 | if (SERVER_HA != null) { 112 | SERVER_HA.shutdown(); 113 | } 114 | try { 115 | Thread.sleep(1000); 116 | } catch (Exception e) { 117 | // TODO: handle exception 118 | } 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /navi-pbrpc-spring/src/test/java/com/baidu/beidou/navi/pbrpc/spring/SpringIntegrationIpPortStringPooledBlockingIOTest.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.spring; 2 | 3 | import static org.hamcrest.Matchers.is; 4 | import static org.junit.Assert.assertThat; 5 | import static org.junit.Assert.fail; 6 | 7 | import java.util.concurrent.Callable; 8 | import java.util.concurrent.CompletionService; 9 | import java.util.concurrent.ExecutorCompletionService; 10 | import java.util.concurrent.ExecutorService; 11 | import java.util.concurrent.Executors; 12 | 13 | import org.junit.AfterClass; 14 | import org.junit.BeforeClass; 15 | import org.junit.Test; 16 | import org.springframework.beans.factory.annotation.Autowired; 17 | import org.springframework.test.context.ContextConfiguration; 18 | import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests; 19 | 20 | import com.baidu.beidou.navi.pbrpc.client.PbrpcClient; 21 | import com.baidu.beidou.navi.pbrpc.demo.proto.Demo; 22 | import com.baidu.beidou.navi.pbrpc.demo.service.DemoService; 23 | import com.baidu.beidou.navi.pbrpc.demo.service.impl.DemoServiceImpl; 24 | import com.baidu.beidou.navi.pbrpc.server.PbrpcServer; 25 | import com.baidu.beidou.navi.pbrpc.transport.PbrpcMsg; 26 | 27 | /** 28 | * @author zhangxu 29 | */ 30 | @ContextConfiguration(locations = {"classpath*:ipportstring_pooled/applicationContext.xml"}) 31 | public class SpringIntegrationIpPortStringPooledBlockingIOTest extends AbstractJUnit4SpringContextTests { 32 | 33 | @Autowired 34 | private DemoService demoService; 35 | 36 | @Test 37 | public void testDoSmth() throws Exception { 38 | Demo.DemoRequest.Builder req = Demo.DemoRequest.newBuilder(); 39 | req.setUserId(1); 40 | 41 | int multiSize = 12; 42 | int totalRequestSize = 10; 43 | ExecutorService pool = Executors.newFixedThreadPool(multiSize); 44 | CompletionService completionService = new ExecutorCompletionService( 45 | pool); 46 | 47 | Invoker invoker = new Invoker(req.build()); 48 | long time = System.currentTimeMillis(); 49 | for (int i = 0; i < totalRequestSize; i++) { 50 | completionService.submit(invoker); 51 | } 52 | 53 | for (int i = 0; i < totalRequestSize; i++) { 54 | completionService.take().get(); 55 | } 56 | 57 | long timetook = System.currentTimeMillis() - time; 58 | System.out.println("Total using " + timetook + "ms"); 59 | System.out.println("QPS:" + 1000f / ((timetook) / (1.0f * totalRequestSize))); 60 | } 61 | 62 | private class Invoker implements Callable { 63 | 64 | private Demo.DemoRequest request; 65 | 66 | public Invoker(Demo.DemoRequest request) { 67 | this.request = request; 68 | } 69 | 70 | @Override 71 | public Demo.DemoResponse call() throws Exception { 72 | Demo.DemoResponse response = demoService.doSmth(request); 73 | System.out.println(response); 74 | assertThat(response.getUserId(), is(1)); 75 | return response; 76 | } 77 | 78 | } 79 | 80 | private static byte[] getData(int userId) { 81 | Demo.DemoRequest.Builder req = Demo.DemoRequest.newBuilder(); 82 | req.setUserId(userId); 83 | byte[] data = req.build().toByteArray(); 84 | return data; 85 | } 86 | 87 | protected static PbrpcServer SERVER = null; 88 | protected static PbrpcServer SERVER_HA = null; 89 | 90 | protected static int PORT = 14419; 91 | protected static int PORT_HA = 14420; 92 | 93 | @BeforeClass 94 | public static void setUp() { 95 | System.out.println("Start server now..."); 96 | SERVER = new PbrpcServer(PORT); 97 | SERVER.register(100, new DemoServiceImpl()); 98 | SERVER.start(); 99 | 100 | SERVER_HA = new PbrpcServer(PORT_HA); 101 | SERVER_HA.register(100, new DemoServiceImpl()); 102 | SERVER_HA.start(); 103 | } 104 | 105 | @AfterClass 106 | public static void tearDown() { 107 | if (SERVER != null) { 108 | SERVER.shutdown(); 109 | } 110 | if (SERVER_HA != null) { 111 | SERVER_HA.shutdown(); 112 | } 113 | try { 114 | Thread.sleep(1000); 115 | } catch (Exception e) { 116 | // TODO: handle exception 117 | } 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Navi-pbrpc ![](https://api.travis-ci.org/neoremind/navi-pbrpc.svg?branch=master) [![Coverage Status](https://coveralls.io/repos/neoremind/navi-pbrpc/badge.svg)](https://coveralls.io/r/neoremind/navi-pbrpc) ![](https://maven-badges.herokuapp.com/maven-central/com.baidu.beidou/navi-pbrpc/badge.svg) Navi-pbrpc provides a rpc solution for using protocol buffer. This library enables client and server to communicate in a peer-to-peer and full duplexing way. The server-side is built upon [netty](http://netty.io/) which supports asynchronous and non-blocking io functionality, while the client-side provides a wide variety of options to communicate with server, which includes short live connection, keep-alive tcp connection, high availability and failover strategy. ## Quick Start ### 1. Prerequisite Add the below dependency to pom.xml for a maven enabled project. com.baidu.beidou navi-pbrpc 1.1.1 ### 2. Make a protobuf generated message Use `protoc` command to compile an **IDL proto file** and generate a java source file. The IDL proto file can define the request and response type. Below is a simple sample: ``` package com.baidu.beidou.navi.pbrpc.demo.proto; option cc_generic_services = true; message DemoRequest { optional int32 user_id = 1; } message DemoResponse { optional int32 user_id = 1; optional string user_name = 2; enum GenderType { MALE = 1; FEMALE = 2; } optional GenderType gender_type = 3; } ``` ### 3. Develop server-side service Develop a server-side service implementation. Below is an example based on the IDL generated java code from the previous step. Note that the method `doSmth` use the generated class `DemoRequest` as the parameter and `DemoResponse` as the return type. The logic here is pretty simple. public class DemoServiceImpl implements DemoService { @Override public DemoResponse doSmth(DemoRequest req) { DemoResponse.Builder builder = DemoResponse.newBuilder(); builder.setUserId(1); builder.setUserName("name-1"); builder.setGenderType(DemoResponse.GenderType.MALE); return builder.build(); } } ### 4. Expose service and start server Register the service implementation and set the **service id** as 100. The id here will be used by the client later as a way of locating one specific service. Then start the server on port 8088. ``` PbrpcServer server = new PbrpcServer(8088); server.register(100, new DemoServiceImpl()); server.start(); ``` ### 5. Develop client to invoke remote service The framework provides many options to communicate with the server in terms of short live connection or keep-alive connection, high availablity and failover strategy. You can check out more on the [Tutorials wiki](https://github.com/neoremind/navi-pbrpc/wiki/Tutorials). Below demostrates how to build a keep-alive, full-duplexing connection pool and make a rpc call. ``` // 1) Build client with keep-alive, full-duplexing pooled connection, and client read timeout is 60s PbrpcClient client = PbrpcClientFactory.buildPooledConnection(new PooledConfiguration(), "127.0.0.1", 8088, 60000); // 2) Construct request data by using protobuf DemoRequest.Builder req = DemoRequest.newBuilder(); req.setUserId(1); byte[] data = req.build().toByteArray(); // 3) Build message by specifying the service id, and the property provider is used as a client trace sign to tell server who I am. PbrpcMsg msg = new PbrpcMsg(); msg.setServiceId(100); msg.setProvider("beidou"); msg.setData(data); // 4) Asynchronous invocation and return a future for client to hold CallFuture future = client.asyncTransport(DemoResponse.class, msg); // 5) Wait response to come. Once rpc call is done, the code will stop blocking right away. DemoResponse res = future.get(); // 6) Print out result. System.out.println(res); ``` === ### Dependencies Navi-pbrpc tries to leverage minimum amount of dependency libraries, so that project built upon Navi-pbrpc will not be overwhelmed by other unwanted libraries. The following are the dependencies. [INFO] +- commons-pool:commons-pool:jar:1.5.7:compile [INFO] +- com.google.protobuf:protobuf-java:jar:2.5.0:compile [INFO] +- io.netty:netty-all:jar:4.0.28.Final:compile [INFO] +- org.javassist:javassist:jar:3.18.1-GA:compile [INFO] +- org.slf4j:slf4j-api:jar:1.7.7:compile [INFO] +- org.slf4j:slf4j-log4j12:jar:1.7.7:compile [INFO] | \- log4j:log4j:jar:1.2.17:compile === ### More information Click here to [Tutorials wiki](https://github.com/neoremind/navi-pbrpc/wiki/Tutorials). ### Supports ![](http://neoremind.net/imgs/gmail.png) -------------------------------------------------------------------------------- /navi-pbrpc-spring/src/main/java/com/baidu/beidou/navi/pbrpc/spring/JdkDynamicIntegrationProxy.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.spring; 2 | 3 | import java.lang.reflect.InvocationHandler; 4 | import java.lang.reflect.Method; 5 | import java.lang.reflect.Proxy; 6 | import java.util.Arrays; 7 | 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | import com.baidu.beidou.navi.pbrpc.annotation.PbrpcMethodId; 12 | import com.baidu.beidou.navi.pbrpc.client.PbrpcClient; 13 | import com.baidu.beidou.navi.pbrpc.exception.client.PbrpcException; 14 | import com.baidu.beidou.navi.pbrpc.transport.PbrpcMsg; 15 | import com.google.protobuf.GeneratedMessage; 16 | 17 | /** 18 | * JDK动态代理生成代理实例对象 19 | * 20 | * @author zhangxu 21 | */ 22 | public class JdkDynamicIntegrationProxy implements IntegrationProxy { 23 | 24 | private static final Logger LOG = LoggerFactory.getLogger(JdkDynamicIntegrationProxy.class); 25 | 26 | /** 27 | * Pbrpc客户端 28 | */ 29 | private PbrpcClient pbrpcClient; 30 | 31 | /** 32 | * {@link PbrpcMsg}中的provider,用于Pbrpc请求头,标示调用者来源,例如填充团队名称 33 | */ 34 | private String provider; 35 | 36 | /** 37 | * 创建指定接口的实例对象 38 | * 39 | * @param clazz 类型 40 | * 41 | * @return 代理实例对象 42 | */ 43 | @Override 44 | public T createProxy(Class clazz) { 45 | return (T) (Proxy.newProxyInstance(getClass().getClassLoader(), 46 | new Class[] {clazz}, new JdkDynamicProxyHandler())); 47 | } 48 | 49 | /** 50 | * JDK动态代理的InvocationHandler,AOP执行期间拦截接口调用的实现 51 | * 52 | * @author zhangxu 53 | */ 54 | class JdkDynamicProxyHandler implements InvocationHandler { 55 | 56 | /** 57 | * 代理运行时拦截的方法 58 | * 59 | * @param proxy 代理接口 60 | * @param method 代理方法 61 | * @param args 参数列表 62 | * 63 | * @return 代理实例对象 64 | * 65 | * @throws Throwable 66 | */ 67 | @Override 68 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 69 | if (LOG.isDebugEnabled()) { 70 | LOG.debug(String.format( 71 | "Proxy bean starts to invoke pbrpc on %s %s.%s(%s)", 72 | method.getReturnType().getSimpleName(), 73 | method.getDeclaringClass().getSimpleName(), 74 | method.getName(), 75 | Arrays.toString(args))); 76 | } 77 | 78 | // check arguments and returnType 79 | if (args == null || args.length != 1) { 80 | throw new PbrpcException("Pbrpc only support one argument"); 81 | } 82 | if (!GeneratedMessage.class.isAssignableFrom(method.getParameterTypes()[0])) { 83 | throw new PbrpcException("Pbrpc method argument should be an instance of GeneratedMessage"); 84 | } 85 | if (!GeneratedMessage.class.isAssignableFrom(method.getReturnType())) { 86 | throw new PbrpcException("Pbrpc method returnType should be an instance of GeneratedMessage"); 87 | } 88 | 89 | Class responseClass = 90 | (Class) method.getReturnType(); 91 | 92 | PbrpcMsg msg = new PbrpcMsg(); 93 | msg.setServiceId(getMethodId(method)); 94 | msg.setProvider(provider); 95 | msg.setData(((GeneratedMessage) args[0]).toByteArray()); 96 | if (LOG.isDebugEnabled()) { 97 | LOG.debug(String.format("provider=%s, methodId=%d", msg.getProvider(), msg.getServiceId())); 98 | } 99 | GeneratedMessage response = pbrpcClient.syncTransport(responseClass, msg); 100 | return response; 101 | } 102 | 103 | /** 104 | * 从接口的注解中获取填充Pbrpc头的methodId,如果没有{@link PbrpcMethodId}注解,则默认为0 105 | * 106 | * @param method 方法 107 | * 108 | * @return methodId 109 | */ 110 | private int getMethodId(Method method) { 111 | PbrpcMethodId pbrpcMethodId = method.getAnnotation(PbrpcMethodId.class); 112 | if (pbrpcMethodId == null) { 113 | return 0; 114 | } 115 | return pbrpcMethodId.value(); 116 | } 117 | } 118 | 119 | public void setPbrpcClient(PbrpcClient pbrpcClient) { 120 | this.pbrpcClient = pbrpcClient; 121 | } 122 | 123 | public void setProvider(String provider) { 124 | this.provider = provider; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/client/handler/PbrpcClientHandler.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.client.handler; 2 | 3 | import io.netty.channel.Channel; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.SimpleChannelInboundHandler; 6 | 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import com.baidu.beidou.navi.pbrpc.client.callback.Callback; 11 | import com.baidu.beidou.navi.pbrpc.client.callback.CallbackContext; 12 | import com.baidu.beidou.navi.pbrpc.client.callback.CallbackPool; 13 | import com.baidu.beidou.navi.pbrpc.codec.Codec; 14 | import com.baidu.beidou.navi.pbrpc.codec.impl.ProtobufCodec; 15 | import com.baidu.beidou.navi.pbrpc.error.ExceptionUtil; 16 | import com.baidu.beidou.navi.pbrpc.transport.PbrpcMessageDeserializer; 17 | import com.baidu.beidou.navi.pbrpc.transport.PbrpcMsg; 18 | import com.baidu.beidou.navi.pbrpc.util.ContextHolder; 19 | import com.baidu.beidou.navi.pbrpc.util.Preconditions; 20 | import com.google.protobuf.GeneratedMessage; 21 | 22 | /** 23 | * ClassName: PbrpcClientHandler
24 | * Function: 客户端的核心handler 25 | * 26 | * @author Zhang Xu 27 | */ 28 | public class PbrpcClientHandler extends SimpleChannelInboundHandler { 29 | 30 | private static final Logger LOG = LoggerFactory.getLogger(PbrpcMessageDeserializer.class); 31 | 32 | /** 33 | * 可配置,默认使用protobuf来做body的序列化 34 | */ 35 | private Codec codec = new ProtobufCodec(); 36 | 37 | /** 38 | * @see io.netty.channel.SimpleChannelInboundHandler#channelRead0(io.netty.channel.ChannelHandlerContext, 39 | * java.lang.Object) 40 | */ 41 | @SuppressWarnings("unchecked") 42 | @Override 43 | public void channelRead0(ChannelHandlerContext ctx, PbrpcMsg pbrpcMsg) throws Exception { 44 | Preconditions 45 | .checkArgument(pbrpcMsg != null, "Pbrpc msg is null which should never happen"); 46 | try { 47 | // LOG.info("Got msg from server:" + pbrpcMsg); 48 | int logId = (int) pbrpcMsg.getLogId(); 49 | CallbackContext context = CallbackPool.getContext(logId); 50 | if (context == null) { 51 | LOG.warn("Receive msg from server but no context found, logId=" + logId); 52 | return; 53 | } 54 | Callback cb = (Callback) context.getCallback(); 55 | if (pbrpcMsg.getErrorCode() != null) { 56 | cb.handleError(ExceptionUtil.buildFromErrorCode(pbrpcMsg.getErrorCode())); 57 | } else { 58 | GeneratedMessage res = (GeneratedMessage) codec.decode( 59 | CallbackPool.getResClass(logId), pbrpcMsg.getData()); 60 | cb.handleResult(res); 61 | } 62 | 63 | // 短连接则关闭channel 64 | if (context.isShortAliveConn()) { 65 | Channel channel = context.getChannel(); 66 | if (channel != null) { 67 | LOG.info("Close " + channel + ", logId=" + logId); 68 | channel.close(); 69 | } 70 | } 71 | // LOG.info("Decoding and invoking callback " + pbrpcMsg.getLogId() + " total " 72 | // + (System.currentTimeMillis() - context.getStarttime()) 73 | // + "ms, transport using " + (start - context.getStarttime()) + "ms"); 74 | } finally { 75 | CallbackPool.remove((int) pbrpcMsg.getLogId()); 76 | ContextHolder.clean(); 77 | // ctx.fireChannelReadComplete(); 78 | } 79 | } 80 | 81 | /** 82 | * @see io.netty.channel.ChannelInboundHandlerAdapter#channelReadComplete(io.netty.channel.ChannelHandlerContext) 83 | */ 84 | @Override 85 | public void channelReadComplete(ChannelHandlerContext ctx) { 86 | // LOG.debug("Client channelReadComplete>>>>>"); 87 | // ctx.flush(); 88 | } 89 | 90 | /** 91 | * @see io.netty.channel.ChannelInboundHandlerAdapter#channelActive(io.netty.channel.ChannelHandlerContext) 92 | */ 93 | @Override 94 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 95 | // LOG.debug("Client channelActive>>>>>"); 96 | } 97 | 98 | /** 99 | * @see io.netty.channel.ChannelInboundHandlerAdapter#exceptionCaught(io.netty.channel.ChannelHandlerContext, 100 | * java.lang.Throwable) 101 | */ 102 | @Override 103 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 104 | LOG.error(cause.getMessage(), cause); 105 | ctx.close(); // FIXME 106 | // ctx.fireChannelRead(); 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/client/ha/RandomLoadBalanceStrategy.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.client.ha; 2 | 3 | import java.util.List; 4 | import java.util.Random; 5 | 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import com.baidu.beidou.navi.pbrpc.client.PbrpcClient; 10 | import com.baidu.beidou.navi.pbrpc.client.callback.CallFuture; 11 | import com.baidu.beidou.navi.pbrpc.exception.client.HAPbrpcException; 12 | import com.baidu.beidou.navi.pbrpc.transport.PbrpcMsg; 13 | import com.google.protobuf.GeneratedMessage; 14 | 15 | /** 16 | * ClassName: RandomLoadBalanceStrategy
17 | * Function: 随机负载均衡策略调用 18 | * 19 | * @author Zhang Xu 20 | */ 21 | public class RandomLoadBalanceStrategy implements LoadBalanceStrategy { 22 | 23 | private static final Logger LOG = LoggerFactory.getLogger(RandomLoadBalanceStrategy.class); 24 | 25 | /** 26 | * 随机数器 27 | */ 28 | private Random randomer = new Random(); 29 | 30 | /** 31 | * 失败处理策略 32 | */ 33 | private FailStrategy failStrategy; 34 | 35 | /** 36 | * 传输调用回调 37 | */ 38 | private TransportCallback transportCallback = new DefaultTransportCallback(); 39 | 40 | public RandomLoadBalanceStrategy() { 41 | } 42 | 43 | /** 44 | * Creates a new instance of RandomLoadBalanceStrategy. 45 | * 46 | * @param failStrategy 47 | */ 48 | public RandomLoadBalanceStrategy(FailStrategy failStrategy) { 49 | this.failStrategy = failStrategy; 50 | } 51 | 52 | /** 53 | * 内部抽象方法调用 54 | * 55 | * @param clientList 56 | * @param responseClazz 57 | * @param pbrpcMsg 58 | * @param isAsync 59 | * 60 | * @return 61 | * 62 | * @throws HAPbrpcException 63 | */ 64 | public Object transport(List clientList, 65 | Class responseClazz, PbrpcMsg pbrpcMsg, boolean isAsync) 66 | throws HAPbrpcException { 67 | int clientSize = clientList.size(); 68 | for (int currRetry = 0; currRetry < failStrategy.getMaxRetryTimes() 69 | && currRetry < clientSize; ) { 70 | int index = randomer.nextInt(clientSize); 71 | PbrpcClient client = clientList.get(index); 72 | try { 73 | LOG.info("Call on " + client.getInfo() + " starts..."); 74 | if (isAsync) { 75 | CallFuture ret = (CallFuture) client.asyncTransport(responseClazz, pbrpcMsg); 76 | transportCallback.onSuccess(client, clientList); 77 | return ret; 78 | } else { 79 | T ret = (T) client.syncTransport(responseClazz, pbrpcMsg); 80 | transportCallback.onSuccess(client, clientList); 81 | return ret; 82 | } 83 | } catch (Exception e) { 84 | transportCallback.onFail(client, clientList, e); 85 | LOG.error("Call on " + client.getInfo() + " failed due to " + e.getMessage(), e); 86 | if (failStrategy.isQuitImmediately(currRetry, clientSize)) { 87 | throw new HAPbrpcException(e); 88 | } 89 | LOG.info("Fail over to next if available..."); 90 | continue; 91 | } finally { 92 | currRetry++; 93 | } 94 | } 95 | throw new HAPbrpcException("Failed to transport on all clients"); 96 | } 97 | 98 | /** 99 | * @see com.baidu.beidou.navi.pbrpc.client.ha.LoadBalanceStrategy#doAsyncTransport(java.util.List, java.lang.Class, 100 | * com.baidu.beidou.navi.pbrpc.transport.PbrpcMsg) 101 | */ 102 | @SuppressWarnings("unchecked") 103 | @Override 104 | public CallFuture doAsyncTransport( 105 | List clientList, Class responseClazz, PbrpcMsg pbrpcMsg) 106 | throws HAPbrpcException { 107 | return (CallFuture) transport(clientList, responseClazz, pbrpcMsg, true); 108 | } 109 | 110 | /** 111 | * @see com.baidu.beidou.navi.pbrpc.client.ha.LoadBalanceStrategy#doSyncTransport(java.util.List, java.lang.Class, 112 | * com.baidu.beidou.navi.pbrpc.transport.PbrpcMsg) 113 | */ 114 | @SuppressWarnings("unchecked") 115 | @Override 116 | public T doSyncTransport(List clientList, 117 | Class responseClazz, PbrpcMsg pbrpcMsg) { 118 | return (T) transport(clientList, responseClazz, pbrpcMsg, false); 119 | } 120 | 121 | public void setFailStrategy(FailStrategy failStrategy) { 122 | this.failStrategy = failStrategy; 123 | } 124 | 125 | public void setTransportCallback(TransportCallback transportCallback) { 126 | this.transportCallback = transportCallback; 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/test/java/com/baidu/beidou/navi/pbrpc/demo/service/impl/DemoServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.demo.service.impl; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | import com.baidu.beidou.navi.pbrpc.demo.proto.Demo.DemoBatchRequest; 9 | import com.baidu.beidou.navi.pbrpc.demo.proto.Demo.DemoBatchResponse; 10 | import com.baidu.beidou.navi.pbrpc.demo.proto.Demo.DemoRequest; 11 | import com.baidu.beidou.navi.pbrpc.demo.proto.Demo.DemoResponse; 12 | import com.baidu.beidou.navi.pbrpc.demo.proto.Demo.DemoText; 13 | import com.baidu.beidou.navi.pbrpc.demo.service.DemoService; 14 | 15 | /** 16 | * ClassName: DemoServiceImpl
17 | * Function: demo服务端 18 | * 19 | * @author Zhang Xu 20 | */ 21 | public class DemoServiceImpl implements DemoService { 22 | 23 | /** 24 | * 默认返回,暂时无用 25 | */ 26 | @SuppressWarnings("unused") 27 | private static final User DEFAULT_USER = new User(1, "name-", User.Gender.MALE); 28 | 29 | /** 30 | * @see com.baidu.beidou.navi.pbrpc.demo.service.DemoService#doSmth(com.baidu.beidou.navi.pbrpc.demo.proto.Demo.DemoRequest) 31 | */ 32 | @Override 33 | public DemoResponse doSmth(DemoRequest req) { 34 | User user = cachedUsers.get(req.getUserId()); 35 | if (user == null) { 36 | throw new RuntimeException("User not found"); 37 | } 38 | DemoResponse.Builder builder = DemoResponse.newBuilder(); 39 | builder.setUserId(user.getUserId()); 40 | builder.setUserName(user.getUserName()); 41 | if (user.getGender().equals(User.Gender.MALE)) { 42 | builder.setGenderType(DemoResponse.GenderType.MALE); 43 | } else { 44 | builder.setGenderType(DemoResponse.GenderType.FEMALE); 45 | } 46 | return builder.build(); 47 | } 48 | 49 | @Override 50 | public DemoResponse doSmthTimeout(DemoRequest req) { 51 | try { 52 | Thread.sleep(10000); 53 | } catch (Exception e) { 54 | // TODO: handle exception 55 | } 56 | return doSmth(req); 57 | } 58 | 59 | /** 60 | * @see com.baidu.beidou.navi.pbrpc.demo.service.DemoService#doSmthBatch(com.baidu.beidou.navi.pbrpc.demo.proto.Demo.DemoBatchRequest) 61 | */ 62 | @Override 63 | public DemoBatchResponse doSmthBatch(DemoBatchRequest req) { 64 | int requestSize = req.getRequestSize(); 65 | DemoBatchResponse.Builder builder = DemoBatchResponse.newBuilder(); 66 | List list = new ArrayList(requestSize); 67 | for (int i = 0; i < requestSize; i++) { 68 | DemoText.Builder demoText = DemoText.newBuilder(); 69 | demoText.setText(req.getText()); 70 | list.add(demoText.build()); 71 | } 72 | builder.addAllTexts(list); 73 | return builder.build(); 74 | } 75 | 76 | /** 77 | * 缓存的user列表 78 | */ 79 | private Map cachedUsers = new HashMap(); 80 | 81 | /** 82 | * 初始化 83 | */ 84 | { 85 | for (int i = 0; i < 10; i++) { 86 | User user = new User(i, "name-" + i, i % 2 == 0 ? User.Gender.MALE : User.Gender.FEMALE); 87 | cachedUsers.put(user.getUserId(), user); 88 | } 89 | } 90 | 91 | /** 92 | * ClassName: User
93 | * Function: 用户VO 94 | * 95 | * @author Zhang Xu 96 | */ 97 | static class User { 98 | 99 | /** 100 | * userid 101 | */ 102 | private int userId; 103 | 104 | /** 105 | * username 106 | */ 107 | private String userName; 108 | 109 | /** 110 | * 性别 111 | */ 112 | private Gender gender; 113 | 114 | /** 115 | * Creates a new instance of User. 116 | * 117 | * @param userId 118 | * @param userName 119 | * @param gender 120 | */ 121 | public User(int userId, String userName, Gender gender) { 122 | super(); 123 | this.userId = userId; 124 | this.userName = userName; 125 | this.gender = gender; 126 | } 127 | 128 | /** 129 | * 性别枚举 130 | */ 131 | public static enum Gender { 132 | MALE, FEMALE; 133 | } 134 | 135 | public int getUserId() { 136 | return userId; 137 | } 138 | 139 | public void setUserId(int userId) { 140 | this.userId = userId; 141 | } 142 | 143 | public String getUserName() { 144 | return userName; 145 | } 146 | 147 | public void setUserName(String userName) { 148 | this.userName = userName; 149 | } 150 | 151 | public Gender getGender() { 152 | return gender; 153 | } 154 | 155 | public void setGender(Gender gender) { 156 | this.gender = gender; 157 | } 158 | 159 | } 160 | 161 | } 162 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/transport/PbrpcMsg.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.transport; 2 | 3 | import com.baidu.beidou.navi.pbrpc.error.ErrorCode; 4 | import com.baidu.beidou.navi.pbrpc.protocol.NsHead; 5 | 6 | /** 7 | * ClassName: PbrpcMsg
8 | * Function: 使用Protobuf做序列化协议的消息VO类,仅用于服务端或者客户端的内存中使用,不会真正用于序列化使用 9 | *

10 | * 一个传输包包含的Header+body两部分,目前header采用NsHead来做,body采用Protobuf协议序列化的字节码 11 | *

12 | * 示意如下: 该类作为服务端和客户端的在内存中使用的VO类,包含了一些最基本的信息,服务端路由的service标示,客户端调用来的logId用于tracing使用,以及最基本的序列化后的数据。 13 | * 14 | *

 15 |  *       Byte/     0       |       1       |       2       |       3       |
 16 |  *          /              |               |               |               |
 17 |  *         |0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
 18 |  *         +---------------+---------------+---------------+---------------+
 19 |  *        0/ NSHEAD HEADER                                                 /
 20 |  *         /                                                               /
 21 |  *         /                                                               /
 22 |  *         /                                                               /
 23 |  *         +---------------+---------------+---------------+---------------+
 24 |  *       36/ serialized protobuf message                                   /
 25 |  *        +/  (note length in the header body length field)                /
 26 |  *         +---------------+---------------+---------------+---------------+
 27 |  * 
28 | * 29 | * @author Zhang Xu 30 | */ 31 | public class PbrpcMsg { 32 | 33 | /** 34 | * 服务的标识id,一般客户端需要制定该id,服务端可以利用这个id路由到某个方法上调用。
35 | * 实际就是{@link NsHead}头中methodId,用于在服务端和客户端传递 36 | */ 37 | private int serviceId; 38 | 39 | /** 40 | * 服务上下文logId,用于tracing使用。
41 | * 实际就是{@link NsHead}头中logId,用于在服务端和客户端传递 42 | */ 43 | private long logId; 44 | 45 | /** 46 | * 调用提供者,类似于appid。
47 | * 实际就是{@link NsHead}头中provider,用于在服务端和客户端传递 48 | */ 49 | private String provider; 50 | 51 | /** 52 | * 一些不关业务逻辑处理的errorCode,由框架负责处理标示,发送请求时候请无设置该值 53 | */ 54 | private ErrorCode errorCode; 55 | 56 | /** 57 | * 传输的经过protobuf序列化的字节码 58 | */ 59 | private byte[] data; 60 | 61 | /** 62 | * @see java.lang.Object#toString() 63 | */ 64 | @Override 65 | public String toString() { 66 | StringBuilder sb = new StringBuilder(); 67 | sb.append("PbrpcMsg[logId="); 68 | sb.append(logId); 69 | sb.append(", serviceId="); 70 | sb.append(serviceId); 71 | sb.append(", provider="); 72 | sb.append(provider); 73 | sb.append(", dataLength="); 74 | sb.append((data == null) ? 0 : data.length); 75 | if (errorCode != null) { 76 | sb.append(", errorCode="); 77 | sb.append(errorCode); 78 | } 79 | sb.append("]"); 80 | return sb.toString(); 81 | } 82 | 83 | /** 84 | * 根据NsHead构造 85 | * 86 | * @param nsHead 87 | * @return 88 | */ 89 | public static PbrpcMsg of(NsHead nsHead) { 90 | PbrpcMsg ret = new PbrpcMsg(); 91 | ret.setServiceId((int) nsHead.getMethodId()); 92 | ret.setLogId(nsHead.getLogId()); 93 | ret.setErrorCode(ErrorCode.get(nsHead.getFlags())); 94 | ret.setProvider(nsHead.getProvider()); 95 | return ret; 96 | } 97 | 98 | /** 99 | * 简单信息的拷贝复制,不拷贝字节码 100 | * 101 | * @param msg 102 | * @return 103 | */ 104 | public static PbrpcMsg copyLiteOf(PbrpcMsg msg) { 105 | PbrpcMsg ret = new PbrpcMsg(); 106 | ret.setLogId(msg.getLogId()); 107 | ret.setProvider(msg.getProvider()); 108 | ret.setServiceId(msg.getServiceId()); 109 | ret.setErrorCode(msg.getErrorCode()); 110 | return ret; 111 | } 112 | 113 | public ErrorCode getErrorCode() { 114 | return errorCode; 115 | } 116 | 117 | public PbrpcMsg setErrorCode(ErrorCode errorCode) { 118 | this.errorCode = errorCode; 119 | return this; 120 | } 121 | 122 | public int getServiceId() { 123 | return serviceId; 124 | } 125 | 126 | public PbrpcMsg setServiceId(int serviceId) { 127 | this.serviceId = serviceId; 128 | return this; 129 | } 130 | 131 | public byte[] getData() { 132 | return data; 133 | } 134 | 135 | public PbrpcMsg setData(byte[] data) { 136 | this.data = data; 137 | return this; 138 | } 139 | 140 | public long getLogId() { 141 | return logId; 142 | } 143 | 144 | public PbrpcMsg setLogId(long logId) { 145 | this.logId = logId; 146 | return this; 147 | } 148 | 149 | public String getProvider() { 150 | return provider; 151 | } 152 | 153 | public PbrpcMsg setProvider(String provider) { 154 | this.provider = provider; 155 | return this; 156 | } 157 | 158 | } 159 | -------------------------------------------------------------------------------- /src/main/java/com/baidu/beidou/navi/pbrpc/client/PooledPbrpcClient.java: -------------------------------------------------------------------------------- 1 | package com.baidu.beidou.navi.pbrpc.client; 2 | 3 | import io.netty.channel.ChannelFuture; 4 | 5 | import org.apache.commons.pool.impl.GenericObjectPool; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import com.baidu.beidou.navi.pbrpc.client.callback.CallFuture; 10 | import com.baidu.beidou.navi.pbrpc.exception.client.OperationNotSupportException; 11 | import com.baidu.beidou.navi.pbrpc.exception.client.PbrpcException; 12 | import com.baidu.beidou.navi.pbrpc.transport.PbrpcMsg; 13 | import com.google.protobuf.GeneratedMessage; 14 | 15 | /** 16 | * ClassName: PooledPbrpcClient
17 | * Function: 使用连接池技术的客户端 18 | * 19 | * @author Zhang Xu 20 | */ 21 | public class PooledPbrpcClient implements PbrpcClient { 22 | 23 | private static final Logger LOG = LoggerFactory.getLogger(PooledPbrpcClient.class); 24 | 25 | /** 26 | * socket连接池 27 | */ 28 | private PbrpcClientChannelPool channelPool; 29 | 30 | /** 31 | * 连接池配置 32 | */ 33 | private GenericObjectPool.Config pooledConfig; 34 | 35 | /** 36 | * 远程服务IP 37 | */ 38 | private String ip; 39 | 40 | /** 41 | * 远程服务端口 42 | */ 43 | private int port; 44 | 45 | /** 46 | * 客户端连接超时,单位毫秒 47 | */ 48 | private int connTimeout; 49 | 50 | /** 51 | * 客户端调用超时,单位毫秒 52 | */ 53 | private int readTimeout; 54 | 55 | public PooledPbrpcClient() { 56 | } 57 | 58 | /** 59 | * Creates a new instance of PooledPbrpcClient. 60 | * 61 | * @param configuration 62 | * 连接池配置 63 | * @param clientConfig 64 | * 客户端配置 65 | * @param ip 66 | * socket远程ip 67 | * @param port 68 | * socket远程端口 69 | * @param connTimeout 70 | * 客户端连接时间,单位为毫秒 71 | * @param readTimeout 72 | * 客户端调用的超时时间,单位为毫秒,超时则会抛出{@link com.baidu.beidou.navi.pbrpc.exception.TimeoutException} 73 | */ 74 | public PooledPbrpcClient(PooledConfiguration configuration, 75 | PbrpcClientConfiguration clientConfig, String ip, int port, int connTimeout, 76 | int readTimeout) { 77 | this.pooledConfig = configuration.getPoolConfig(); 78 | this.ip = ip; 79 | this.port = port; 80 | this.connTimeout = connTimeout; 81 | this.readTimeout = readTimeout; 82 | channelPool = new PbrpcClientChannelPool(pooledConfig, clientConfig, ip, port, connTimeout, 83 | readTimeout); 84 | } 85 | 86 | /** 87 | * @see com.baidu.beidou.navi.pbrpc.client.PbrpcClient#asyncTransport(java.lang.Class, 88 | * com.baidu.beidou.navi.pbrpc.transport.PbrpcMsg) 89 | */ 90 | @Override 91 | public CallFuture asyncTransport(Class responseClazz, 92 | PbrpcMsg pbrpcMsg) { 93 | PbrpcClientChannel channel = channelPool.getResource(); 94 | try { 95 | CallFuture res = channel.asyncTransport(responseClazz, pbrpcMsg, this.readTimeout); 96 | return res; 97 | } catch (Exception e) { 98 | LOG.error("asyncTransport failed, " + e.getMessage(), e); 99 | channelPool.returnBrokenResource(channel); 100 | throw new PbrpcException("Pbrpc invocation failed on " + getInfo() + ", " 101 | + e.getMessage(), e); 102 | } finally { 103 | channelPool.returnResource(channel); 104 | } 105 | } 106 | 107 | /** 108 | * @see com.baidu.beidou.navi.pbrpc.client.PbrpcClient#syncTransport(java.lang.Class, 109 | * com.baidu.beidou.navi.pbrpc.transport.PbrpcMsg) 110 | */ 111 | @Override 112 | public T syncTransport(Class responseClazz, PbrpcMsg pbrpcMsg) { 113 | try { 114 | CallFuture future = asyncTransport(responseClazz, pbrpcMsg); 115 | if (future != null) { 116 | return future.get(); 117 | } 118 | return null; 119 | } catch (PbrpcException e) { 120 | throw e; 121 | } catch (InterruptedException e) { 122 | throw new PbrpcException("Pbrpc invocation failed on " + getInfo() + ", " 123 | + e.getMessage(), e); 124 | } 125 | } 126 | 127 | /** 128 | * @see com.baidu.beidou.navi.pbrpc.client.PbrpcClient#connect() 129 | */ 130 | @Override 131 | public ChannelFuture connect() { 132 | throw new OperationNotSupportException(); 133 | } 134 | 135 | /** 136 | * @see com.baidu.beidou.navi.pbrpc.client.PbrpcClient#shutdown() 137 | */ 138 | @Override 139 | public void shutdown() { 140 | channelPool.destroy(); 141 | } 142 | 143 | /** 144 | * @see com.baidu.beidou.navi.pbrpc.client.PbrpcClient#getInfo() 145 | */ 146 | @Override 147 | public String getInfo() { 148 | return ip + ":" + port + ", connTimeout=" + connTimeout + ", readTimeout=" + readTimeout; 149 | } 150 | 151 | } 152 | --------------------------------------------------------------------------------