├── .gitattributes ├── .gitignore ├── .travis.yml ├── LICENSE ├── client ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── colobu │ │ │ └── rpcx │ │ │ └── client │ │ │ ├── Callable.java │ │ │ ├── NettyClient.java │ │ │ ├── Selector.java │ │ │ ├── ServiceAddr.java │ │ │ ├── ZkServiceDiscovery.java │ │ │ ├── http │ │ │ └── RpcxHttpClient.java │ │ │ └── impl │ │ │ └── RandomSelector.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── colobu │ └── rpcx │ └── client │ ├── NettyClientTest.java │ ├── RpcxHttpClientTest.java │ ├── SelectorTest.java │ └── ServiceDiscoveryTest.java ├── common ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── colobu │ │ │ └── rpcx │ │ │ ├── cache │ │ │ ├── AbstractCacheFactory.java │ │ │ ├── Cache.java │ │ │ ├── CacheFactory.java │ │ │ ├── LruCacheFactory.java │ │ │ └── impl │ │ │ │ └── LruCache.java │ │ │ ├── common │ │ │ ├── Bytes.java │ │ │ ├── ClassPathResource.java │ │ │ ├── ClassUtils.java │ │ │ ├── CollectionUtils.java │ │ │ ├── Config.java │ │ │ ├── InvokeCallback.java │ │ │ ├── NamedThreadFactory.java │ │ │ ├── NetUtils.java │ │ │ ├── Pair.java │ │ │ ├── RemotingHelper.java │ │ │ ├── RemotingUtil.java │ │ │ ├── RpcxVersion.java │ │ │ ├── SemaphoreReleaseOnlyOnce.java │ │ │ ├── StringUtils.java │ │ │ └── retry │ │ │ │ ├── RetryNTimes.java │ │ │ │ └── RetryPolicy.java │ │ │ ├── concurrent │ │ │ └── ConcurrentHashSet.java │ │ │ ├── config │ │ │ ├── Constants.java │ │ │ ├── NettyClientConfig.java │ │ │ └── RpcxConfig.java │ │ │ ├── deploy │ │ │ └── AgentLoader.java │ │ │ ├── discovery │ │ │ └── IServiceDiscovery.java │ │ │ ├── exception │ │ │ ├── RemotingException.java │ │ │ ├── RemotingSendRequestException.java │ │ │ ├── RemotingTimeoutException.java │ │ │ └── RemotingTooMuchRequestException.java │ │ │ ├── fail │ │ │ └── FailType.java │ │ │ ├── filter │ │ │ ├── Filter.java │ │ │ ├── FilterWrapper.java │ │ │ └── impl │ │ │ │ ├── AccessLogFilter.java │ │ │ │ ├── CacheFilter.java │ │ │ │ ├── ConsumerContextFilter.java │ │ │ │ ├── ConsumerTraceidFilter.java │ │ │ │ ├── ContextFilter.java │ │ │ │ ├── EchoFilter.java │ │ │ │ ├── ExceptionFilter.java │ │ │ │ ├── FailFilter.java │ │ │ │ ├── GenericFilter.java │ │ │ │ ├── HotDeployFilter.java │ │ │ │ ├── MonitorFilter.java │ │ │ │ ├── SelectorFilter.java │ │ │ │ ├── TimeoutFilter.java │ │ │ │ ├── TokenFilter.java │ │ │ │ ├── TpsLimitFilter.java │ │ │ │ └── TraceidFilter.java │ │ │ ├── io │ │ │ └── UnsafeStringWriter.java │ │ │ ├── monitor │ │ │ ├── Monitor.java │ │ │ ├── MonitorFactory.java │ │ │ ├── MonitorService.java │ │ │ └── impl │ │ │ │ ├── RpcxMonitor.java │ │ │ │ └── Statistics.java │ │ │ ├── netty │ │ │ ├── ChannelEventListener.java │ │ │ ├── ChannelWrapper.java │ │ │ ├── ClientChannelEventListener.java │ │ │ ├── DecoderState.java │ │ │ ├── IClient.java │ │ │ ├── NettyClientHandler.java │ │ │ ├── NettyConnetManageHandler.java │ │ │ ├── NettyDecoder.java │ │ │ ├── NettyEncoder.java │ │ │ ├── NettyEvent.java │ │ │ ├── NettyEventExecuter.java │ │ │ ├── NettyEventType.java │ │ │ ├── NettyRemotingAbstract.java │ │ │ ├── NettyRequestProcessor.java │ │ │ ├── NettyServerConfig.java │ │ │ ├── NettyServerHandler.java │ │ │ ├── RequestTask.java │ │ │ └── ResponseFuture.java │ │ │ ├── protocol │ │ │ ├── CommandCustomHeader.java │ │ │ ├── CompressType.java │ │ │ ├── DefaultCommandHeader.java │ │ │ ├── LanguageCode.java │ │ │ ├── Message.java │ │ │ ├── MessageStatusType.java │ │ │ ├── MessageType.java │ │ │ ├── RemotingCommand.java │ │ │ ├── RemotingCommandType.java │ │ │ ├── RemotingSysResponseCode.java │ │ │ └── SerializeType.java │ │ │ ├── register │ │ │ └── IServiceRegister.java │ │ │ ├── rpc │ │ │ ├── CglibProxy.java │ │ │ ├── ClassHelper.java │ │ │ ├── HessianUtils.java │ │ │ ├── Invocation.java │ │ │ ├── Invoker.java │ │ │ ├── Node.java │ │ │ ├── Protocol.java │ │ │ ├── ReflectUtils.java │ │ │ ├── Result.java │ │ │ ├── RpcContext.java │ │ │ ├── RpcException.java │ │ │ ├── URL.java │ │ │ ├── annotation │ │ │ │ ├── Consumer.java │ │ │ │ ├── Provider.java │ │ │ │ └── RpcFilter.java │ │ │ └── impl │ │ │ │ ├── ConsumerConfig.java │ │ │ │ ├── ConsumerFinder.java │ │ │ │ ├── Exporter.java │ │ │ │ ├── ProviderFinder.java │ │ │ │ ├── RpcConsumerInvoker.java │ │ │ │ ├── RpcFilterFinder.java │ │ │ │ ├── RpcInvocation.java │ │ │ │ ├── RpcProviderInvoker.java │ │ │ │ └── RpcResult.java │ │ │ ├── selector │ │ │ ├── SelectMode.java │ │ │ ├── Weighted.java │ │ │ └── WeightedRountRobin.java │ │ │ ├── tps │ │ │ ├── DefaultTPSLimiter.java │ │ │ ├── StatItem.java │ │ │ └── TPSLimiter.java │ │ │ └── utils │ │ │ ├── PathStatus.java │ │ │ └── ZkClient.java │ └── resources │ │ ├── application.properties │ │ └── test │ └── test │ └── java │ └── com │ └── colobu │ └── rpcx │ ├── common │ ├── CommonTest.java │ ├── TestPoolFactory.java │ ├── WeightedRountRobinTest.java │ └── YamlTest.java │ ├── filter │ └── FilterTest.java │ ├── protocol │ └── MessageTest.java │ ├── rpc │ ├── A.java │ ├── ExporterTest.java │ ├── IA.java │ ├── ProxyTest.java │ └── ReflectUtilsTest.java │ ├── url │ └── URLTest.java │ └── utils │ └── ZkClientTest.java ├── container ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── colobu │ │ └── rpcx │ │ └── spring │ │ ├── RpcxAutoConfigure.java │ │ └── RpcxConsumer.java │ └── resources │ └── META-INF │ └── spring.factories ├── demo ├── api │ ├── pom.xml │ └── src │ │ └── main │ │ └── java │ │ └── com │ │ └── colobu │ │ └── rpcx │ │ └── service │ │ ├── DemoService.java │ │ ├── IArith.java │ │ ├── ITest2Service.java │ │ └── ITestService.java ├── demmoserver │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ ├── colobu │ │ │ │ └── rpcx │ │ │ │ │ ├── bootstrap │ │ │ │ │ └── Bootstrap.java │ │ │ │ │ ├── config │ │ │ │ │ └── ConsumerConfig.java │ │ │ │ │ ├── demo │ │ │ │ │ └── Server.java │ │ │ │ │ └── service │ │ │ │ │ ├── Arith.java │ │ │ │ │ ├── DemoServiceImpl.java │ │ │ │ │ └── TestService.java │ │ │ │ └── demo │ │ │ │ └── filter │ │ │ │ └── DemoFilter.java │ │ └── resources │ │ │ ├── application.yaml │ │ │ └── logback.xml │ │ └── test │ │ └── java │ │ └── com │ │ └── colobu │ │ └── rpcx │ │ └── rpc │ │ └── test │ │ └── ExporterTest.java ├── democlient │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ ├── colobu │ │ │ │ └── rpcx │ │ │ │ │ ├── bootstrap │ │ │ │ │ └── Bootstrap.java │ │ │ │ │ ├── config │ │ │ │ │ └── ConsumerConfig.java │ │ │ │ │ ├── demo │ │ │ │ │ └── Client.java │ │ │ │ │ └── handler │ │ │ │ │ └── TestController.java │ │ │ │ └── demo │ │ │ │ └── client │ │ │ │ └── filter │ │ │ │ └── DemoClientFilter.java │ │ └── resources │ │ │ ├── application.properties │ │ │ ├── client │ │ │ └── nodejs │ │ │ │ └── client.js │ │ │ └── logback.xml │ │ └── test │ │ └── java │ │ └── com │ │ └── colobu │ │ └── rpcx │ │ └── test │ │ └── ClientTest.java ├── demoserver2 │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── colobu │ │ │ └── rpcx │ │ │ ├── bootstrap │ │ │ └── Server2Bootstrap.java │ │ │ └── service │ │ │ └── Test2Service.java │ │ └── resources │ │ ├── application.yaml │ │ └── logback.xml └── pom.xml ├── pom.xml ├── readme.md └── server ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── colobu │ │ └── rpcx │ │ ├── handler │ │ ├── RpcxHttpHandler.java │ │ └── RpcxProcessHandler.java │ │ ├── processor │ │ ├── RpcHttpProcessor.java │ │ └── RpcProcessor.java │ │ └── server │ │ ├── NettyServer.java │ │ └── ZkServiceRegister.java └── resources │ └── logback.xml └── test └── java └── com └── colobu └── rpcx └── server └── NettyServerTest.java /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Known text files 5 | *.css text diff=css 6 | *.java text diff=java 7 | *.js text 8 | *.json text 9 | *.jsp text 10 | *.jspf text 11 | *.jspx text 12 | *.htm text diff=html 13 | *.html text diff=html 14 | *.properties text 15 | *.sh text 16 | *.md text 17 | *.txt text 18 | *.xml text 19 | *.yml text 20 | 21 | # Known binary files 22 | *.class binary 23 | *.gif binary 24 | *.ico binary 25 | *.jar binary 26 | *.jpg binary 27 | *.jpeg binary 28 | *.png binary 29 | *.war binary 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Git folder # 2 | /.git/ 3 | 4 | # Compilation folders # 5 | /bin/ 6 | /target/ 7 | /build/ 8 | /common/target/ 9 | /client/target/ 10 | /server/target/ 11 | /demo/api/target/ 12 | /demo/demmoserver/target/ 13 | /demo/democlient/target/ 14 | /demo/democlient/logs/ 15 | /demo/logs/ 16 | /container/target/ 17 | /logs/ 18 | /server/logs/ 19 | /demo/demmoserver/logs/ 20 | 21 | # Java compile files # 22 | *.class 23 | 24 | # Package files # 25 | *.jar 26 | *.war 27 | *.ear 28 | *.db 29 | 30 | # Log files # 31 | /*.log 32 | /*.log.* 33 | 34 | # Output folders # 35 | /test-output/ 36 | 37 | # Eclipse files # 38 | .buildpath 39 | .classpath 40 | .cproject 41 | .externalToolBuilders/ 42 | .launch 43 | .loadpath 44 | .metadata 45 | .project 46 | .settings/ 47 | bin/** 48 | tmp/** 49 | tmp/**/* 50 | *.tmp 51 | *.nak 52 | *.swp 53 | *~.nib 54 | *.pydevproject 55 | local.properties 56 | /src/main/resources/rebel.xml 57 | .springBeans 58 | 59 | # IntelliJ Idea files # 60 | .idea 61 | *.iml 62 | 63 | # Windows files # 64 | Thumbs.db 65 | Desktop.ini 66 | 67 | # OS files # 68 | .DS_Store 69 | .svn 70 | ._* 71 | .Spotlight-V100 72 | .Trashes 73 | .idea 74 | *.iml 75 | pom.xml.releaseBackup 76 | release.properties 77 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Travis CI Configuration file 2 | # @link https://travis-ci.org/ 3 | 4 | # Using Java for the project 5 | language: java 6 | jdk: 7 | - oraclejdk8 8 | # - oraclejdk9 9 | 10 | script: 11 | # Unit and integration tests are run 12 | - mvn clean verify cobertura:cobertura 13 | 14 | after_success: 15 | - bash <(curl -s https://codecov.io/bash) 16 | 17 | -------------------------------------------------------------------------------- /client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.colobu 8 | client 9 | 1.3-SNAPSHOT 10 | 11 | 12 | 1.3-SNAPSHOT 13 | 14 | 15 | 16 | 17 | 18 | com.colobu 19 | common 20 | ${rpcx.version} 21 | 22 | 23 | 24 | 25 | junit 26 | junit 27 | 4.13.1 28 | test 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | org.apache.maven.plugins 38 | maven-compiler-plugin 39 | 3.1 40 | 41 | 1.8 42 | 1.8 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /client/src/main/java/com/colobu/rpcx/client/Callable.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.client; 2 | 3 | import com.colobu.rpcx.protocol.Message; 4 | 5 | /** 6 | * Created by goodjava@qq.com. 7 | */ 8 | public interface Callable { 9 | void call(Message msg); 10 | } 11 | -------------------------------------------------------------------------------- /client/src/main/java/com/colobu/rpcx/client/Selector.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.client; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Created by goodjava@qq.com. 7 | */ 8 | public interface Selector { 9 | 10 | 11 | String select(String servicePath, String serviceMethod, List serviceList); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /client/src/main/java/com/colobu/rpcx/client/ServiceAddr.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.client; 2 | 3 | /** 4 | * Created by goodjava@qq.com. 5 | */ 6 | public class ServiceAddr { 7 | 8 | 9 | } 10 | -------------------------------------------------------------------------------- /client/src/main/java/com/colobu/rpcx/client/http/RpcxHttpClient.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.client.http; 2 | 3 | import com.colobu.rpcx.common.Pair; 4 | import com.colobu.rpcx.protocol.Message; 5 | import com.colobu.rpcx.rpc.Invocation; 6 | import com.colobu.rpcx.rpc.RpcException; 7 | import com.colobu.rpcx.rpc.URL; 8 | import com.colobu.rpcx.rpc.impl.RpcInvocation; 9 | import com.google.gson.Gson; 10 | import org.apache.http.HttpEntity; 11 | import org.apache.http.HttpResponse; 12 | import org.apache.http.client.config.RequestConfig; 13 | import org.apache.http.client.methods.HttpPost; 14 | import org.apache.http.entity.ByteArrayEntity; 15 | import org.apache.http.entity.ContentType; 16 | import org.apache.http.impl.client.CloseableHttpClient; 17 | import org.apache.http.impl.client.HttpClients; 18 | import org.apache.http.util.EntityUtils; 19 | import org.slf4j.Logger; 20 | import org.slf4j.LoggerFactory; 21 | 22 | import java.util.stream.Collectors; 23 | import java.util.stream.IntStream; 24 | import java.util.stream.Stream; 25 | 26 | /** 27 | * @author goodjava@qq.com 28 | */ 29 | public class RpcxHttpClient { 30 | 31 | private static final Logger logger = LoggerFactory.getLogger(RpcxHttpClient.class); 32 | 33 | /** 34 | * http 调用 35 | * 36 | * @param url 37 | * @param service 38 | * @param method 39 | * @param params key=类型 value=json后的值 40 | * @return 41 | */ 42 | public static String execute(String url, String service, String method, Pair... params) { 43 | RequestConfig defaultRequestConfig = RequestConfig.custom() 44 | .setSocketTimeout(1000) 45 | .setConnectTimeout(1000) 46 | .setConnectionRequestTimeout(1000) 47 | .build(); 48 | 49 | try (CloseableHttpClient client = HttpClients.custom().setDefaultRequestConfig(defaultRequestConfig).build()) { 50 | HttpPost post = new HttpPost(url); 51 | post.setHeader("X-RPCX-ServicePath", service); 52 | post.setHeader("X-RPCX-ServiceMethod", method); 53 | post.setHeader("connection", "close"); 54 | 55 | Gson gson = new Gson(); 56 | Invocation invocation = new RpcInvocation(); 57 | String[] parameterTypeNames = new String[params.length]; 58 | Object[] arguments = new Object[params.length]; 59 | IntStream.range(0, params.length).forEach(index -> { 60 | Pair p = params[index]; 61 | parameterTypeNames[index] = p.getObject1(); 62 | arguments[index] = p.getObject2(); 63 | }); 64 | 65 | invocation.setParameterTypeNames(parameterTypeNames); 66 | invocation.setArguments(arguments); 67 | 68 | URL u = new URL("rpcx", "", 0); 69 | 70 | ((RpcInvocation) invocation).setClassName(service); 71 | ((RpcInvocation) invocation).setMethodName(method); 72 | 73 | u.setServiceInterface(invocation.getClassName() + "." + invocation.getMethodName()); 74 | String _params = Stream.of(invocation.getArguments()).map(it -> gson.toJson(it)).collect(Collectors.joining(",")); 75 | u.setPath(invocation.getClassName() + "." + invocation.getMethodName() + "(" + _params + ")"); 76 | ((RpcInvocation) invocation).setUrl(u); 77 | 78 | byte[] payload = new Gson().toJson(invocation).getBytes(); 79 | 80 | ByteArrayEntity entriy = new ByteArrayEntity(payload, ContentType.DEFAULT_BINARY); 81 | post.setEntity(entriy); 82 | HttpResponse res = client.execute(post); 83 | HttpEntity resEntity = res.getEntity(); 84 | byte[] data = EntityUtils.toByteArray(resEntity); 85 | Message message = gson.fromJson(new String(data), Message.class); 86 | return new String(message.payload); 87 | } catch (Exception ex) { 88 | logger.info("execute error:{}", ex.getMessage()); 89 | throw new RpcException(ex); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /client/src/main/java/com/colobu/rpcx/client/impl/RandomSelector.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.client.impl; 2 | 3 | import com.colobu.rpcx.client.Selector; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.util.List; 8 | import java.util.Random; 9 | 10 | /** 11 | * Created by goodjava@qq.com. 12 | */ 13 | public class RandomSelector implements Selector { 14 | 15 | private static final Logger logger = LoggerFactory.getLogger(RandomSelector.class); 16 | 17 | @Override 18 | public String select(String servicePath, String serviceMethod, List list) { 19 | if (list.size() > 0) { 20 | Random random = new Random(); 21 | int i = random.nextInt(list.size()); 22 | String addr = list.get(i); 23 | logger.info("random select addr:{}", addr); 24 | return addr; 25 | } 26 | return null; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /client/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.type=dev 2 | server.port=8010 3 | server.debug=true 4 | spring.main.banner-mode=off 5 | 6 | #rpcx 7 | rpcx.package.path=com.colobu 8 | rpcx.base.path=/youpin/services/ 9 | zk.connect.string=127.0.0.1:2181 10 | 11 | rpcx_filter_package=com.demo.client.filter 12 | 13 | 14 | rpcx_port=8028 15 | -------------------------------------------------------------------------------- /client/src/test/java/com/colobu/rpcx/client/NettyClientTest.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.client; 2 | 3 | import com.colobu.rpcx.config.Constants; 4 | import com.colobu.rpcx.filter.FilterWrapper; 5 | import com.colobu.rpcx.protocol.*; 6 | import com.colobu.rpcx.rpc.Invoker; 7 | import com.colobu.rpcx.rpc.Result; 8 | import com.colobu.rpcx.rpc.URL; 9 | import com.colobu.rpcx.rpc.impl.RpcConsumerInvoker; 10 | import com.colobu.rpcx.rpc.impl.RpcInvocation; 11 | import com.google.common.collect.Maps; 12 | import com.google.common.collect.Sets; 13 | import org.junit.Test; 14 | 15 | import java.util.stream.IntStream; 16 | 17 | /** 18 | * Created by zhangzhiyong on 2018/7/3. 19 | */ 20 | public class NettyClientTest { 21 | 22 | 23 | /** 24 | * 调用golang 并且使用filter增强 25 | */ 26 | @Test 27 | public void testCallGolang() { 28 | ZkServiceDiscovery serviceDiscovery = new ZkServiceDiscovery("/youpin/services/", "Arith"); 29 | NettyClient client = new NettyClient(serviceDiscovery); 30 | Invoker invoker = new RpcConsumerInvoker(client); 31 | Invoker wrapperInvoker = FilterWrapper.ins().buildInvokerChain(invoker, "", Constants.CONSUMER, Sets.newHashSet()); 32 | 33 | RpcInvocation invocation = new RpcInvocation(); 34 | invocation.setMethodName("Echo"); 35 | invocation.setClassName("Arith"); 36 | invocation.setLanguageCode(LanguageCode.GO); 37 | invocation.setPayload("zzy".getBytes()); 38 | invocation.setUrl(new URL("rpcx", "", 0)); 39 | invocation.setSerializeType(SerializeType.SerializeNone); 40 | 41 | Result result = wrapperInvoker.invoke(invocation); 42 | 43 | if (!result.hasException()) { 44 | System.out.println(new String((byte[]) (result.getValue()))); 45 | } else { 46 | result.getException().printStackTrace(); 47 | } 48 | } 49 | 50 | 51 | /** 52 | * 直连 53 | * 54 | * @throws Exception 55 | */ 56 | @Test 57 | public void testSendMsg() throws Exception { 58 | Message req = new Message("Arith", "Echo"); 59 | req.setVersion((byte) 0); 60 | req.setMessageType(MessageType.Request); 61 | req.setHeartbeat(false); 62 | req.setOneway(false); 63 | req.setCompressType(CompressType.None); 64 | req.setSerializeType(SerializeType.SerializeNone); 65 | req.setSeq(123); 66 | req.metadata.put("test", "1234"); 67 | req.payload = "world".getBytes("UTF-8"); 68 | 69 | NettyClient client = new NettyClient(null); 70 | Message res = client.call("192.168.31.82:8997", req, 1000); 71 | System.out.println(new String(res.payload)); 72 | } 73 | 74 | //经过服务发现 75 | @Test 76 | public void testGolangServiceFinder() throws Exception { 77 | Message req = new Message("Arith", "Echo"); 78 | req.setVersion((byte) 0); 79 | req.setMessageType(MessageType.Request); 80 | req.setHeartbeat(false); 81 | req.setOneway(false); 82 | req.setCompressType(CompressType.None); 83 | req.setSerializeType(SerializeType.SerializeNone); 84 | req.setSeq(123); 85 | req.metadata.put("test", "1234"); 86 | req.payload = "world".getBytes("UTF-8"); 87 | 88 | ZkServiceDiscovery serviceDiscovery = new ZkServiceDiscovery("/youpin/services/", "Arith");//发现golang的服务 89 | NettyClient client = new NettyClient(serviceDiscovery); 90 | Message res = client.call(req, 2000, Constants.SYNC_KEY); 91 | System.out.println(new String(res.payload)); 92 | } 93 | 94 | 95 | //测试循环发送消息 96 | @Test 97 | public void testLoopSendMsg() throws Exception { 98 | Message req = new Message("Arith", "Echo"); 99 | req.setVersion((byte) 0); 100 | req.setMessageType(MessageType.Request); 101 | req.setHeartbeat(false); 102 | req.setOneway(false); 103 | req.setCompressType(CompressType.None); 104 | req.setSerializeType(SerializeType.SerializeNone); 105 | req.setSeq(123); 106 | req.metadata.put("test", "1234"); 107 | req.payload = "world".getBytes("UTF-8"); 108 | 109 | NettyClient client = new NettyClient(null); 110 | IntStream.range(0, 100).forEach(it -> { 111 | Message res = null; 112 | try { 113 | res = client.call("10.231.72.75:8976", req, 1000); 114 | } catch (Exception e) { 115 | e.printStackTrace(); 116 | } 117 | System.out.println(new String(res.payload)); 118 | }); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /client/src/test/java/com/colobu/rpcx/client/RpcxHttpClientTest.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.client; 2 | 3 | import com.colobu.rpcx.client.http.RpcxHttpClient; 4 | import com.colobu.rpcx.common.Pair; 5 | import org.junit.Test; 6 | 7 | public class RpcxHttpClientTest { 8 | 9 | 10 | @Test 11 | public void testExecute() { 12 | String res = RpcxHttpClient.execute("http://10.231.39.214:8033/", "com.colobu.rpcx.service.TestService", "sum", Pair.of("int", "11"), Pair.of("int", "22")); 13 | System.out.println(res); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /client/src/test/java/com/colobu/rpcx/client/SelectorTest.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.client; 2 | 3 | import com.colobu.rpcx.client.impl.RandomSelector; 4 | import org.junit.Test; 5 | 6 | /** 7 | * Created by zhangzhiyong on 2018/7/4. 8 | */ 9 | public class SelectorTest { 10 | 11 | 12 | @Test 13 | public void testRandomSelector() { 14 | System.out.println(new RandomSelector().select("","", null)); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /client/src/test/java/com/colobu/rpcx/client/ServiceDiscoveryTest.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.client; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.concurrent.TimeUnit; 6 | 7 | /** 8 | * Created by zhangzhiyong on 2018/7/4. 9 | */ 10 | public class ServiceDiscoveryTest { 11 | 12 | 13 | @Test 14 | public void testWatch() throws Exception { 15 | new ZkServiceDiscovery("","").watch(); 16 | TimeUnit.HOURS.sleep(1); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/cache/AbstractCacheFactory.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.cache; 2 | 3 | 4 | import com.colobu.rpcx.rpc.URL; 5 | 6 | import java.util.concurrent.ConcurrentHashMap; 7 | import java.util.concurrent.ConcurrentMap; 8 | 9 | /** 10 | * @author goodjava@qq.com 11 | */ 12 | public abstract class AbstractCacheFactory implements CacheFactory { 13 | 14 | private final ConcurrentMap caches = new ConcurrentHashMap(); 15 | 16 | @Override 17 | public Cache getCache(URL url) { 18 | String key = url.toFullString(); 19 | Cache cache = caches.get(key); 20 | if (cache == null) { 21 | caches.put(key, createCache(url)); 22 | cache = caches.get(key); 23 | } 24 | return cache; 25 | } 26 | 27 | protected abstract Cache createCache(URL url); 28 | 29 | } 30 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/cache/Cache.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.cache; 2 | 3 | /** 4 | * @author goodjava@qq.com 5 | */ 6 | public interface Cache { 7 | 8 | void put(Object key, Object value); 9 | 10 | Object get(Object key); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/cache/CacheFactory.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.cache; 2 | 3 | 4 | import com.colobu.rpcx.rpc.URL; 5 | 6 | /** 7 | * @author goodjava@qq.com 8 | */ 9 | public interface CacheFactory { 10 | 11 | Cache getCache(URL url); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/cache/LruCacheFactory.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.cache; 2 | 3 | 4 | import com.colobu.rpcx.cache.impl.LruCache; 5 | import com.colobu.rpcx.rpc.URL; 6 | 7 | /** 8 | * @author goodjava@qq.com 9 | */ 10 | public class LruCacheFactory extends AbstractCacheFactory { 11 | 12 | @Override 13 | protected Cache createCache(URL url) { 14 | return new LruCache(); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/cache/impl/LruCache.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.cache.impl; 2 | 3 | 4 | import com.colobu.rpcx.cache.Cache; 5 | 6 | import java.util.LinkedHashMap; 7 | import java.util.Map; 8 | import java.util.Map.Entry; 9 | 10 | /** 11 | * Created by goodjava@qq.com. 12 | */ 13 | public class LruCache implements Cache { 14 | 15 | private final Map store; 16 | 17 | public LruCache() { 18 | final int max = 1000; 19 | this.store = new LinkedHashMap() { 20 | private static final long serialVersionUID = -3834209229668463829L; 21 | @Override 22 | protected boolean removeEldestEntry(Entry eldest) { 23 | return size() > max; 24 | } 25 | }; 26 | } 27 | 28 | @Override 29 | public void put(Object key, Object value) { 30 | synchronized (store) { 31 | store.put(key, value); 32 | } 33 | } 34 | 35 | @Override 36 | public Object get(Object key) { 37 | synchronized (store) { 38 | return store.get(key); 39 | } 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/common/ClassPathResource.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.common; 2 | 3 | import com.google.common.io.ByteStreams; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.io.FileNotFoundException; 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | import java.util.Properties; 11 | 12 | /** 13 | * @author goodjava@qq.com 14 | */ 15 | public class ClassPathResource { 16 | 17 | private static final Logger logger = LoggerFactory.getLogger(ClassPathResource.class); 18 | 19 | private final String path; 20 | 21 | private ClassLoader classLoader; 22 | 23 | 24 | public ClassPathResource(String path) { 25 | this.path = path; 26 | this.classLoader = ClassUtils.getDefaultClassLoader(); 27 | } 28 | 29 | 30 | public InputStream getInputStream() { 31 | InputStream is; 32 | if (this.classLoader != null) { 33 | is = this.classLoader.getResourceAsStream(this.path); 34 | } else { 35 | is = ClassLoader.getSystemResourceAsStream(this.path); 36 | } 37 | if (is == null) { 38 | logger.warn("cannot be opened because it does not exist:{}", this.path); 39 | } 40 | return is; 41 | } 42 | 43 | 44 | public String getString() { 45 | try { 46 | InputStream is = getInputStream(); 47 | if (null == is) { 48 | return ""; 49 | } 50 | return new String(ByteStreams.toByteArray(is)); 51 | } catch (IOException e) { 52 | e.printStackTrace(); 53 | return ""; 54 | } 55 | } 56 | 57 | public Properties getProperties() { 58 | Properties prop = new Properties(); 59 | try { 60 | InputStream is = getInputStream(); 61 | if (null == is) { 62 | return prop; 63 | } 64 | prop.load(is); 65 | } catch (IOException e) { 66 | e.printStackTrace(); 67 | } 68 | return prop; 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/common/ClassUtils.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.common; 2 | 3 | import com.colobu.rpcx.rpc.ReflectUtils; 4 | 5 | import java.lang.reflect.Method; 6 | import java.util.Arrays; 7 | import java.util.stream.Collectors; 8 | import java.util.stream.Stream; 9 | 10 | /** 11 | * @author goodjava@qq.com 12 | */ 13 | public class ClassUtils { 14 | 15 | 16 | private ClassUtils() { 17 | 18 | } 19 | 20 | public static ClassLoader getDefaultClassLoader() { 21 | ClassLoader cl = null; 22 | try { 23 | cl = Thread.currentThread().getContextClassLoader(); 24 | } catch (Throwable ex) { 25 | // Cannot access thread context ClassLoader - falling back... 26 | } 27 | if (cl == null) { 28 | // No thread context class loader -> use class loader of this class. 29 | cl = ClassUtils.class.getClassLoader(); 30 | if (cl == null) { 31 | // getClassLoader() returning null indicates the bootstrap ClassLoader 32 | try { 33 | cl = ClassLoader.getSystemClassLoader(); 34 | } catch (Throwable ex) { 35 | // Cannot access system ClassLoader - oh well, maybe the caller can live with null... 36 | } 37 | } 38 | } 39 | return cl; 40 | } 41 | 42 | 43 | public static Class getClassByName(String name) { 44 | Class clazz = null; 45 | try { 46 | clazz = Class.forName(name); 47 | } catch (ClassNotFoundException e) { 48 | e.printStackTrace(); 49 | } 50 | return clazz; 51 | } 52 | 53 | public static String getMethodKey(String className, String methodName, String[] parameterNames) { 54 | return className + "." + methodName + "(" + Arrays.stream(parameterNames).collect(Collectors.joining(",")) + ")"; 55 | } 56 | 57 | public static String[] getMethodParameterNames(Method method) { 58 | Class[] types = method.getParameterTypes(); 59 | return Stream.of(types).map(it -> ReflectUtils.getName(it)).toArray(String[]::new); 60 | } 61 | 62 | 63 | public static Method getMethod(String className, String methodName, String[] parameterTypeNames) { 64 | Class clazz = ClassUtils.getClassByName(className); 65 | Class[] clazzArray = Stream.of(parameterTypeNames).map(it -> ReflectUtils.forName(it)).toArray(Class[]::new); 66 | Method m = null; 67 | try { 68 | m = clazz.getMethod(methodName, clazzArray); 69 | } catch (NoSuchMethodException e) { 70 | e.printStackTrace(); 71 | } 72 | return m; 73 | } 74 | 75 | 76 | } 77 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/common/Config.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.common; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.yaml.snakeyaml.Yaml; 6 | 7 | import java.util.Map; 8 | import java.util.Properties; 9 | 10 | /** 11 | * @author goodjava@qq.com 12 | */ 13 | public class Config { 14 | 15 | private static final Logger logger = LoggerFactory.getLogger(Config.class); 16 | 17 | private Properties properties; 18 | 19 | private Config() { 20 | properties = new ClassPathResource("application.properties").getProperties(); 21 | //拥有多个配置文件 22 | if (properties.containsKey("spring.profiles.active")) { 23 | Properties propertiesTmp = new ClassPathResource("application-" + properties.get("spring.profiles.active") + ".properties").getProperties(); 24 | propertiesTmp.keySet().stream().forEach(key -> properties.put(key, propertiesTmp.get(key))); 25 | } 26 | String yamlProperties = new ClassPathResource("application.yaml").getString(); 27 | if (StringUtils.isNotEmpty(yamlProperties)) { 28 | Yaml yaml = new Yaml(); 29 | Map m = yaml.load(yamlProperties); 30 | m.entrySet().stream().forEach(kv -> { 31 | if (kv.getKey().startsWith("rpcx.")) { 32 | properties.put(kv.getKey(), String.valueOf(kv.getValue())); 33 | } 34 | }); 35 | } 36 | logger.info("read config finish :{}", this.properties.keySet()); 37 | } 38 | 39 | 40 | private static class LazyHolder { 41 | private static final Config ins = new Config(); 42 | } 43 | 44 | 45 | public static Config ins() { 46 | return LazyHolder.ins; 47 | } 48 | 49 | public String get(String key) { 50 | return this.properties.getProperty(key); 51 | } 52 | 53 | public String get(String key, String defaultValue) { 54 | return this.properties.getProperty(key, defaultValue); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/common/InvokeCallback.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.common; 2 | 3 | 4 | import com.colobu.rpcx.netty.ResponseFuture; 5 | 6 | /** 7 | * @author goodjava@qq.com 8 | */ 9 | public interface InvokeCallback { 10 | void operationComplete(final ResponseFuture responseFuture); 11 | } 12 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/common/NamedThreadFactory.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.common; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.util.concurrent.ThreadFactory; 7 | import java.util.concurrent.atomic.AtomicInteger; 8 | 9 | /** 10 | * @author goodjava@qq.com 11 | */ 12 | public class NamedThreadFactory implements ThreadFactory { 13 | 14 | private static final Logger logger = LoggerFactory.getLogger(NamedThreadFactory.class); 15 | 16 | private final AtomicInteger mThreadNum = new AtomicInteger(1); 17 | 18 | private final String mPrefix; 19 | 20 | private final boolean mDaemo; 21 | 22 | private final ThreadGroup mGroup; 23 | 24 | public NamedThreadFactory(String prefix) { 25 | this(prefix, false); 26 | } 27 | 28 | public NamedThreadFactory(String prefix, boolean daemo) { 29 | mPrefix = prefix + "-thread-"; 30 | mDaemo = daemo; 31 | SecurityManager s = System.getSecurityManager(); 32 | mGroup = (s == null) ? Thread.currentThread().getThreadGroup() : s.getThreadGroup(); 33 | } 34 | 35 | @Override 36 | public Thread newThread(Runnable runnable) { 37 | String name = mPrefix + mThreadNum.getAndIncrement(); 38 | logger.debug("threadfactory create new thread:{}", name); 39 | Thread ret = new Thread(mGroup, runnable, name, 0); 40 | ret.setDaemon(mDaemo); 41 | return ret; 42 | } 43 | 44 | public ThreadGroup getThreadGroup() { 45 | return mGroup; 46 | } 47 | } -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/common/Pair.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.common; 2 | 3 | import java.util.Objects; 4 | 5 | /** 6 | * @author goodjava@qq.com 7 | */ 8 | public class Pair { 9 | private T1 object1; 10 | private T2 object2; 11 | 12 | 13 | public Pair(T1 object1, T2 object2) { 14 | this.object1 = object1; 15 | this.object2 = object2; 16 | } 17 | 18 | 19 | public static Pair of(T1 object, T2 object2) { 20 | return new Pair<>(object, object2); 21 | } 22 | 23 | 24 | public T1 getObject1() { 25 | return object1; 26 | } 27 | 28 | 29 | public void setObject1(T1 object1) { 30 | this.object1 = object1; 31 | } 32 | 33 | 34 | public T2 getObject2() { 35 | return object2; 36 | } 37 | 38 | 39 | public void setObject2(T2 object2) { 40 | this.object2 = object2; 41 | } 42 | 43 | 44 | @Override 45 | public boolean equals(Object o) { 46 | if (this == o) { 47 | return true; 48 | } 49 | if (!(o instanceof Pair)) { 50 | return false; 51 | } 52 | Pair pair = (Pair) o; 53 | return Objects.equals(getObject1(), pair.getObject1()) && 54 | Objects.equals(getObject2(), pair.getObject2()); 55 | } 56 | 57 | @Override 58 | public int hashCode() { 59 | 60 | return Objects.hash(getObject1(), getObject2()); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/common/RemotingHelper.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.common; 2 | 3 | import io.netty.channel.Channel; 4 | 5 | import java.net.SocketAddress; 6 | 7 | /** 8 | * @author goodjava@qq.com 9 | */ 10 | public class RemotingHelper { 11 | 12 | public static String parseChannelRemoteAddr(final Channel channel) { 13 | if (null == channel) { 14 | return ""; 15 | } 16 | SocketAddress remote = channel.remoteAddress(); 17 | final String addr = remote != null ? remote.toString() : ""; 18 | 19 | if (addr.length() > 0) { 20 | int index = addr.lastIndexOf("/"); 21 | if (index >= 0) { 22 | return addr.substring(index + 1); 23 | } 24 | 25 | return addr; 26 | } 27 | return ""; 28 | } 29 | 30 | public static String exceptionSimpleDesc(Throwable e) { 31 | StringBuffer sb = new StringBuffer(); 32 | if (e != null) { 33 | sb.append(e.toString()); 34 | 35 | StackTraceElement[] stackTrace = e.getStackTrace(); 36 | if (stackTrace != null && stackTrace.length > 0) { 37 | StackTraceElement elment = stackTrace[0]; 38 | sb.append(", "); 39 | sb.append(elment.toString()); 40 | } 41 | } 42 | 43 | return sb.toString(); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/common/RpcxVersion.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.common; 2 | 3 | /** 4 | * @author goodjava@qq.com 5 | */ 6 | public class RpcxVersion { 7 | 8 | private String version = "1.2.6"; 9 | private String date = "20181102"; 10 | 11 | 12 | @Override 13 | public String toString() { 14 | return version + " " + date; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/common/SemaphoreReleaseOnlyOnce.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.common; 2 | 3 | import java.util.concurrent.Semaphore; 4 | import java.util.concurrent.atomic.AtomicBoolean; 5 | 6 | /** 7 | * @author goodjava@qq.com 8 | */ 9 | public class SemaphoreReleaseOnlyOnce { 10 | private final AtomicBoolean released = new AtomicBoolean(false); 11 | private final Semaphore semaphore; 12 | 13 | 14 | public SemaphoreReleaseOnlyOnce(Semaphore semaphore) { 15 | this.semaphore = semaphore; 16 | } 17 | 18 | 19 | public void release() { 20 | if (this.semaphore != null) { 21 | if (this.released.compareAndSet(false, true)) { 22 | this.semaphore.release(); 23 | } 24 | } 25 | } 26 | 27 | 28 | public Semaphore getSemaphore() { 29 | return semaphore; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/common/retry/RetryNTimes.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.common.retry; 2 | 3 | import com.colobu.rpcx.rpc.Result; 4 | 5 | import java.util.function.Function; 6 | 7 | /** 8 | * @author goodjava@qq.com 9 | */ 10 | public class RetryNTimes implements RetryPolicy { 11 | 12 | 13 | private final int n; 14 | 15 | public RetryNTimes(int n) { 16 | this.n = n; 17 | } 18 | 19 | @Override 20 | public Result retry(Function func) { 21 | Result res = null; 22 | for (int i = 1; i < n + 1; i++) { 23 | res = func.apply(i); 24 | if (!res.getAttachment("needRetry").equals("true")) { 25 | return res; 26 | } 27 | } 28 | return res; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/common/retry/RetryPolicy.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.common.retry; 2 | 3 | 4 | import com.colobu.rpcx.rpc.Result; 5 | 6 | import java.util.function.Function; 7 | 8 | /** 9 | * @author goodjava@qq.com 10 | */ 11 | public interface RetryPolicy { 12 | 13 | /** 14 | * 判断的条件是result中没有异常 15 | * @param func 16 | * @return 17 | */ 18 | Result retry(Function func); 19 | } 20 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/concurrent/ConcurrentHashSet.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.concurrent; 2 | 3 | import java.util.AbstractSet; 4 | import java.util.ConcurrentModificationException; 5 | import java.util.Iterator; 6 | import java.util.Set; 7 | import java.util.concurrent.ConcurrentHashMap; 8 | 9 | /** 10 | * @author goodjava@qq.com 11 | */ 12 | public class ConcurrentHashSet extends AbstractSet implements Set, java.io.Serializable { 13 | 14 | private static final long serialVersionUID = -8672117787651310382L; 15 | 16 | private static final Object PRESENT = new Object(); 17 | 18 | private final ConcurrentHashMap map; 19 | 20 | public ConcurrentHashSet(){ 21 | map = new ConcurrentHashMap(); 22 | } 23 | 24 | public ConcurrentHashSet(int initialCapacity){ 25 | map = new ConcurrentHashMap(initialCapacity); 26 | } 27 | 28 | /** 29 | * Returns an iterator over the elements in this set. The elements are 30 | * returned in no particular order. 31 | * 32 | * @return an Iterator over the elements in this set 33 | * @see ConcurrentModificationException 34 | */ 35 | @Override 36 | public Iterator iterator() { 37 | return map.keySet().iterator(); 38 | } 39 | 40 | /** 41 | * Returns the number of elements in this set (its cardinality). 42 | * 43 | * @return the number of elements in this set (its cardinality) 44 | */ 45 | @Override 46 | public int size() { 47 | return map.size(); 48 | } 49 | 50 | /** 51 | * Returns true if this set contains no elements. 52 | * 53 | * @return true if this set contains no elements 54 | */ 55 | @Override 56 | public boolean isEmpty() { 57 | return map.isEmpty(); 58 | } 59 | 60 | /** 61 | * Returns true if this set contains the specified element. More 62 | * formally, returns true if and only if this set contains an 63 | * element e such that 64 | * (o==null ? e==null : o.equals(e)). 65 | * 66 | * @param o 67 | * element whose presence in this set is to be tested 68 | * @return true if this set contains the specified element 69 | */ 70 | @Override 71 | public boolean contains(Object o) { 72 | return map.containsKey(o); 73 | } 74 | 75 | /** 76 | * Adds the specified element to this set if it is not already present. More 77 | * formally, adds the specified element e to this set if this set 78 | * contains no element e2 such that 79 | * (e==null ? e2==null : e.equals(e2)). If this 80 | * set already contains the element, the call leaves the set unchanged and 81 | * returns false. 82 | * 83 | * @param e 84 | * element to be added to this set 85 | * @return true if this set did not already contain the specified 86 | * element 87 | */ 88 | @Override 89 | public boolean add(E e) { 90 | return map.put(e, PRESENT) == null; 91 | } 92 | 93 | /** 94 | * Removes the specified element from this set if it is present. More 95 | * formally, removes an element e such that 96 | * (o==null ? e==null : o.equals(e)), if this 97 | * set contains such an element. Returns true if this set contained 98 | * the element (or equivalently, if this set changed as a result of the 99 | * call). (This set will not contain the element once the call returns.) 100 | * 101 | * @param o 102 | * object to be removed from this set, if present 103 | * @return true if the set contained the specified element 104 | */ 105 | @Override 106 | public boolean remove(Object o) { 107 | return map.remove(o) == PRESENT; 108 | } 109 | 110 | /** 111 | * Removes all of the elements from this set. The set will be empty after 112 | * this call returns. 113 | */ 114 | @Override 115 | public void clear() { 116 | map.clear(); 117 | } 118 | 119 | } -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/config/Constants.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.config; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | import java.util.regex.Pattern; 5 | 6 | /** 7 | * @author goodjava@qq.com 8 | */ 9 | public class Constants { 10 | 11 | public static final String VERSION_KEY = "version"; 12 | 13 | public static final String GROUP_KEY = "group"; 14 | 15 | public static final String BACKUP_KEY = "backup"; 16 | 17 | public static final String DEFAULT_KEY_PREFIX = "default."; 18 | 19 | public static final Pattern COMMA_SPLIT_PATTERN = Pattern.compile("\\s*[,]+\\s*"); 20 | 21 | public static final String INTERFACE_KEY = "interface"; 22 | 23 | public static final String LOCALHOST_KEY = "localhost"; 24 | 25 | public static final String ANYHOST_VALUE = "0.0.0.0"; 26 | 27 | public static final String ANYHOST_KEY = "anyhost"; 28 | 29 | public static final String ASYNC_KEY = "async"; 30 | 31 | public static final String SYNC_KEY = "sync"; 32 | 33 | public static final String ONE_WAY_KEY = "oneway"; 34 | 35 | public static final String RETURN_KEY = "return"; 36 | 37 | public static final String $ECHO = "$echo"; 38 | 39 | public static final String $HOT_DEPLOY = "$hot_deploy"; 40 | 41 | public static final String TOKEN_KEY = "token"; 42 | 43 | public static final String TIMEOUT_KEY = "timeout"; 44 | 45 | public static final String PATH_KEY = "path"; 46 | 47 | public static final String CACHE_KEY = "cache"; 48 | 49 | public static final String ACCESSLOG_KEY = "accesslog"; 50 | 51 | public static final String FALSE = "false"; 52 | 53 | public static final String TRUE = "true"; 54 | 55 | public static final String COMMA_SEPARATOR = ","; 56 | 57 | public static final String TPS_LIMIT_RATE_KEY = "tps"; 58 | 59 | public static final String TPS_LIMIT_INTERVAL_KEY = "tps.interval"; 60 | 61 | public static final long DEFAULT_TPS_LIMIT_INTERVAL = TimeUnit.MINUTES.toMillis(1); 62 | 63 | public static final String MONITOR_KEY = "monitor"; 64 | 65 | public static final String APPLICATION_KEY = "application"; 66 | 67 | public static final String INPUT_KEY = "input"; 68 | 69 | public static final String OUTPUT_KEY = "output"; 70 | 71 | public static final String SIDE_KEY = "side"; 72 | 73 | public static final String PROVIDER_SIDE = "provider"; 74 | 75 | public static final String CONSUMER_SIDE = "consumer"; 76 | 77 | public static final String COUNT_PROTOCOL = "count"; 78 | 79 | public static final String PROVIDER = "provider"; 80 | 81 | public static final String CONSUMER = "consumer"; 82 | 83 | public static final String $INVOKE = "$invoke"; 84 | 85 | public static final String SEND_TYPE = "sendType"; 86 | 87 | public static final String FAIL_TYPE = "fail.type"; 88 | 89 | public static final String LANGUAGE = "language"; 90 | 91 | public static final String RPCX_ERROR_CODE = "__rpcx_error__"; 92 | 93 | public static final String RPCX_ERROR_MESSAGE = "_rpcx_error_message"; 94 | 95 | public static final String TRACE_ID = "trace_id"; 96 | 97 | public static final String SPAN_ID = "span_id"; 98 | 99 | public static final String X_RPCX_SERVICEPATH = "X-RPCX-ServicePath"; 100 | 101 | public static final String X_RPCX_SERVICEMETHOD = "X-RPCX-ServiceMethod"; 102 | 103 | public static final String X_RPCX_TRACEID = "X-RPCX-TraceId"; 104 | 105 | 106 | } 107 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/config/NettyClientConfig.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.config; 2 | 3 | /** 4 | * @author goodjava@qq.com 5 | */ 6 | public class NettyClientConfig { 7 | private int clientWorkerThreads = 4; 8 | private int clientCallbackExecutorThreads = Runtime.getRuntime().availableProcessors(); 9 | private int clientOnewaySemaphoreValue = 65535; 10 | private int clientAsyncSemaphoreValue = 65535; 11 | private int connectTimeoutMillis = 3000; 12 | private long channelNotActiveInterval = 1000 * 60; 13 | 14 | private int clientChannelMaxIdleTimeSeconds = 120; 15 | 16 | private int clientSocketSndBufSize = 65535; 17 | private int clientSocketRcvBufSize = 65535; 18 | private boolean clientPooledByteBufAllocatorEnable = false; 19 | private boolean clientCloseSocketIfTimeout = false; 20 | 21 | public boolean isClientCloseSocketIfTimeout() { 22 | return clientCloseSocketIfTimeout; 23 | } 24 | 25 | public void setClientCloseSocketIfTimeout(final boolean clientCloseSocketIfTimeout) { 26 | this.clientCloseSocketIfTimeout = clientCloseSocketIfTimeout; 27 | } 28 | 29 | public int getClientWorkerThreads() { 30 | return clientWorkerThreads; 31 | } 32 | 33 | 34 | public void setClientWorkerThreads(int clientWorkerThreads) { 35 | this.clientWorkerThreads = clientWorkerThreads; 36 | } 37 | 38 | 39 | public int getClientOnewaySemaphoreValue() { 40 | return clientOnewaySemaphoreValue; 41 | } 42 | 43 | 44 | public void setClientOnewaySemaphoreValue(int clientOnewaySemaphoreValue) { 45 | this.clientOnewaySemaphoreValue = clientOnewaySemaphoreValue; 46 | } 47 | 48 | 49 | public int getConnectTimeoutMillis() { 50 | return connectTimeoutMillis; 51 | } 52 | 53 | 54 | public void setConnectTimeoutMillis(int connectTimeoutMillis) { 55 | this.connectTimeoutMillis = connectTimeoutMillis; 56 | } 57 | 58 | 59 | public int getClientCallbackExecutorThreads() { 60 | return clientCallbackExecutorThreads; 61 | } 62 | 63 | 64 | public void setClientCallbackExecutorThreads(int clientCallbackExecutorThreads) { 65 | this.clientCallbackExecutorThreads = clientCallbackExecutorThreads; 66 | } 67 | 68 | 69 | public long getChannelNotActiveInterval() { 70 | return channelNotActiveInterval; 71 | } 72 | 73 | 74 | public void setChannelNotActiveInterval(long channelNotActiveInterval) { 75 | this.channelNotActiveInterval = channelNotActiveInterval; 76 | } 77 | 78 | 79 | public int getClientAsyncSemaphoreValue() { 80 | return clientAsyncSemaphoreValue; 81 | } 82 | 83 | 84 | public void setClientAsyncSemaphoreValue(int clientAsyncSemaphoreValue) { 85 | this.clientAsyncSemaphoreValue = clientAsyncSemaphoreValue; 86 | } 87 | 88 | 89 | public int getClientChannelMaxIdleTimeSeconds() { 90 | return clientChannelMaxIdleTimeSeconds; 91 | } 92 | 93 | 94 | public void setClientChannelMaxIdleTimeSeconds(int clientChannelMaxIdleTimeSeconds) { 95 | this.clientChannelMaxIdleTimeSeconds = clientChannelMaxIdleTimeSeconds; 96 | } 97 | 98 | 99 | public int getClientSocketSndBufSize() { 100 | return clientSocketSndBufSize; 101 | } 102 | 103 | 104 | public void setClientSocketSndBufSize(int clientSocketSndBufSize) { 105 | this.clientSocketSndBufSize = clientSocketSndBufSize; 106 | } 107 | 108 | 109 | public int getClientSocketRcvBufSize() { 110 | return clientSocketRcvBufSize; 111 | } 112 | 113 | 114 | public void setClientSocketRcvBufSize(int clientSocketRcvBufSize) { 115 | this.clientSocketRcvBufSize = clientSocketRcvBufSize; 116 | } 117 | 118 | 119 | public boolean isClientPooledByteBufAllocatorEnable() { 120 | return clientPooledByteBufAllocatorEnable; 121 | } 122 | 123 | 124 | public void setClientPooledByteBufAllocatorEnable(boolean clientPooledByteBufAllocatorEnable) { 125 | this.clientPooledByteBufAllocatorEnable = clientPooledByteBufAllocatorEnable; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/config/RpcxConfig.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.config; 2 | 3 | public class RpcxConfig { 4 | /** 5 | * consumer的包路径 6 | */ 7 | private String consumerPackage; 8 | /** 9 | * provider 的包路径 10 | */ 11 | private String providerPackage; 12 | /** 13 | * 用户自定义filter 的包路径 14 | */ 15 | private String filterPackage; 16 | /** 17 | * rpcx 连接 zk的地址 host:port 18 | */ 19 | private String zkAddr; 20 | /** 21 | * 热更新的token 22 | */ 23 | private String hotDeployToken; 24 | /** 25 | * 服务的端口号 26 | */ 27 | private int serverPort; 28 | 29 | /** 30 | * 业务处理的线程数量 31 | */ 32 | private int bizProcessorNum; 33 | 34 | /** 35 | * 服务器read write的线程数量 36 | */ 37 | private int workerProcessorNum; 38 | 39 | private int sndBufSize; 40 | 41 | private int rcvBufSize; 42 | 43 | 44 | public String getConsumerPackage() { 45 | return consumerPackage; 46 | } 47 | 48 | public void setConsumerPackage(String consumerPackage) { 49 | this.consumerPackage = consumerPackage; 50 | } 51 | 52 | public String getProviderPackage() { 53 | return providerPackage; 54 | } 55 | 56 | public void setProviderPackage(String providerPackage) { 57 | this.providerPackage = providerPackage; 58 | } 59 | 60 | public String getFilterPackage() { 61 | return filterPackage; 62 | } 63 | 64 | public void setFilterPackage(String filterPackage) { 65 | this.filterPackage = filterPackage; 66 | } 67 | 68 | public String getZkAddr() { 69 | return zkAddr; 70 | } 71 | 72 | public void setZkAddr(String zkAddr) { 73 | this.zkAddr = zkAddr; 74 | } 75 | 76 | public String getHotDeployToken() { 77 | return hotDeployToken; 78 | } 79 | 80 | public void setHotDeployToken(String hotDeployToken) { 81 | this.hotDeployToken = hotDeployToken; 82 | } 83 | 84 | public int getServerPort() { 85 | return serverPort; 86 | } 87 | 88 | public void setServerPort(int serverPort) { 89 | this.serverPort = serverPort; 90 | } 91 | 92 | 93 | public int getBizProcessorNum() { 94 | return bizProcessorNum; 95 | } 96 | 97 | public void setBizProcessorNum(int bizProcessorNum) { 98 | this.bizProcessorNum = bizProcessorNum; 99 | } 100 | 101 | public int getWorkerProcessorNum() { 102 | return workerProcessorNum; 103 | } 104 | 105 | public void setWorkerProcessorNum(int workerProcessorNum) { 106 | this.workerProcessorNum = workerProcessorNum; 107 | } 108 | 109 | public int getSndBufSize() { 110 | return sndBufSize; 111 | } 112 | 113 | public void setSndBufSize(int sndBufSize) { 114 | this.sndBufSize = sndBufSize; 115 | } 116 | 117 | public int getRcvBufSize() { 118 | return rcvBufSize; 119 | } 120 | 121 | public void setRcvBufSize(int rcvBufSize) { 122 | this.rcvBufSize = rcvBufSize; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/deploy/AgentLoader.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.deploy; 2 | 3 | import com.sun.tools.attach.VirtualMachine; 4 | 5 | import java.io.IOException; 6 | 7 | public class AgentLoader { 8 | 9 | 10 | public void loadAgent(String processId, String jarFileName, String params) { 11 | VirtualMachine virtualMachine = null; 12 | try { 13 | virtualMachine = VirtualMachine.attach(processId); 14 | virtualMachine.loadAgent(jarFileName, params); 15 | } catch (Exception e) { 16 | e.printStackTrace(); 17 | } finally { 18 | try { 19 | virtualMachine.detach(); 20 | } catch (IOException e) { 21 | e.printStackTrace(); 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/discovery/IServiceDiscovery.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.discovery; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * @author goodjava@qq.com 7 | */ 8 | public interface IServiceDiscovery { 9 | 10 | /** 11 | * 根据serviceName 获取 服务的ip和端口号列表 12 | * @param serviceName 13 | * @return 14 | */ 15 | List getServices(String serviceName); 16 | 17 | /** 18 | * 观察注册中心的变化 19 | */ 20 | void watch(); 21 | 22 | void close(); 23 | 24 | /** 25 | * 手动添加需要监控的服务 26 | * @param serviceNames 27 | */ 28 | void addServices(final String... serviceNames); 29 | } 30 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/exception/RemotingException.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.exception; 2 | 3 | 4 | /** 5 | * @author goodjava@qq.com 6 | */ 7 | public class RemotingException extends Exception { 8 | private static final long serialVersionUID = -5690687334570505110L; 9 | 10 | 11 | public RemotingException(String message) { 12 | super(message); 13 | } 14 | 15 | 16 | public RemotingException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/exception/RemotingSendRequestException.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.exception; 2 | 3 | /** 4 | * @author goodjava@qq.com 5 | */ 6 | public class RemotingSendRequestException extends RemotingException { 7 | private static final long serialVersionUID = 5391285827332471674L; 8 | 9 | 10 | public RemotingSendRequestException(String addr) { 11 | this(addr, null); 12 | } 13 | 14 | 15 | public RemotingSendRequestException(String addr, Throwable cause) { 16 | super("send request to <" + addr + "> failed", cause); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/exception/RemotingTimeoutException.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.exception; 2 | 3 | /** 4 | * @author goodjava@qq.com 5 | */ 6 | public class RemotingTimeoutException extends RemotingException { 7 | 8 | private static final long serialVersionUID = 4106899185095245979L; 9 | 10 | 11 | public RemotingTimeoutException(String message) { 12 | super(message); 13 | } 14 | 15 | 16 | public RemotingTimeoutException(String addr, long timeoutMillis) { 17 | this(addr, timeoutMillis, null); 18 | } 19 | 20 | 21 | public RemotingTimeoutException(String addr, long timeoutMillis, Throwable cause) { 22 | super("wait response on the channel <" + addr + "> timeout, " + timeoutMillis + "(ms)", cause); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/exception/RemotingTooMuchRequestException.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.exception; 2 | 3 | /** 4 | * @author goodjava@qq.com 5 | */ 6 | public class RemotingTooMuchRequestException extends RemotingException { 7 | private static final long serialVersionUID = 4326919581254519654L; 8 | 9 | 10 | public RemotingTooMuchRequestException(String message) { 11 | super(message); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/fail/FailType.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.fail; 2 | 3 | /** 4 | * @author goodjava@qq.com 5 | */ 6 | public enum FailType { 7 | /** 8 | * 立刻返回 9 | */ 10 | FailFast, 11 | /** 12 | * 换一个服务节点 13 | */ 14 | FailOver, 15 | /** 16 | * 在当前节点重试 17 | */ 18 | FailTry, 19 | } 20 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/filter/Filter.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.filter; 2 | 3 | import com.colobu.rpcx.rpc.Invoker; 4 | import com.colobu.rpcx.rpc.Result; 5 | import com.colobu.rpcx.rpc.RpcException; 6 | import com.colobu.rpcx.rpc.impl.RpcInvocation; 7 | 8 | /** 9 | * @author goodjava@qq.com 10 | */ 11 | public interface Filter { 12 | 13 | Result invoke(Invoker invoker, RpcInvocation invocation) throws RpcException; 14 | 15 | /** 16 | * filter name 17 | * @return 18 | */ 19 | default String name() { 20 | return this.getClass().getSimpleName(); 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/filter/impl/CacheFilter.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.filter.impl; 2 | 3 | 4 | import com.colobu.rpcx.cache.Cache; 5 | import com.colobu.rpcx.cache.LruCacheFactory; 6 | import com.colobu.rpcx.common.StringUtils; 7 | import com.colobu.rpcx.config.Constants; 8 | import com.colobu.rpcx.filter.Filter; 9 | import com.colobu.rpcx.rpc.Invoker; 10 | import com.colobu.rpcx.rpc.Result; 11 | import com.colobu.rpcx.rpc.RpcException; 12 | import com.colobu.rpcx.rpc.annotation.RpcFilter; 13 | import com.colobu.rpcx.rpc.impl.RpcInvocation; 14 | import com.colobu.rpcx.rpc.impl.RpcResult; 15 | import org.slf4j.Logger; 16 | import org.slf4j.LoggerFactory; 17 | 18 | /** 19 | * @author goodjava@qq.com 20 | */ 21 | @RpcFilter(order = -998, group = {Constants.PROVIDER}) 22 | public class CacheFilter implements Filter { 23 | 24 | private static final Logger logger = LoggerFactory.getLogger(CacheFilter.class); 25 | 26 | private static LruCacheFactory factory = new LruCacheFactory(); 27 | 28 | @Override 29 | public Result invoke(Invoker invoker, RpcInvocation invocation) throws RpcException { 30 | if (Constants.TRUE.equals(invoker.getUrl().getParameter(Constants.CACHE_KEY,Constants.FALSE))) { 31 | logger.debug("CacheFilter begin"); 32 | Cache cache = factory.getCache(invoker.getUrl()); 33 | if (cache != null) { 34 | String key = StringUtils.toArgumentString(invocation.getArguments()); 35 | logger.info("cache key:{}", key); 36 | if (cache != null && key != null) { 37 | Object value = cache.get(key); 38 | if (value != null) { 39 | logger.info("CacheFilter end get from cache"); 40 | return new RpcResult(value); 41 | } 42 | Result result = invoker.invoke(invocation); 43 | if (!result.hasException()) { 44 | cache.put(key, result.getValue()); 45 | } 46 | logger.debug("CacheFilter end"); 47 | return result; 48 | } 49 | } 50 | } 51 | return invoker.invoke(invocation); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/filter/impl/ConsumerContextFilter.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.filter.impl; 2 | 3 | 4 | import com.colobu.rpcx.common.ClassUtils; 5 | import com.colobu.rpcx.common.NetUtils; 6 | import com.colobu.rpcx.config.Constants; 7 | import com.colobu.rpcx.filter.Filter; 8 | import com.colobu.rpcx.protocol.LanguageCode; 9 | import com.colobu.rpcx.rpc.*; 10 | import com.colobu.rpcx.rpc.annotation.RpcFilter; 11 | import com.colobu.rpcx.rpc.impl.RpcInvocation; 12 | 13 | 14 | /** 15 | * @author goodjava@qq.com 16 | * 初始化consumer 上下文 17 | */ 18 | @RpcFilter(group = {Constants.CONSUMER}, order = -3000) 19 | public class ConsumerContextFilter implements Filter { 20 | 21 | @Override 22 | public Result invoke(Invoker invoker, RpcInvocation invocation) throws RpcException { 23 | String path = ""; 24 | 25 | if (invocation.getLanguageCode().equals(LanguageCode.JAVA)) { 26 | path = ClassUtils.getMethodKey(invocation.getClassName(), invocation.getMethodName(), invocation.getParameterTypeNames()); 27 | } 28 | URL url = new URL("rpcx", NetUtils.getLocalAddress().getHostAddress(), 0, path); 29 | url = url.setServiceInterface(invocation.getClassName() + "." + invocation.getMethodName()); 30 | invoker.setUrl(url); 31 | RpcContext.getContext() 32 | .setLocalAddress(NetUtils.getLocalHost(), 0) 33 | .setRemoteAddress(invoker.getUrl().getHost(), invoker.getUrl().getPort()); 34 | invocation.setInvoker(invoker); 35 | try { 36 | return invoker.invoke(invocation); 37 | } finally { 38 | //同步的和oneway的直接清除掉context 39 | if (invocation.getSendType().equals(Constants.SYNC_KEY) || invocation.getSendType().equals(Constants.ONE_WAY_KEY)) { 40 | RpcContext.removeContext(); 41 | } else { 42 | //async 需要手动自己清理(RpcContext.removeContext),因为future 还要从 contex他中拿 43 | RpcContext.getContext().clearAttachments(); 44 | RpcContext.getContext().setServiceAddr(""); 45 | RpcContext.getContext().setLocalAddress("", 0); 46 | RpcContext.getContext().setRemoteAddress("", 0); 47 | } 48 | } 49 | } 50 | 51 | } -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/filter/impl/ConsumerTraceidFilter.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.filter.impl; 2 | 3 | import com.colobu.rpcx.common.ClassUtils; 4 | import com.colobu.rpcx.config.Constants; 5 | import com.colobu.rpcx.filter.Filter; 6 | import com.colobu.rpcx.rpc.Invoker; 7 | import com.colobu.rpcx.rpc.Result; 8 | import com.colobu.rpcx.rpc.RpcException; 9 | import com.colobu.rpcx.rpc.annotation.RpcFilter; 10 | import com.colobu.rpcx.rpc.impl.RpcInvocation; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | /** 15 | * @author goodjava@qq.com 16 | * 打印traceid 17 | */ 18 | @RpcFilter(group = {Constants.CONSUMER}, order = -1000) 19 | public class ConsumerTraceidFilter implements Filter { 20 | 21 | private static final Logger logger = LoggerFactory.getLogger(ConsumerTraceidFilter.class); 22 | 23 | @Override 24 | public Result invoke(Invoker invoker, RpcInvocation invocation) throws RpcException { 25 | Result result = invoker.invoke(invocation); 26 | 27 | if (null != result) { 28 | String key = ClassUtils.getMethodKey(invocation.getClassName(), invocation.getMethodName(), invocation.getParameterTypeNames()); 29 | String traceId = result.getAttachment(Constants.TRACE_ID); 30 | String spanId = result.getAttachment(Constants.SPAN_ID); 31 | logger.info("invoke {} traceid:{} spanId:{} error:{}", key, traceId, spanId, result.hasException()); 32 | } 33 | 34 | return result; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/filter/impl/ContextFilter.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.filter.impl; 2 | 3 | 4 | import com.colobu.rpcx.config.Constants; 5 | import com.colobu.rpcx.filter.Filter; 6 | import com.colobu.rpcx.rpc.Invoker; 7 | import com.colobu.rpcx.rpc.Result; 8 | import com.colobu.rpcx.rpc.RpcContext; 9 | import com.colobu.rpcx.rpc.RpcException; 10 | import com.colobu.rpcx.rpc.annotation.RpcFilter; 11 | import com.colobu.rpcx.rpc.impl.RpcInvocation; 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | 15 | import java.util.Map; 16 | 17 | /** 18 | * @author goodjava@qq.com 19 | */ 20 | @RpcFilter(order = -2000, group = {Constants.PROVIDER}) 21 | public class ContextFilter implements Filter { 22 | 23 | private static final Logger logger = LoggerFactory.getLogger(ContextFilter.class); 24 | 25 | @Override 26 | public Result invoke(Invoker invoker, RpcInvocation invocation) throws RpcException { 27 | logger.debug("ContextFilter begin className:{} methodName:{}", invocation.getClassName(), invocation.getMethodName()); 28 | Map attachments = invocation.getAttachments(); 29 | RpcContext.getContext() 30 | .setAttachments(attachments) 31 | .setRemoteAddress(invocation.getUrl().getAddress(), invocation.getUrl().getPort()) 32 | .setLocalAddress(invoker.getUrl().getHost(), 33 | invoker.getUrl().getPort()); 34 | invocation.setInvoker(invoker); 35 | try { 36 | return invoker.invoke(invocation); 37 | } finally { 38 | RpcContext.removeContext(); 39 | logger.debug("ContextFilter end"); 40 | } 41 | } 42 | 43 | 44 | } -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/filter/impl/EchoFilter.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.filter.impl; 2 | 3 | 4 | import com.colobu.rpcx.config.Constants; 5 | import com.colobu.rpcx.filter.Filter; 6 | import com.colobu.rpcx.rpc.Invoker; 7 | import com.colobu.rpcx.rpc.Result; 8 | import com.colobu.rpcx.rpc.RpcException; 9 | import com.colobu.rpcx.rpc.annotation.RpcFilter; 10 | import com.colobu.rpcx.rpc.impl.RpcInvocation; 11 | import com.colobu.rpcx.rpc.impl.RpcResult; 12 | 13 | /** 14 | * @author goodjava@qq.com 15 | */ 16 | @RpcFilter(order = -2001, group = {Constants.PROVIDER}) 17 | public class EchoFilter implements Filter { 18 | 19 | @Override 20 | public Result invoke(Invoker invoker, RpcInvocation inv) throws RpcException { 21 | if (inv.getMethodName().equals(Constants.$ECHO) && inv.getArguments() != null && inv.getArguments().length == 1) { 22 | return new RpcResult(inv.getArguments()[0]); 23 | } 24 | return invoker.invoke(inv); 25 | } 26 | 27 | } -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/filter/impl/ExceptionFilter.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.filter.impl; 2 | 3 | 4 | import com.colobu.rpcx.config.Constants; 5 | import com.colobu.rpcx.filter.Filter; 6 | import com.colobu.rpcx.rpc.*; 7 | import com.colobu.rpcx.rpc.annotation.RpcFilter; 8 | import com.colobu.rpcx.rpc.impl.RpcInvocation; 9 | import com.colobu.rpcx.rpc.impl.RpcResult; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | 14 | /** 15 | * @author goodjava@qq.com 16 | */ 17 | @RpcFilter(group = {Constants.PROVIDER}, order = -1999) 18 | public class ExceptionFilter implements Filter { 19 | 20 | private static final Logger logger = LoggerFactory.getLogger(ExceptionFilter.class); 21 | 22 | @Override 23 | public Result invoke(Invoker invoker, RpcInvocation invocation) throws RpcException { 24 | try { 25 | Result result = invoker.invoke(invocation); 26 | return result; 27 | } catch (RpcException ex) { 28 | Result result = new RpcResult(); 29 | result.setThrowable(ex); 30 | return result; 31 | } catch (Throwable throwable) { 32 | Result result = new RpcResult(); 33 | result.setThrowable(throwable); 34 | return result; 35 | } 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/filter/impl/FailFilter.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.filter.impl; 2 | 3 | import com.colobu.rpcx.common.retry.RetryNTimes; 4 | import com.colobu.rpcx.config.Constants; 5 | import com.colobu.rpcx.fail.FailType; 6 | import com.colobu.rpcx.filter.Filter; 7 | import com.colobu.rpcx.rpc.Invoker; 8 | import com.colobu.rpcx.rpc.Result; 9 | import com.colobu.rpcx.rpc.RpcException; 10 | import com.colobu.rpcx.rpc.annotation.RpcFilter; 11 | import com.colobu.rpcx.rpc.impl.RpcInvocation; 12 | import com.colobu.rpcx.selector.SelectMode; 13 | import org.slf4j.Logger; 14 | import org.slf4j.LoggerFactory; 15 | 16 | /** 17 | * @author goodjava@qq.com 18 | *

19 | * 负责管理失败的重试 20 | */ 21 | @RpcFilter(group = {Constants.CONSUMER}, order = -1000) 22 | public class FailFilter implements Filter { 23 | 24 | 25 | private static final Logger logger = LoggerFactory.getLogger(FailFilter.class); 26 | 27 | @Override 28 | public Result invoke(Invoker invoker, RpcInvocation invocation) throws RpcException { 29 | FailType failType = invocation.getFailType(); 30 | RetryNTimes retry = new RetryNTimes(invocation.getRetryNum()); 31 | Result result = retry.retry((n) -> { 32 | Result res = invoker.invoke(invocation); 33 | if (res.hasException()) { 34 | logger.warn("{} invoke error:{}", invocation.getUrl().getPath(), res.getException().getMessage()); 35 | //失败了立刻返回 36 | if (failType.equals(FailType.FailFast)) { 37 | logger.info("------>failFast"); 38 | res.getAttachments().put("needRetry", "false"); 39 | return res; 40 | } 41 | //换个服务节点重试 42 | if (failType.equals(FailType.FailOver)) { 43 | logger.info("------>failOver"); 44 | res.getAttachments().put("needRetry", "true"); 45 | return res; 46 | } 47 | //当前节点重试 48 | if (failType.equals(FailType.FailTry)) { 49 | logger.info("------>failTry"); 50 | res.getAttachments().put("needRetry", "true"); 51 | //这样走到下游的SelectFilter就不会再选出来一个新的Service了 52 | invocation.setSelectMode(SelectMode.SelectByUser); 53 | return res; 54 | } 55 | } 56 | res.getAttachments().put("needRetry", "false"); 57 | return res; 58 | }); 59 | 60 | return result; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/filter/impl/GenericFilter.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.filter.impl; 2 | 3 | 4 | import com.colobu.rpcx.common.ClassUtils; 5 | import com.colobu.rpcx.config.Constants; 6 | import com.colobu.rpcx.filter.Filter; 7 | import com.colobu.rpcx.rpc.Invoker; 8 | import com.colobu.rpcx.rpc.ReflectUtils; 9 | import com.colobu.rpcx.rpc.Result; 10 | import com.colobu.rpcx.rpc.RpcException; 11 | import com.colobu.rpcx.rpc.annotation.RpcFilter; 12 | import com.colobu.rpcx.rpc.impl.Exporter; 13 | import com.colobu.rpcx.rpc.impl.RpcInvocation; 14 | import com.google.gson.Gson; 15 | 16 | import java.lang.reflect.Method; 17 | import java.util.stream.IntStream; 18 | 19 | 20 | /** 21 | * @author goodjava@qq.com 22 | * 泛化调用 23 | */ 24 | @RpcFilter(group = {Constants.PROVIDER}, order = -2001) 25 | public class GenericFilter implements Filter { 26 | 27 | @Override 28 | public Result invoke(Invoker invoker, RpcInvocation inv) throws RpcException { 29 | if (inv.getMethodName().equals(Constants.$INVOKE)) { 30 | String[] types = inv.getParameterTypeNames(); 31 | final String[] args = (String[]) inv.getArguments(); 32 | 33 | Gson gson = new Gson(); 34 | int len = types.length; 35 | 36 | Class[] classTypes = new Class[types.length]; 37 | 38 | Object[] params = IntStream.range(0, len).mapToObj(i -> { 39 | String type = types[i]; 40 | Class clazz = ReflectUtils.forName(type); 41 | classTypes[i] = clazz; 42 | int j = i + 1; 43 | String arg = args[j]; 44 | Object obj = gson.fromJson(arg, clazz); 45 | return obj; 46 | }).toArray(Object[]::new); 47 | 48 | //从新组装Invocation 49 | inv.setMethodName(args[0]); 50 | inv.setParameterTypes(classTypes); 51 | inv.setArguments(params); 52 | 53 | 54 | Method method = ClassUtils.getMethod(inv.getClassName(), inv.getMethodName(), inv.getParameterTypeNames()); 55 | invoker.setMethod(method); 56 | 57 | Result res = invoker.invoke(inv); 58 | 59 | if (!res.hasException()) { 60 | Object value = res.getValue(); 61 | res.setValue(gson.toJson(value)); 62 | return res; 63 | } 64 | 65 | } 66 | 67 | return invoker.invoke(inv); 68 | } 69 | 70 | } -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/filter/impl/HotDeployFilter.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.filter.impl; 2 | 3 | 4 | import com.colobu.rpcx.common.Config; 5 | import com.colobu.rpcx.common.StringUtils; 6 | import com.colobu.rpcx.config.Constants; 7 | import com.colobu.rpcx.deploy.AgentLoader; 8 | import com.colobu.rpcx.filter.Filter; 9 | import com.colobu.rpcx.rpc.Invoker; 10 | import com.colobu.rpcx.rpc.Result; 11 | import com.colobu.rpcx.rpc.RpcException; 12 | import com.colobu.rpcx.rpc.annotation.RpcFilter; 13 | import com.colobu.rpcx.rpc.impl.RpcInvocation; 14 | import com.colobu.rpcx.rpc.impl.RpcResult; 15 | import org.slf4j.Logger; 16 | import org.slf4j.LoggerFactory; 17 | 18 | import java.io.IOException; 19 | import java.lang.management.ManagementFactory; 20 | import java.lang.management.RuntimeMXBean; 21 | import java.nio.file.Files; 22 | import java.nio.file.Paths; 23 | import java.util.UUID; 24 | 25 | /** 26 | * @author goodjava@qq.com 27 | * 支持热更新 28 | */ 29 | @RpcFilter(order = -2002, group = {Constants.PROVIDER}) 30 | public class HotDeployFilter implements Filter { 31 | 32 | private static final Logger logger = LoggerFactory.getLogger(HotDeployFilter.class); 33 | 34 | @Override 35 | public Result invoke(Invoker invoker, RpcInvocation inv) throws RpcException { 36 | if (inv.getMethodName().equals(Constants.$HOT_DEPLOY) && inv.getArguments().length == 3) { 37 | logger.info("hot deploy begin"); 38 | Object[] arguments = inv.getArguments(); 39 | 40 | String className = arguments[0].toString(); 41 | String token = arguments[1].toString(); 42 | 43 | String configToken = Config.ins().get("rpcx.deploy.tokey"); 44 | if (StringUtils.isEmpty(configToken) || !token.equals(configToken)) { 45 | throw new RpcException("token error"); 46 | } 47 | 48 | byte[] classData = (byte[]) arguments[2]; 49 | String uuid = UUID.randomUUID().toString(); 50 | String file = "/tmp/" + uuid; 51 | String pid = getPid(); 52 | logger.info("className:{} file:{} pid:{} data len:{}", className, file, pid, classData.length); 53 | try { 54 | Files.write(Paths.get(file), classData); 55 | } catch (IOException e) { 56 | e.printStackTrace(); 57 | } 58 | new AgentLoader().loadAgent(pid, Config.ins().get("rpcx_agent_path"), file + "__" + className); 59 | 60 | try { 61 | Files.delete(Paths.get(file)); 62 | } catch (IOException e) { 63 | e.printStackTrace(); 64 | } 65 | return new RpcResult("Finish"); 66 | } 67 | 68 | return invoker.invoke(inv); 69 | } 70 | 71 | 72 | public String getPid() { 73 | RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean(); 74 | // format: "pid@hostname" 75 | String name = runtime.getName(); 76 | return name.substring(0, name.indexOf('@')); 77 | } 78 | 79 | } -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/filter/impl/SelectorFilter.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.filter.impl; 2 | 3 | import com.colobu.rpcx.config.Constants; 4 | import com.colobu.rpcx.filter.Filter; 5 | import com.colobu.rpcx.rpc.*; 6 | import com.colobu.rpcx.rpc.annotation.RpcFilter; 7 | import com.colobu.rpcx.rpc.impl.RpcInvocation; 8 | import com.colobu.rpcx.selector.SelectMode; 9 | import com.colobu.rpcx.selector.Weighted; 10 | import com.colobu.rpcx.selector.WeightedRountRobin; 11 | 12 | import java.security.SecureRandom; 13 | import java.util.List; 14 | import java.util.concurrent.ConcurrentHashMap; 15 | import java.util.stream.Collectors; 16 | 17 | 18 | /** 19 | * @author goodjava@qq.com 20 | */ 21 | @RpcFilter(group = {Constants.CONSUMER}) 22 | public class SelectorFilter implements Filter { 23 | 24 | private static SecureRandom secureRandom = new SecureRandom(); 25 | 26 | private static ConcurrentHashMap selectIndexMap = new ConcurrentHashMap<>(); 27 | 28 | /** 29 | * 基于权重 30 | */ 31 | private static ConcurrentHashMap weightRoundRobinMap = new ConcurrentHashMap<>(); 32 | 33 | @Override 34 | public Result invoke(Invoker invoker, RpcInvocation invocation) throws RpcException { 35 | //目前使用类名当服务名称 36 | String serviceName = invocation.getClassName(); 37 | 38 | //获取服务列表(ip:port?param) 39 | List serviceList = invoker.serviceDiscovery().getServices(serviceName); 40 | 41 | serviceList = serviceList.stream().filter(it->{ 42 | URL url = URL.valueOf(it); 43 | if (!it.contains("state=inactive") && invocation.getGroup().equals(url.getParameter(Constants.GROUP_KEY,""))) { 44 | return true; 45 | } 46 | return false; 47 | }).collect(Collectors.toList()); 48 | 49 | 50 | if (serviceList.size() <= 0) { 51 | throw new RpcException("service list size <=0 ", "-3"); 52 | } 53 | 54 | SelectMode selectMode = invocation.getSelectMode(); 55 | switch (selectMode) { 56 | case RandomSelect: { 57 | String service = randomSelect(serviceList); 58 | RpcContext.getContext().setServiceAddr(service); 59 | break; 60 | } 61 | case RoundRobin: { 62 | String service = roundRobin(serviceList, serviceName); 63 | RpcContext.getContext().setServiceAddr(service); 64 | break; 65 | } 66 | case WeightedRoundRobin: { 67 | String service = weightedRountRobin(serviceList, serviceName); 68 | RpcContext.getContext().setServiceAddr(service); 69 | break; 70 | } 71 | case SelectByUser: { 72 | break; 73 | } 74 | } 75 | 76 | 77 | return invoker.invoke(invocation); 78 | } 79 | 80 | 81 | private String roundRobin(List serviceList, String serviceName) { 82 | Integer index = selectIndexMap.get(serviceName); 83 | if (null == index) { 84 | selectIndexMap.putIfAbsent(serviceName, 0); 85 | index = selectIndexMap.get(serviceName); 86 | } 87 | 88 | int i = index % serviceList.size(); 89 | String serviceAddr = serviceList.get(i); 90 | selectIndexMap.compute(serviceName, (k, v) -> { 91 | v = v + 1; 92 | return v; 93 | }); 94 | return URL.valueOf(serviceAddr).getAddress(); 95 | } 96 | 97 | 98 | private String weightedRountRobin(List serviceList, String serviceName) { 99 | WeightedRountRobin weightedRountRobin = weightRoundRobinMap.get(serviceName); 100 | if (null == weightedRountRobin) { 101 | weightRoundRobinMap.putIfAbsent(serviceName, new WeightedRountRobin(serviceList)); 102 | weightedRountRobin = weightRoundRobinMap.get(serviceName); 103 | } 104 | //需要更新权重列表,有可能服务器上下线 105 | weightedRountRobin.updateWeighteds(serviceList); 106 | 107 | Weighted wei = weightedRountRobin.nextWeighted(); 108 | if (null == wei) { 109 | return null; 110 | } 111 | return URL.valueOf(wei.getServer()).getAddress(); 112 | } 113 | 114 | 115 | private String randomSelect(List serviceList) { 116 | int index = secureRandom.nextInt(serviceList.size()); 117 | return URL.valueOf(serviceList.get(index)).getAddress(); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/filter/impl/TimeoutFilter.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.filter.impl; 2 | 3 | 4 | import com.colobu.rpcx.config.Constants; 5 | import com.colobu.rpcx.filter.Filter; 6 | import com.colobu.rpcx.rpc.Invoker; 7 | import com.colobu.rpcx.rpc.Result; 8 | import com.colobu.rpcx.rpc.RpcException; 9 | import com.colobu.rpcx.rpc.annotation.RpcFilter; 10 | import com.colobu.rpcx.rpc.impl.RpcInvocation; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | import java.util.Arrays; 15 | 16 | 17 | /** 18 | * @author goodjava@qq.com 19 | */ 20 | @RpcFilter(order = -1000, group = {Constants.PROVIDER}) 21 | public class TimeoutFilter implements Filter { 22 | 23 | private static final Logger logger = LoggerFactory.getLogger(TimeoutFilter.class); 24 | 25 | @Override 26 | public Result invoke(Invoker invoker, RpcInvocation invocation) throws RpcException { 27 | if (!("-1".equals(invoker.getUrl().getParameter(Constants.TIMEOUT_KEY)))) { 28 | long start = System.currentTimeMillis(); 29 | Result result = invoker.invoke(invocation); 30 | long elapsed = System.currentTimeMillis() - start; 31 | 32 | int v = invoker.getUrl().getParameter(Constants.TIMEOUT_KEY, Integer.MAX_VALUE); 33 | if (invoker.getUrl() != null && v != 0 && elapsed > v) { 34 | logger.warn("invoke time out. method: " + invocation.getMethodName() 35 | + " arguments: " + Arrays.toString(invocation.getArguments()) + " , url is " 36 | + invoker.getUrl() + ", invoke elapsed " + elapsed + " ms."); 37 | } 38 | return result; 39 | } 40 | 41 | return invoker.invoke(invocation); 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/filter/impl/TokenFilter.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.filter.impl; 2 | 3 | 4 | import com.colobu.rpcx.common.StringUtils; 5 | import com.colobu.rpcx.config.Constants; 6 | import com.colobu.rpcx.filter.Filter; 7 | import com.colobu.rpcx.rpc.Invoker; 8 | import com.colobu.rpcx.rpc.Result; 9 | import com.colobu.rpcx.rpc.RpcContext; 10 | import com.colobu.rpcx.rpc.RpcException; 11 | import com.colobu.rpcx.rpc.annotation.RpcFilter; 12 | import com.colobu.rpcx.rpc.impl.RpcInvocation; 13 | 14 | import java.util.Map; 15 | 16 | /** 17 | * Created by goodjava@qq.com. 18 | */ 19 | @RpcFilter(order = -999, group = {Constants.PROVIDER}) 20 | public class TokenFilter implements Filter { 21 | 22 | @Override 23 | public Result invoke(Invoker invoker, RpcInvocation inv) 24 | throws RpcException { 25 | String token = invoker.getUrl().getParameter(Constants.TOKEN_KEY,""); 26 | if (!StringUtils.isEmpty(token)) { 27 | Class serviceType = invoker.getInterface(); 28 | Map attachments = inv.getAttachments(); 29 | String remoteToken = attachments == null ? null : attachments.get(Constants.TOKEN_KEY); 30 | if (!token.equals(remoteToken)) { 31 | throw new RpcException("Invalid token! Forbid invoke remote service " + serviceType + " method " + inv.getMethodName() + "() from consumer " + RpcContext.getContext().getRemoteHost() + " to provider " + RpcContext.getContext().getLocalHost()); 32 | } 33 | } 34 | return invoker.invoke(inv); 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/filter/impl/TpsLimitFilter.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.filter.impl; 2 | 3 | 4 | import com.colobu.rpcx.config.Constants; 5 | import com.colobu.rpcx.filter.Filter; 6 | import com.colobu.rpcx.rpc.Invoker; 7 | import com.colobu.rpcx.rpc.Result; 8 | import com.colobu.rpcx.rpc.RpcException; 9 | import com.colobu.rpcx.rpc.annotation.RpcFilter; 10 | import com.colobu.rpcx.rpc.impl.RpcInvocation; 11 | import com.colobu.rpcx.tps.DefaultTPSLimiter; 12 | import com.colobu.rpcx.tps.TPSLimiter; 13 | 14 | /** 15 | * Created by goodjava@qq.com. 16 | */ 17 | @RpcFilter(group = {Constants.PROVIDER}) 18 | public class TpsLimitFilter implements Filter { 19 | 20 | private static final TPSLimiter tpsLimiter = new DefaultTPSLimiter(); 21 | 22 | @Override 23 | public Result invoke(Invoker invoker, RpcInvocation invocation) throws RpcException { 24 | if (invocation.getUrl().getParameter(Constants.TPS_LIMIT_RATE_KEY,"-1").equals("-1")) { 25 | return invoker.invoke(invocation); 26 | } 27 | 28 | if (!tpsLimiter.isAllowable(invoker.getUrl(), invocation)) { 29 | throw new RpcException( 30 | new StringBuilder(64) 31 | .append("Failed to invoke service ") 32 | .append(invoker.getInterface().getName()) 33 | .append(".") 34 | .append(invocation.getMethodName()) 35 | .append(" because exceed max service tps.") 36 | .toString()); 37 | } 38 | 39 | return invoker.invoke(invocation); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/filter/impl/TraceidFilter.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.filter.impl; 2 | 3 | import com.colobu.rpcx.common.ClassUtils; 4 | import com.colobu.rpcx.common.StringUtils; 5 | import com.colobu.rpcx.config.Constants; 6 | import com.colobu.rpcx.filter.Filter; 7 | import com.colobu.rpcx.rpc.Invoker; 8 | import com.colobu.rpcx.rpc.Result; 9 | import com.colobu.rpcx.rpc.RpcContext; 10 | import com.colobu.rpcx.rpc.RpcException; 11 | import com.colobu.rpcx.rpc.annotation.RpcFilter; 12 | import com.colobu.rpcx.rpc.impl.RpcInvocation; 13 | import org.slf4j.Logger; 14 | import org.slf4j.LoggerFactory; 15 | 16 | import java.util.UUID; 17 | 18 | /** 19 | * @author goodjava@qq.com 20 | */ 21 | @RpcFilter(order = -999, group = {Constants.PROVIDER}) 22 | public class TraceidFilter implements Filter { 23 | 24 | private static final Logger logger = LoggerFactory.getLogger(TraceidFilter.class); 25 | 26 | @Override 27 | public Result invoke(Invoker invoker, RpcInvocation invocation) throws RpcException { 28 | String clientTraceId = invocation.getAttachment(Constants.TRACE_ID); 29 | String key = ClassUtils.getMethodKey(invocation.getClassName(), invocation.getMethodName(), invocation.getParameterTypeNames()); 30 | String traceId = ""; 31 | String spanId = invocation.getAttachment(Constants.SPAN_ID, ""); 32 | if (StringUtils.isNotEmpty(clientTraceId)) { 33 | traceId = clientTraceId; 34 | spanId = spanId + "," + UUID.randomUUID().toString(); 35 | } else { 36 | //new 37 | traceId = UUID.randomUUID().toString(); 38 | spanId = traceId; 39 | } 40 | logger.info("invoke begin:{} traceId:{} spanId:{}", key, traceId, spanId); 41 | RpcContext.getContext().getAttachments().put(Constants.TRACE_ID, traceId); 42 | RpcContext.getContext().getAttachments().put(Constants.SPAN_ID, spanId); 43 | try { 44 | Result res = invoker.invoke(invocation); 45 | logger.info("invoke end:{} success traceId:{} spanId:{}", key, traceId, spanId); 46 | return res; 47 | } catch (Throwable ex) { 48 | logger.info("invoke end:{} failure traceId:{} spanId:{}", key, traceId, spanId); 49 | throw ex; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/io/UnsafeStringWriter.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.io; 2 | 3 | import java.io.IOException; 4 | import java.io.Writer; 5 | 6 | 7 | /** 8 | * Created by goodjava@qq.com. 9 | */ 10 | public class UnsafeStringWriter extends Writer 11 | { 12 | private StringBuilder mBuffer; 13 | 14 | public UnsafeStringWriter() 15 | { 16 | lock = mBuffer = new StringBuilder(); 17 | } 18 | 19 | public UnsafeStringWriter(int size) 20 | { 21 | if( size < 0 ) { 22 | throw new IllegalArgumentException("Negative buffer size"); 23 | } 24 | 25 | lock = mBuffer = new StringBuilder(); 26 | } 27 | 28 | @Override 29 | public void write(int c) 30 | { 31 | mBuffer.append((char)c); 32 | } 33 | 34 | @Override 35 | public void write(char[] cs) throws IOException 36 | { 37 | mBuffer.append(cs, 0, cs.length); 38 | } 39 | 40 | @Override 41 | public void write(char[] cs, int off, int len) throws IOException 42 | { 43 | if( (off < 0) || (off > cs.length) || (len < 0) || 44 | ((off + len) > cs.length) || ((off + len) < 0) ) { 45 | throw new IndexOutOfBoundsException(); 46 | } 47 | 48 | if( len > 0 ) { 49 | mBuffer.append(cs, off, len); 50 | } 51 | } 52 | 53 | @Override 54 | public void write(String str) 55 | { 56 | mBuffer.append(str); 57 | } 58 | 59 | @Override 60 | public void write(String str, int off, int len) 61 | { 62 | mBuffer.append(str.substring(off, off + len)); 63 | } 64 | 65 | @Override 66 | public Writer append(CharSequence csq) 67 | { 68 | if (csq == null) { 69 | write("null"); 70 | } else { 71 | write(csq.toString()); 72 | } 73 | return this; 74 | } 75 | 76 | @Override 77 | public Writer append(CharSequence csq, int start, int end) 78 | { 79 | CharSequence cs = (csq == null ? "null" : csq); 80 | write(cs.subSequence(start, end).toString()); 81 | return this; 82 | } 83 | 84 | @Override 85 | public Writer append(char c) 86 | { 87 | mBuffer.append(c); 88 | return this; 89 | } 90 | 91 | @Override 92 | public void close(){} 93 | 94 | @Override 95 | public void flush(){} 96 | 97 | @Override 98 | public String toString() 99 | { 100 | return mBuffer.toString(); 101 | } 102 | } -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/monitor/Monitor.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.monitor; 2 | 3 | import com.colobu.rpcx.rpc.Node; 4 | 5 | /** 6 | * Created by goodjava@qq.com. 7 | */ 8 | public interface Monitor extends Node, MonitorService { 9 | 10 | } -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/monitor/MonitorFactory.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.monitor; 2 | 3 | import com.colobu.rpcx.monitor.impl.RpcxMonitor; 4 | import com.colobu.rpcx.rpc.URL; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import java.util.List; 8 | 9 | /** 10 | * @author goodjava@qq.com 11 | */ 12 | public class MonitorFactory { 13 | 14 | private static final Logger logger = LoggerFactory.getLogger(MonitorFactory.class); 15 | 16 | /** 17 | * Create monitor. 18 | */ 19 | public Monitor getMonitor(URL url) { 20 | return new RpcxMonitor(new MonitorService() { 21 | @Override 22 | public void collect(URL statistics) { 23 | logger.info(statistics.toFullString()); 24 | } 25 | 26 | @Override 27 | public List lookup(URL query) { 28 | return null; 29 | } 30 | }); 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/monitor/MonitorService.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.monitor; 2 | 3 | 4 | import com.colobu.rpcx.config.Constants; 5 | import com.colobu.rpcx.rpc.URL; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * Created by goodjava@qq.com. 11 | */ 12 | public interface MonitorService { 13 | 14 | String APPLICATION = "application"; 15 | 16 | String INTERFACE = "interface"; 17 | 18 | String METHOD = "method"; 19 | 20 | String GROUP = "group"; 21 | 22 | String VERSION = "version"; 23 | 24 | String CONSUMER = "consumer"; 25 | 26 | String PROVIDER = "provider"; 27 | 28 | String TIMESTAMP = "timestamp"; 29 | 30 | String SUCCESS = "success"; 31 | 32 | String FAILURE = "failure"; 33 | 34 | String INPUT = Constants.INPUT_KEY; 35 | 36 | String OUTPUT = Constants.OUTPUT_KEY; 37 | 38 | String ELAPSED = "elapsed"; 39 | 40 | String CONCURRENT = "concurrent"; 41 | 42 | String MAX_INPUT = "max.input"; 43 | 44 | String MAX_OUTPUT = "max.output"; 45 | 46 | String MAX_ELAPSED = "max.elapsed"; 47 | 48 | String MAX_CONCURRENT = "max.concurrent"; 49 | 50 | /** 51 | * 监控数据采集. 52 | * 1. 支持调用次数统计:count://host/interface?application=foo&method=foo&provider=10.20.153.11:20880&success=12&failure=2&elapsed=135423423 53 | * 1.1 host,application,interface,group,version,method 记录监控来源主机,应用,接口,方法信息。 54 | * 1.2 如果是消费者发送的数据,加上provider地址参数,反之,加上来源consumer地址参数。 55 | * 1.3 success,faulure,elapsed 记录距上次采集,调用的成功次数,失败次数,成功调用总耗时,平均时间将用总耗时除以成功次数。 56 | * 57 | * @param statistics 58 | */ 59 | void collect(URL statistics); 60 | 61 | /** 62 | * 监控数据查询.  63 | * 1. 支持按天查询:count://host/interface?application=foo&method=foo&side=provider&view=chart&date=2012-07-03 64 | * 1.1 host,application,interface,group,version,method 查询主机,应用,接口,方法的匹配条件,缺失的条件的表示全部,host用0.0.0.0表示全部。 65 | * 1.2 side=consumer,provider 查询由调用的哪一端采集的数据,缺省为都查询。 66 | * 1.3 缺省为view=summary,返回全天汇总信息,支持view=chart表示返回全天趋势图表图片的URL地址,可以进接嵌入其它系统的页面上展示。 67 | * 1.4 date=2012-07-03 指定查询数据的日期,缺省为当天。 68 | * 69 | * @param query 70 | * @return statistics 71 | */ 72 | List lookup(URL query); 73 | 74 | } -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/netty/ChannelEventListener.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.netty; 2 | 3 | import io.netty.channel.Channel; 4 | 5 | /** 6 | * @author goodjava@qq.com 7 | */ 8 | public interface ChannelEventListener { 9 | 10 | void onChannelConnect(final String remoteAddr, final Channel channel); 11 | 12 | void onChannelClose(final String remoteAddr, final Channel channel); 13 | 14 | void onChannelException(final String remoteAddr, final Channel channel); 15 | 16 | void onChannelIdle(final String remoteAddr, final Channel channel); 17 | } 18 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/netty/ChannelWrapper.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.netty; 2 | 3 | import io.netty.channel.Channel; 4 | import io.netty.channel.ChannelFuture; 5 | 6 | /** 7 | * @author goodjava@qq.com 8 | */ 9 | public class ChannelWrapper { 10 | 11 | private final ChannelFuture channelFuture; 12 | 13 | 14 | public ChannelWrapper(ChannelFuture channelFuture) { 15 | this.channelFuture = channelFuture; 16 | } 17 | 18 | 19 | public boolean isOK() { 20 | return this.channelFuture.channel() != null && this.channelFuture.channel().isActive(); 21 | } 22 | 23 | 24 | public boolean isWriteable() { 25 | return this.channelFuture.channel().isWritable(); 26 | } 27 | 28 | 29 | public Channel getChannel() { 30 | return this.channelFuture.channel(); 31 | } 32 | 33 | 34 | public ChannelFuture getChannelFuture() { 35 | return channelFuture; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/netty/ClientChannelEventListener.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.netty; 2 | 3 | import io.netty.channel.Channel; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | /** 8 | * @author goodjava@qq.com 9 | */ 10 | public class ClientChannelEventListener implements ChannelEventListener { 11 | 12 | private static final Logger logger = LoggerFactory.getLogger(ClientChannelEventListener.class); 13 | 14 | 15 | public ClientChannelEventListener() { 16 | } 17 | 18 | @Override 19 | public void onChannelConnect(String remoteAddr, Channel channel) { 20 | logger.info("client connect remoteAddr:{}", remoteAddr); 21 | } 22 | 23 | @Override 24 | public void onChannelClose(String remoteAddr, Channel channel) { 25 | logger.info("client close remoteAddr:" + remoteAddr); 26 | } 27 | 28 | @Override 29 | public void onChannelException(String remoteAddr, Channel channel) { 30 | logger.info("client onChannelException remoteAddr:{}", remoteAddr); 31 | } 32 | 33 | @Override 34 | public void onChannelIdle(String remoteAddr, Channel channel) { 35 | 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/netty/DecoderState.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.netty; 2 | 3 | /** 4 | * @author goodjava@qq.com 5 | */ 6 | public enum DecoderState { 7 | /** 8 | * 魔术值 9 | */ 10 | MagicNumber, 11 | /** 12 | * 包头 13 | */ 14 | Header, 15 | /** 16 | * 包体 17 | */ 18 | Body, 19 | } 20 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/netty/IClient.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.netty; 2 | 3 | import com.colobu.rpcx.discovery.IServiceDiscovery; 4 | import com.colobu.rpcx.protocol.Message; 5 | 6 | /** 7 | * @author goodjava@qq.com 8 | */ 9 | public interface IClient { 10 | 11 | Message call(Message req, long timeOut, String sendType) throws Exception; 12 | 13 | Message call(String addr, Message req, long timeOut) throws Exception; 14 | 15 | IServiceDiscovery getServiceDiscovery(); 16 | 17 | void close(); 18 | 19 | } 20 | 21 | 22 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/netty/NettyClientHandler.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.netty; 2 | 3 | import com.colobu.rpcx.protocol.RemotingCommand; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.SimpleChannelInboundHandler; 6 | 7 | /** 8 | * @author goodjava@qq.com 9 | */ 10 | public class NettyClientHandler extends SimpleChannelInboundHandler { 11 | 12 | private final NettyRemotingAbstract nettyClient; 13 | 14 | public NettyClientHandler(NettyRemotingAbstract nettyClient) { 15 | this.nettyClient = nettyClient; 16 | } 17 | 18 | @Override 19 | protected void channelRead0(ChannelHandlerContext ctx, RemotingCommand msg) { 20 | nettyClient.processMessageReceived(ctx, msg); 21 | } 22 | 23 | 24 | } 25 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/netty/NettyConnetManageHandler.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.netty; 2 | 3 | import com.colobu.rpcx.common.RemotingHelper; 4 | import io.netty.channel.ChannelDuplexHandler; 5 | import io.netty.channel.ChannelHandlerContext; 6 | import io.netty.channel.ChannelPromise; 7 | import io.netty.handler.timeout.IdleState; 8 | import io.netty.handler.timeout.IdleStateEvent; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | import java.net.SocketAddress; 13 | 14 | import static com.colobu.rpcx.common.RemotingUtil.closeChannel; 15 | 16 | /** 17 | * @author goodjava@qq.com 18 | */ 19 | public class NettyConnetManageHandler extends ChannelDuplexHandler { 20 | 21 | private static final Logger log = LoggerFactory.getLogger(NettyConnetManageHandler.class); 22 | 23 | private final NettyRemotingAbstract nettyRemotingAbstract; 24 | 25 | public NettyConnetManageHandler(NettyRemotingAbstract nettyRemotingAbstract) { 26 | this.nettyRemotingAbstract = nettyRemotingAbstract; 27 | } 28 | 29 | @Override 30 | public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) 31 | throws Exception { 32 | final String local = localAddress == null ? "UNKNOW" : localAddress.toString(); 33 | final String remote = remoteAddress == null ? "UNKNOW" : remoteAddress.toString(); 34 | log.info("NETTY CLIENT PIPELINE: CONNECT {} => {}", local, remote); 35 | super.connect(ctx, remoteAddress, localAddress, promise); 36 | 37 | if (nettyRemotingAbstract.hasEventListener()) { 38 | nettyRemotingAbstract.putNettyEvent(new NettyEvent(NettyEventType.CONNECT, remoteAddress.toString(), ctx.channel())); 39 | } 40 | } 41 | 42 | 43 | @Override 44 | public void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { 45 | final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); 46 | log.info("NETTY CLIENT PIPELINE: DISCONNECT {}", remoteAddress); 47 | closeChannel(ctx.channel()); 48 | super.disconnect(ctx, promise); 49 | 50 | if (nettyRemotingAbstract.hasEventListener()) { 51 | nettyRemotingAbstract.putNettyEvent(new NettyEvent(NettyEventType.CLOSE, remoteAddress.toString(), ctx.channel())); 52 | } 53 | } 54 | 55 | 56 | @Override 57 | public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { 58 | final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); 59 | log.info("NETTY CLIENT PIPELINE: CLOSE {}", remoteAddress); 60 | nettyRemotingAbstract.closeChannel(ctx.channel()); 61 | super.close(ctx, promise); 62 | 63 | if (nettyRemotingAbstract.hasEventListener()) { 64 | nettyRemotingAbstract.putNettyEvent(new NettyEvent(NettyEventType.CLOSE, remoteAddress.toString(), ctx.channel())); 65 | } 66 | } 67 | 68 | @Override 69 | public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { 70 | if (evt instanceof IdleStateEvent) { 71 | IdleStateEvent evnet = (IdleStateEvent) evt; 72 | if (evnet.state().equals(IdleState.ALL_IDLE)) { 73 | final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); 74 | log.warn("NETTY CLIENT PIPELINE: IDLE exception [{}]", remoteAddress); 75 | closeChannel(ctx.channel()); 76 | if (nettyRemotingAbstract.hasEventListener()) { 77 | nettyRemotingAbstract 78 | .putNettyEvent(new NettyEvent(NettyEventType.IDLE, remoteAddress.toString(), ctx.channel())); 79 | } 80 | } 81 | } 82 | 83 | ctx.fireUserEventTriggered(evt); 84 | } 85 | 86 | @Override 87 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 88 | final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel()); 89 | log.warn("NETTY CLIENT PIPELINE: exceptionCaught {}", remoteAddress); 90 | log.warn("NETTY CLIENT PIPELINE: exceptionCaught exception.", cause); 91 | closeChannel(ctx.channel()); 92 | if (nettyRemotingAbstract.hasEventListener()) { 93 | nettyRemotingAbstract.putNettyEvent(new NettyEvent(NettyEventType.EXCEPTION, remoteAddress.toString(), ctx.channel())); 94 | } 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/netty/NettyDecoder.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.netty; 2 | 3 | import com.colobu.rpcx.protocol.Message; 4 | import com.colobu.rpcx.protocol.RemotingCommand; 5 | import com.colobu.rpcx.rpc.RpcException; 6 | import io.netty.buffer.ByteBuf; 7 | import io.netty.channel.ChannelHandlerContext; 8 | import io.netty.handler.codec.ReplayingDecoder; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * @author goodjava@qq.com 14 | */ 15 | public class NettyDecoder extends ReplayingDecoder { 16 | 17 | private Message message = null; 18 | 19 | public NettyDecoder() { 20 | super(DecoderState.MagicNumber); 21 | } 22 | 23 | @Override 24 | protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) { 25 | switch (state()) { 26 | case MagicNumber: 27 | message = new Message(); 28 | byte magicNumber = in.readByte(); 29 | if (magicNumber != Message.magicNumber) { 30 | throw new RpcException("magicNumber error:" + magicNumber); 31 | } 32 | checkpoint(DecoderState.Header); 33 | case Header: 34 | byte[] header = new byte[12]; 35 | header[0] = Message.magicNumber; 36 | in.readBytes(header, 1, 11); 37 | message.header = header; 38 | checkpoint(DecoderState.Body); 39 | case Body: 40 | int totalLen = in.readInt(); 41 | byte[] data = new byte[totalLen]; 42 | in.readBytes(data); 43 | RemotingCommand command = new RemotingCommand(message, data); 44 | checkpoint(DecoderState.MagicNumber); 45 | //业务解码交给业务层 46 | out.add(command); 47 | break; 48 | default: 49 | throw new RpcException("Shouldn't reach here."); 50 | } 51 | } 52 | 53 | 54 | } 55 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/netty/NettyEncoder.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.netty; 2 | 3 | import com.colobu.rpcx.common.RemotingHelper; 4 | import com.colobu.rpcx.common.RemotingUtil; 5 | import com.colobu.rpcx.protocol.RemotingCommand; 6 | import io.netty.buffer.ByteBuf; 7 | import io.netty.channel.ChannelHandlerContext; 8 | import io.netty.handler.codec.MessageToByteEncoder; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | import java.nio.ByteBuffer; 13 | 14 | /** 15 | * @author goodjava@qq.com 16 | */ 17 | public class NettyEncoder extends MessageToByteEncoder { 18 | 19 | private static final Logger log = LoggerFactory.getLogger(NettyEncoder.class); 20 | 21 | @Override 22 | public void encode(ChannelHandlerContext ctx, RemotingCommand remotingCommand, ByteBuf out) { 23 | try { 24 | byte[] data = remotingCommand.getMessage().encode(); 25 | out.writeBytes(data); 26 | } catch (Exception e) { 27 | log.error("encode exception, " + RemotingHelper.parseChannelRemoteAddr(ctx.channel()), e); 28 | if (remotingCommand != null) { 29 | log.error(remotingCommand.toString()); 30 | } 31 | RemotingUtil.closeChannel(ctx.channel()); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/netty/NettyEvent.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.netty; 2 | 3 | import io.netty.channel.Channel; 4 | 5 | /** 6 | * @author goodjava@qq.com 7 | */ 8 | public class NettyEvent { 9 | 10 | private final NettyEventType type; 11 | private final String remoteAddr; 12 | private final Channel channel; 13 | 14 | 15 | public NettyEvent(NettyEventType type, String remoteAddr, Channel channel) { 16 | this.type = type; 17 | this.remoteAddr = remoteAddr; 18 | this.channel = channel; 19 | } 20 | 21 | 22 | public NettyEventType getType() { 23 | return type; 24 | } 25 | 26 | 27 | public String getRemoteAddr() { 28 | return remoteAddr; 29 | } 30 | 31 | 32 | public Channel getChannel() { 33 | return channel; 34 | } 35 | 36 | 37 | @Override 38 | public String toString() { 39 | return "NettyEvent [type=" + type + ", remoteAddr=" + remoteAddr + ", channel=" + channel + "]"; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/netty/NettyEventExecuter.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.netty; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.util.concurrent.LinkedBlockingQueue; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | /** 10 | * @author goodjava@qq.com 11 | */ 12 | public class NettyEventExecuter implements Runnable { 13 | 14 | 15 | private static final Logger logger = LoggerFactory.getLogger(NettyEventExecuter.class); 16 | 17 | private final LinkedBlockingQueue eventQueue = new LinkedBlockingQueue(); 18 | 19 | private final int maxSize = 10000; 20 | 21 | private volatile boolean stop = false; 22 | 23 | public void putNettyEvent(final NettyEvent event) { 24 | if (this.eventQueue.size() <= maxSize) { 25 | this.eventQueue.add(event); 26 | } else { 27 | logger.warn("event queue size[{}] enough, so drop this event {}", this.eventQueue.size(), event.toString()); 28 | } 29 | } 30 | 31 | 32 | @Override 33 | public void run() { 34 | final ChannelEventListener listener = null; 35 | while (!this.isStoped()) { 36 | try { 37 | NettyEvent event = this.eventQueue.poll(3000, TimeUnit.MILLISECONDS); 38 | if (event != null && listener != null) { 39 | switch (event.getType()) { 40 | case IDLE: 41 | listener.onChannelIdle(event.getRemoteAddr(), event.getChannel()); 42 | break; 43 | case CLOSE: 44 | listener.onChannelClose(event.getRemoteAddr(), event.getChannel()); 45 | break; 46 | case CONNECT: 47 | listener.onChannelConnect(event.getRemoteAddr(), event.getChannel()); 48 | break; 49 | case EXCEPTION: 50 | listener.onChannelException(event.getRemoteAddr(), event.getChannel()); 51 | break; 52 | default: 53 | break; 54 | 55 | } 56 | } 57 | } catch (Exception e) { 58 | logger.warn(this.getServiceName() + " service has exception. ", e); 59 | } 60 | } 61 | logger.info(this.getServiceName() + " service end"); 62 | } 63 | 64 | private boolean isStoped() { 65 | return stop; 66 | } 67 | 68 | public void shutdown() { 69 | this.stop = true; 70 | } 71 | 72 | private String getServiceName() { 73 | return null; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/netty/NettyEventType.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.netty; 2 | 3 | /** 4 | * @author goodjava@qq.com 5 | */ 6 | public enum NettyEventType { 7 | /** 8 | * 连接 9 | */ 10 | CONNECT, 11 | 12 | /** 13 | * 关闭 14 | */ 15 | CLOSE, 16 | 17 | /** 18 | * 空闲 19 | */ 20 | IDLE, 21 | 22 | /** 23 | * 异常 24 | */ 25 | EXCEPTION 26 | } 27 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/netty/NettyRequestProcessor.java: -------------------------------------------------------------------------------- 1 | 2 | package com.colobu.rpcx.netty; 3 | 4 | import com.colobu.rpcx.protocol.RemotingCommand; 5 | import io.netty.channel.ChannelHandlerContext; 6 | 7 | /** 8 | * @author goodjava@qq.com 9 | */ 10 | public interface NettyRequestProcessor { 11 | RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request) 12 | throws Exception; 13 | boolean rejectRequest(); 14 | } 15 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/netty/NettyServerConfig.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.netty; 2 | 3 | import com.colobu.rpcx.common.Config; 4 | 5 | /** 6 | * @author goodjava@qq.com 7 | */ 8 | public class NettyServerConfig implements Cloneable { 9 | private int listenPort = 8888; 10 | private int serverWorkerThreads = Runtime.getRuntime().availableProcessors() * 2; 11 | private int serverCallbackExecutorThreads = 0; 12 | private int serverOnewaySemaphoreValue = 256; 13 | private int serverAsyncSemaphoreValue = 64; 14 | private int serverChannelMaxIdleTimeSeconds = 120; 15 | 16 | private int serverSocketSndBufSize = 1024 * 64; 17 | private int serverSocketRcvBufSize = 1024 * 64; 18 | 19 | //业务的线程数 20 | private int serverBizThreads = 1000; 21 | 22 | 23 | public int getServerBizThreads() { 24 | int num = Integer.valueOf(Config.ins().get("rpcx.biz.processor.num", String.valueOf(serverBizThreads))); 25 | return num; 26 | } 27 | 28 | public int getListenPort() { 29 | return listenPort; 30 | } 31 | 32 | 33 | public void setListenPort(int listenPort) { 34 | this.listenPort = listenPort; 35 | } 36 | 37 | 38 | public int getServerWorkerThreads() { 39 | int num = Integer.valueOf(Config.ins().get("rpcx.worker.processor.num", String.valueOf(serverWorkerThreads))); 40 | return num; 41 | } 42 | 43 | 44 | public void setServerWorkerThreads(int serverWorkerThreads) { 45 | this.serverWorkerThreads = serverWorkerThreads; 46 | } 47 | 48 | 49 | public int getServerOnewaySemaphoreValue() { 50 | return serverOnewaySemaphoreValue; 51 | } 52 | 53 | 54 | public void setServerOnewaySemaphoreValue(int serverOnewaySemaphoreValue) { 55 | this.serverOnewaySemaphoreValue = serverOnewaySemaphoreValue; 56 | } 57 | 58 | 59 | public int getServerCallbackExecutorThreads() { 60 | return serverCallbackExecutorThreads; 61 | } 62 | 63 | 64 | public void setServerCallbackExecutorThreads(int serverCallbackExecutorThreads) { 65 | this.serverCallbackExecutorThreads = serverCallbackExecutorThreads; 66 | } 67 | 68 | 69 | public int getServerAsyncSemaphoreValue() { 70 | return serverAsyncSemaphoreValue; 71 | } 72 | 73 | 74 | public void setServerAsyncSemaphoreValue(int serverAsyncSemaphoreValue) { 75 | this.serverAsyncSemaphoreValue = serverAsyncSemaphoreValue; 76 | } 77 | 78 | 79 | public int getServerChannelMaxIdleTimeSeconds() { 80 | return serverChannelMaxIdleTimeSeconds; 81 | } 82 | 83 | 84 | public void setServerChannelMaxIdleTimeSeconds(int serverChannelMaxIdleTimeSeconds) { 85 | this.serverChannelMaxIdleTimeSeconds = serverChannelMaxIdleTimeSeconds; 86 | } 87 | 88 | 89 | public int getServerSocketSndBufSize() { 90 | int size = Integer.valueOf(Config.ins().get("rpcx.snd.buf.size", String.valueOf(serverSocketSndBufSize))); 91 | return size; 92 | } 93 | 94 | 95 | public int getServerSocketRcvBufSize() { 96 | int size = Integer.valueOf(Config.ins().get("rpcx.rcv.buf.size", String.valueOf(serverSocketRcvBufSize))); 97 | return size; 98 | } 99 | 100 | 101 | @Override 102 | public Object clone() throws CloneNotSupportedException { 103 | return (NettyServerConfig) super.clone(); 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/netty/NettyServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.netty; 2 | 3 | import com.colobu.rpcx.protocol.RemotingCommand; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.SimpleChannelInboundHandler; 6 | 7 | /** 8 | * @author goodjava@qq.com 9 | */ 10 | public class NettyServerHandler extends SimpleChannelInboundHandler { 11 | 12 | private final NettyRemotingAbstract nettyServer; 13 | 14 | public NettyServerHandler(NettyRemotingAbstract nettyClient) { 15 | this.nettyServer = nettyClient; 16 | } 17 | 18 | @Override 19 | protected void channelRead0(ChannelHandlerContext ctx, RemotingCommand msg) { 20 | nettyServer.processMessageReceived(ctx, msg); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/netty/RequestTask.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.netty; 2 | 3 | 4 | import com.colobu.rpcx.protocol.RemotingCommand; 5 | import io.netty.channel.Channel; 6 | 7 | /** 8 | * @author goodjava@qq.com 9 | */ 10 | public class RequestTask implements Runnable { 11 | private final Runnable runnable; 12 | private final long createTimestamp = System.currentTimeMillis(); 13 | private final Channel channel; 14 | private final RemotingCommand request; 15 | private boolean stopRun = false; 16 | 17 | public RequestTask(final Runnable runnable, final Channel channel, final RemotingCommand request) { 18 | this.runnable = runnable; 19 | this.channel = channel; 20 | this.request = request; 21 | } 22 | 23 | @Override 24 | public int hashCode() { 25 | int result = runnable != null ? runnable.hashCode() : 0; 26 | result = 31 * result + (int) (getCreateTimestamp() ^ (getCreateTimestamp() >>> 32)); 27 | result = 31 * result + (channel != null ? channel.hashCode() : 0); 28 | result = 31 * result + (request != null ? request.hashCode() : 0); 29 | result = 31 * result + (isStopRun() ? 1 : 0); 30 | return result; 31 | } 32 | 33 | @Override 34 | public boolean equals(final Object o) { 35 | if (this == o) { 36 | return true; 37 | } 38 | if (!(o instanceof RequestTask)) { 39 | return false; 40 | } 41 | 42 | final RequestTask that = (RequestTask) o; 43 | 44 | if (getCreateTimestamp() != that.getCreateTimestamp()) { 45 | return false; 46 | } 47 | if (isStopRun() != that.isStopRun()) { 48 | return false; 49 | } 50 | if (channel != null ? !channel.equals(that.channel) : that.channel != null) { 51 | return false; 52 | } 53 | return request != null ? request.getOpaque() == that.request.getOpaque() : that.request == null; 54 | 55 | } 56 | 57 | public long getCreateTimestamp() { 58 | return createTimestamp; 59 | } 60 | 61 | public boolean isStopRun() { 62 | return stopRun; 63 | } 64 | 65 | public void setStopRun(final boolean stopRun) { 66 | this.stopRun = stopRun; 67 | } 68 | 69 | @Override 70 | public void run() { 71 | if (!this.stopRun) { 72 | this.runnable.run(); 73 | } 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/protocol/CommandCustomHeader.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.protocol; 2 | 3 | /** 4 | * Created by goodjava@qq.com. 5 | */ 6 | public class CommandCustomHeader { 7 | } 8 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/protocol/CompressType.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.protocol; 2 | 3 | /** 4 | * Created by goodjava@qq.com. 5 | */ 6 | public enum CompressType { 7 | /** 8 | * 不压缩 9 | */ 10 | None(0), 11 | /** 12 | * gzip压缩 13 | */ 14 | Gzip(1); 15 | 16 | 17 | private final int v; 18 | 19 | CompressType(int v) { 20 | this.v = v; 21 | } 22 | 23 | private static CompressType[] values = CompressType.values(); 24 | public static CompressType getValue(int i) { 25 | return values[i]; 26 | } 27 | 28 | public int value() { 29 | return v; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/protocol/DefaultCommandHeader.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.protocol; 2 | 3 | 4 | /** 5 | * Created by goodjava@qq.com. 6 | */ 7 | public class DefaultCommandHeader extends CommandCustomHeader { 8 | } 9 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/protocol/LanguageCode.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.protocol; 2 | 3 | /** 4 | * Created by goodjava@qq.com. 5 | */ 6 | public enum LanguageCode { 7 | /** 8 | * java 9 | */ 10 | JAVA, 11 | /** 12 | * go 13 | */ 14 | GO, 15 | /** 16 | * http 17 | */ 18 | HTTP, 19 | } 20 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/protocol/MessageStatusType.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.protocol; 2 | 3 | /** 4 | * Created by goodjava@qq.com. 5 | */ 6 | public enum MessageStatusType { 7 | /** 8 | * 一般 9 | */ 10 | Normal(0), 11 | /** 12 | * 错误 13 | */ 14 | Error(1); 15 | 16 | 17 | private final int v; 18 | 19 | MessageStatusType(int v) { 20 | this.v = v; 21 | } 22 | 23 | private static MessageStatusType[] values = MessageStatusType.values(); 24 | public static MessageStatusType getValue(int i) { 25 | return values[i]; 26 | } 27 | 28 | public int value() { 29 | return v; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/protocol/MessageType.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.protocol; 2 | 3 | /** 4 | * Created by goodjava@qq.com. 5 | */ 6 | public enum MessageType { 7 | /** 8 | * 请求 9 | */ 10 | Request(0), 11 | 12 | /** 13 | * 应答 14 | */ 15 | Response(1); 16 | 17 | 18 | private final int value; 19 | 20 | MessageType(int value) { 21 | this.value = value; 22 | } 23 | 24 | private static MessageType[] values = MessageType.values(); 25 | public static MessageType getValue(int i) { 26 | return values[i]; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/protocol/RemotingCommand.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.protocol; 2 | 3 | import com.colobu.rpcx.config.Constants; 4 | 5 | /** 6 | * Created by goodjava@qq.com. 7 | */ 8 | public class RemotingCommand { 9 | 10 | 11 | private int code = 0; 12 | private int version = 0; 13 | 14 | 15 | /** 16 | * 解码的时候会用到,不会实际传输 17 | */ 18 | private transient byte[] data; 19 | 20 | private Message message; 21 | 22 | public Message getMessage() { 23 | return message; 24 | } 25 | 26 | public void setMessage(Message message) { 27 | this.message = message; 28 | this.setOpaque((int) this.message.getSeq()); 29 | } 30 | 31 | public RemotingCommand() { 32 | } 33 | 34 | public RemotingCommand(Message message, byte[] body) { 35 | this.message = message; 36 | this.data = body; 37 | } 38 | 39 | 40 | public static RemotingCommand createRequestCommand(Message message) { 41 | RemotingCommand cmd = new RemotingCommand(); 42 | cmd.setMessage(message); 43 | return cmd; 44 | } 45 | 46 | 47 | public static RemotingCommand createResponseCommand(Message message) { 48 | RemotingCommand cmd = new RemotingCommand(); 49 | cmd.setMessage(message); 50 | return cmd; 51 | } 52 | 53 | 54 | 55 | public void markResponseType() { 56 | this.message.setMessageType(MessageType.Response); 57 | } 58 | 59 | 60 | public int getCode() { 61 | return code; 62 | } 63 | 64 | public void setCode(int code) { 65 | this.code = code; 66 | } 67 | 68 | public int getVersion() { 69 | return version; 70 | } 71 | 72 | public void setVersion(int version) { 73 | this.version = version; 74 | } 75 | 76 | public int getOpaque() { 77 | return (int) this.message.getSeq(); 78 | } 79 | 80 | public void setOpaque(int opaque) { 81 | this.message.setSeq(opaque); 82 | } 83 | 84 | 85 | public boolean isOnewayRPC() { 86 | return this.message.isOneway(); 87 | } 88 | 89 | 90 | public RemotingCommandType getType() { 91 | if (this.isResponseType()) { 92 | return RemotingCommandType.RESPONSE_COMMAND; 93 | } 94 | return RemotingCommandType.REQUEST_COMMAND; 95 | } 96 | 97 | 98 | public boolean isResponseType() { 99 | return this.message.getMessageType().equals(MessageType.Response); 100 | } 101 | 102 | public void markOnewayRPC() { 103 | this.message.setOneway(true); 104 | } 105 | 106 | public static RemotingCommand createResponseCommand(int errorCode, String errorMessage) { 107 | RemotingCommand cmd = new RemotingCommand(); 108 | cmd.markResponseType(); 109 | cmd.getMessage().setMessageStatusType(MessageStatusType.Error); 110 | cmd.getMessage().metadata.put(Constants.RPCX_ERROR_CODE, String.valueOf(errorCode)); 111 | cmd.getMessage().metadata.put(Constants.RPCX_ERROR_MESSAGE, errorMessage); 112 | return cmd; 113 | } 114 | 115 | public byte[] getData() { 116 | return data; 117 | } 118 | 119 | public void setData(byte[] data) { 120 | this.data = data; 121 | } 122 | 123 | 124 | public void setErrorMessage(int code, String message) { 125 | this.setErrorMessage(String.valueOf(code), message); 126 | } 127 | 128 | 129 | /** 130 | * rpcx 是通过 meta 传递错误信息的 131 | * 132 | * @param code 133 | * @param message 134 | */ 135 | public void setErrorMessage(String code, String message) { 136 | //带有错误的返回结果 137 | this.message.setMessageStatusType(MessageStatusType.Error); 138 | this.message.metadata.put(Constants.RPCX_ERROR_CODE, code); 139 | this.message.metadata.put(Constants.RPCX_ERROR_MESSAGE, message); 140 | } 141 | 142 | public RemotingCommand requestToResponse() { 143 | this.message.setMessageType(MessageType.Response); 144 | this.data = new byte[]{}; 145 | this.message.payload = new byte[]{}; 146 | this.message.metadata.clear(); 147 | return this; 148 | } 149 | 150 | } -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/protocol/RemotingCommandType.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.protocol; 2 | 3 | /** 4 | * Created by goodjava@qq.com. 5 | */ 6 | public enum RemotingCommandType { 7 | 8 | /** 9 | * 请求命令 10 | */ 11 | REQUEST_COMMAND, 12 | 13 | /** 14 | * 应答命令 15 | */ 16 | RESPONSE_COMMAND 17 | } 18 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/protocol/RemotingSysResponseCode.java: -------------------------------------------------------------------------------- 1 | 2 | package com.colobu.rpcx.protocol; 3 | 4 | /** 5 | * Created by goodjava@qq.com. 6 | */ 7 | public class RemotingSysResponseCode { 8 | 9 | public static final int SUCCESS = 0; 10 | 11 | public static final int SYSTEM_ERROR = 1; 12 | 13 | public static final int SYSTEM_BUSY = 2; 14 | 15 | public static final int REQUEST_CODE_NOT_SUPPORTED = 3; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/protocol/SerializeType.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.protocol; 2 | 3 | /** 4 | * Created by goodjava@qq.com. 5 | */ 6 | public enum SerializeType { 7 | 8 | /** 9 | * java序列化 10 | */ 11 | SerializeNone(0), 12 | /** 13 | * json序列化 14 | */ 15 | JSON(1), 16 | /** 17 | * protobuf序列化 18 | */ 19 | ProtoBuffer(2), 20 | /** 21 | * msgpack序列化 22 | */ 23 | MsgPack(3), 24 | 25 | 26 | Thrift(4); 27 | 28 | 29 | private final int v; 30 | 31 | SerializeType(int v) { 32 | this.v = v; 33 | } 34 | 35 | private static SerializeType[] values = SerializeType.values(); 36 | public static SerializeType getValue(int i) { 37 | return values[i]; 38 | } 39 | 40 | public int value() { 41 | return v; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/register/IServiceRegister.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.register; 2 | 3 | /** 4 | * @author goodjava@qq.com 5 | */ 6 | public interface IServiceRegister { 7 | 8 | /** 9 | * 服务注册 10 | */ 11 | void register(); 12 | 13 | /** 14 | * 开启注册服务 15 | */ 16 | void start(); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/rpc/CglibProxy.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.rpc; 2 | 3 | import net.sf.cglib.proxy.Enhancer; 4 | 5 | import java.lang.reflect.Method; 6 | import java.util.function.BiFunction; 7 | 8 | /** 9 | * Created by goodjava@qq.com. 10 | */ 11 | public class CglibProxy { 12 | 13 | 14 | public T getProxy(Class clazz, final BiFunction function) { 15 | Enhancer e = new Enhancer(); 16 | e.setSuperclass(clazz); 17 | e.setCallback((net.sf.cglib.proxy.InvocationHandler) (proxy, method, args) -> { 18 | String methodName = method.getName(); 19 | if ("getClass".equals(methodName)) { 20 | return proxy.getClass(); 21 | } 22 | if ("hashCode".equals(methodName)) { 23 | return proxy.hashCode(); 24 | } 25 | if ("toString".equals(methodName)) { 26 | return proxy.toString(); 27 | } 28 | return function.apply(method, args); 29 | }); 30 | return (T) e.create(); 31 | } 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/rpc/HessianUtils.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.rpc; 2 | 3 | import com.caucho.hessian.io.HessianInput; 4 | import com.caucho.hessian.io.HessianOutput; 5 | 6 | import java.io.ByteArrayInputStream; 7 | import java.io.ByteArrayOutputStream; 8 | import java.io.IOException; 9 | 10 | /** 11 | * @author goodjava@qq.com 12 | */ 13 | public class HessianUtils { 14 | 15 | 16 | private HessianUtils() { 17 | 18 | } 19 | 20 | public static byte[] write(Object obj) { 21 | ByteArrayOutputStream os = new ByteArrayOutputStream(); 22 | HessianOutput ho = new HessianOutput(os); 23 | try { 24 | ho.writeObject(obj); 25 | return os.toByteArray(); 26 | } catch (IOException e) { 27 | throw new RuntimeException(e); 28 | } finally { 29 | try { 30 | ho.close(); 31 | os.close(); 32 | } catch (Exception ex) { 33 | 34 | } 35 | } 36 | } 37 | 38 | 39 | public static Object read(byte[] data) { 40 | ByteArrayInputStream is = new ByteArrayInputStream(data); 41 | HessianInput hi = new HessianInput(is); 42 | try { 43 | return hi.readObject(); 44 | } catch (IOException e) { 45 | throw new RuntimeException(e); 46 | } finally { 47 | try { 48 | hi.close(); 49 | is.close(); 50 | } catch (Exception ex) { 51 | 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/rpc/Invocation.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.rpc; 2 | 3 | import java.util.Map; 4 | 5 | 6 | /** 7 | * Created by goodjava@qq.com. 8 | */ 9 | public interface Invocation { 10 | 11 | String getMethodName(); 12 | 13 | String getClassName(); 14 | 15 | Class[] getParameterTypes(); 16 | 17 | String[] getParameterTypeNames(); 18 | 19 | Object[] getArguments(); 20 | 21 | Map getAttachments(); 22 | 23 | String getAttachment(String key); 24 | 25 | String getAttachment(String key, String defaultValue); 26 | 27 | Invoker getInvoker(); 28 | 29 | Class getResultType(); 30 | 31 | void setArguments(Object[] arguments); 32 | 33 | void setParameterTypeNames(String[] parameterTypeNames); 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/rpc/Invoker.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.rpc; 2 | 3 | import com.colobu.rpcx.discovery.IServiceDiscovery; 4 | import com.colobu.rpcx.rpc.impl.RpcInvocation; 5 | import com.esotericsoftware.reflectasm.MethodAccess; 6 | 7 | import java.lang.reflect.Method; 8 | 9 | 10 | /** 11 | * @author goodjava@qq.com 12 | */ 13 | public interface Invoker extends Node { 14 | 15 | Class getInterface(); 16 | 17 | Result invoke(RpcInvocation invocation) throws RpcException; 18 | 19 | void setMethod(Method method); 20 | 21 | default void setMethodAccess(MethodAccess methodAccess){ 22 | 23 | } 24 | 25 | Method getMethod(); 26 | 27 | void setInterface(Class clazz); 28 | 29 | /** 30 | * 服务发现 31 | * @return 32 | */ 33 | default IServiceDiscovery serviceDiscovery() { 34 | return null; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/rpc/Node.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.rpc; 2 | 3 | /** 4 | * Created by goodjava@qq.com. 5 | */ 6 | public interface Node { 7 | 8 | URL getUrl(); 9 | 10 | void setUrl(URL url); 11 | 12 | boolean isAvailable(); 13 | 14 | void destroy(); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/rpc/Protocol.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.rpc; 2 | 3 | /** 4 | * Created by goodjava@qq.com. 5 | */ 6 | public class Protocol { 7 | } 8 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/rpc/Result.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.rpc; 2 | 3 | import java.util.Map; 4 | 5 | 6 | /** 7 | * Created by goodjava@qq.com. 8 | */ 9 | public interface Result { 10 | 11 | void setValue(Object value); 12 | 13 | Object getValue(); 14 | 15 | Throwable getException(); 16 | 17 | boolean hasException(); 18 | 19 | Map getAttachments(); 20 | 21 | String getAttachment(String key); 22 | 23 | String getAttachment(String key, String defaultValue); 24 | 25 | void setThrowable(Throwable throwable); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/rpc/RpcException.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.rpc; 2 | 3 | 4 | /** 5 | * @author goodjava@qq.com 6 | */ 7 | public class RpcException extends RuntimeException { 8 | 9 | private String code; 10 | 11 | public RpcException(String message, String code) { 12 | super(message); 13 | this.code = code; 14 | } 15 | 16 | public RpcException(String message, Throwable cause, String code) { 17 | super(message, cause); 18 | this.code = code; 19 | } 20 | 21 | public RpcException(Throwable cause) { 22 | super(cause); 23 | } 24 | 25 | public RpcException(String message) { 26 | super(message); 27 | } 28 | 29 | public RpcException(Exception ex) { 30 | super(ex); 31 | } 32 | 33 | 34 | public String getCode() { 35 | return code; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/rpc/annotation/Consumer.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.rpc.annotation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | 6 | /** 7 | * Created by goodjava@qq.com. 8 | */ 9 | @Retention(RetentionPolicy.RUNTIME) 10 | @Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE}) 11 | @Documented 12 | public @interface Consumer { 13 | 14 | String impl(); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/rpc/annotation/Provider.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.rpc.annotation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | 6 | /** 7 | * Created by goodjava@qq.com. 8 | */ 9 | @Retention(RetentionPolicy.RUNTIME) 10 | @Target({ElementType.TYPE, ElementType.METHOD, ElementType.ANNOTATION_TYPE}) 11 | @Documented 12 | public @interface Provider { 13 | 14 | String group() default ""; 15 | 16 | String name() default ""; 17 | 18 | String version() default ""; 19 | 20 | String[] excludeFilters() default ""; 21 | 22 | /** 23 | * 服务启动token验证,客户端需要提供相同的token 24 | * 25 | * @return 26 | */ 27 | String token() default ""; 28 | 29 | /** 30 | * 服务器超时调用后会打印警告,不影响正常调用 31 | * 超时filter 32 | * 33 | * @return 34 | */ 35 | long timeout() default -1; 36 | 37 | /** 38 | * 缓存filter 39 | * 40 | * @return 41 | */ 42 | boolean cache() default false; 43 | 44 | /** 45 | * 是否开启监控 46 | * 监控filter 47 | * 48 | * @return 49 | */ 50 | boolean monitor() default false; 51 | 52 | /** 53 | * 一分钟内tps 能达到的上限 -1 是没有上限 54 | * tps filter 55 | * 56 | * @return 57 | */ 58 | int tps() default -1; 59 | 60 | /** 61 | * 权重 62 | * 63 | * @return 64 | */ 65 | String weight() default ""; 66 | 67 | } 68 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/rpc/annotation/RpcFilter.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.rpc.annotation; 2 | 3 | 4 | import java.lang.annotation.*; 5 | 6 | 7 | /** 8 | * Created by goodjava@qq.com. 9 | */ 10 | @Retention(RetentionPolicy.RUNTIME) 11 | @Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE}) 12 | @Documented 13 | public @interface RpcFilter { 14 | 15 | //数字越小的越先执行 16 | int order() default 0; 17 | 18 | String[] group() default {}; 19 | 20 | } 21 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/rpc/impl/ConsumerFinder.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.rpc.impl; 2 | 3 | import com.colobu.rpcx.rpc.annotation.Consumer; 4 | import com.colobu.rpcx.rpc.annotation.Provider; 5 | import org.reflections.Reflections; 6 | 7 | import java.util.Set; 8 | import java.util.stream.Collectors; 9 | 10 | /** 11 | * @author goodjava@qq.com 12 | */ 13 | public class ConsumerFinder { 14 | 15 | public Set find(String consumerPackage) { 16 | Reflections reflections = new Reflections(consumerPackage); 17 | //不包括实现类 18 | Set> classesList = reflections.getTypesAnnotatedWith(Consumer.class,true); 19 | return classesList.stream().map(it->{ 20 | Consumer consumer = it.getAnnotation(Consumer.class); 21 | return consumer.impl(); 22 | }).collect(Collectors.toSet()); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/rpc/impl/ProviderFinder.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.rpc.impl; 2 | 3 | import com.colobu.rpcx.rpc.annotation.Provider; 4 | import org.reflections.Reflections; 5 | 6 | import java.util.Set; 7 | 8 | 9 | /** 10 | * @author goodjava@qq.com 11 | */ 12 | public class ProviderFinder { 13 | 14 | private final String providerPackage; 15 | 16 | public ProviderFinder(String providerPackage) { 17 | this.providerPackage = providerPackage; 18 | } 19 | 20 | 21 | public Set> find() { 22 | Reflections reflections = new Reflections(providerPackage); 23 | Set> classesList = reflections.getTypesAnnotatedWith(Provider.class); 24 | return classesList; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/rpc/impl/RpcFilterFinder.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.rpc.impl; 2 | 3 | import com.colobu.rpcx.rpc.annotation.RpcFilter; 4 | import org.reflections.Reflections; 5 | 6 | import java.util.List; 7 | import java.util.Set; 8 | import java.util.stream.Collectors; 9 | import java.util.stream.Stream; 10 | 11 | /** 12 | * Created by goodjava@qq.com. 13 | */ 14 | public class RpcFilterFinder { 15 | 16 | private final String filterPackage; 17 | private final String group; 18 | 19 | public RpcFilterFinder(String providerPackage, String group) { 20 | this.filterPackage = providerPackage; 21 | this.group = group; 22 | } 23 | 24 | 25 | public List find() { 26 | Reflections reflections = new Reflections(filterPackage); 27 | Set> classesList = reflections.getTypesAnnotatedWith(RpcFilter.class); 28 | List list = classesList.stream().filter(it -> { 29 | RpcFilter an = it.getAnnotation(RpcFilter.class); 30 | return Stream.of(an.group()).anyMatch(it2 -> it2.equals(group));//过滤出provider 31 | }).collect(Collectors.toList()); 32 | return list.stream().sorted((a, b) -> { 33 | RpcFilter a1 = (RpcFilter) a.getAnnotation(RpcFilter.class); 34 | RpcFilter b1 = (RpcFilter) b.getAnnotation(RpcFilter.class); 35 | return a1.order() - b1.order(); 36 | }).collect(Collectors.toList()); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/rpc/impl/RpcResult.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.rpc.impl; 2 | 3 | import com.colobu.rpcx.rpc.Result; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | 7 | /** 8 | * @author goodjava@qq.com 9 | */ 10 | public class RpcResult implements Result { 11 | 12 | private Object value; 13 | 14 | private Throwable throwable; 15 | 16 | private Map attachments = new HashMap<>(); 17 | 18 | public RpcResult(Object value) { 19 | this.value = value; 20 | } 21 | 22 | public RpcResult() { 23 | } 24 | 25 | 26 | public RpcResult(Throwable throwable) { 27 | this.throwable = throwable; 28 | } 29 | 30 | @Override 31 | public void setValue(Object value) { 32 | this.value = value; 33 | } 34 | 35 | @Override 36 | public Object getValue() { 37 | return value; 38 | } 39 | 40 | @Override 41 | public Throwable getException() { 42 | return this.throwable; 43 | } 44 | 45 | @Override 46 | public void setThrowable(Throwable throwable) { 47 | this.throwable = throwable; 48 | } 49 | 50 | @Override 51 | public boolean hasException() { 52 | return null != throwable; 53 | } 54 | 55 | @Override 56 | public Map getAttachments() { 57 | return attachments; 58 | } 59 | 60 | @Override 61 | public String getAttachment(String key) { 62 | return this.attachments.get(key); 63 | } 64 | 65 | @Override 66 | public String getAttachment(String key, String defaultValue) { 67 | String result = attachments.get(key); 68 | if (result == null || result.length() == 0) { 69 | result = defaultValue; 70 | } 71 | return result; 72 | } 73 | 74 | 75 | } 76 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/selector/SelectMode.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.selector; 2 | 3 | public enum SelectMode { 4 | /** 5 | * RandomSelect is selecting randomly 6 | */ 7 | RandomSelect, 8 | /** 9 | * RoundRobin is selecting by round robin 10 | */ 11 | RoundRobin, 12 | /** 13 | * WeightedRoundRobin is selecting by weighted round robin 14 | */ 15 | WeightedRoundRobin, 16 | /** 17 | * SelectByUser is selecting by implementation of users 18 | */ 19 | SelectByUser, 20 | } 21 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/selector/Weighted.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.selector; 2 | 3 | public class Weighted { 4 | 5 | public String server; 6 | public int weight; 7 | public int currentWeight; 8 | public int effectiveWeight; 9 | 10 | public Weighted(String server, int weight) { 11 | this.server = server; 12 | this.weight = weight; 13 | } 14 | 15 | public String getServer() { 16 | return server; 17 | } 18 | 19 | public void setServer(String server) { 20 | this.server = server; 21 | } 22 | 23 | public int getWeight() { 24 | return weight; 25 | } 26 | 27 | public void setWeight(int weight) { 28 | this.weight = weight; 29 | } 30 | 31 | public int getCurrentWeight() { 32 | return currentWeight; 33 | } 34 | 35 | public void setCurrentWeight(int currentWeight) { 36 | this.currentWeight = currentWeight; 37 | } 38 | 39 | public int getEffectiveWeight() { 40 | return effectiveWeight; 41 | } 42 | 43 | public void setEffectiveWeight(int effectiveWeight) { 44 | this.effectiveWeight = effectiveWeight; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/selector/WeightedRountRobin.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.selector; 2 | 3 | import com.colobu.rpcx.rpc.URL; 4 | 5 | import java.util.Arrays; 6 | import java.util.List; 7 | import java.util.stream.Collectors; 8 | 9 | /** 10 | * @author goodjava@qq.com 11 | *

12 | * https://github.com/phusion/nginx/commit/27e94984486058d73157038f7950a0a36ecc6e35 13 | */ 14 | public class WeightedRountRobin { 15 | 16 | private List weighteds; 17 | 18 | public WeightedRountRobin(Weighted[] weighteds) { 19 | this.weighteds = Arrays.asList(weighteds); 20 | } 21 | 22 | 23 | private boolean contains(URL url) { 24 | String weight = url.getParameter("weight"); 25 | String address = url.getAddress(); 26 | 27 | return weighteds.stream().anyMatch((it) -> { 28 | if (it.getServer().equals(address) && it.getWeight() == Integer.parseInt(weight)) { 29 | return true; 30 | } 31 | return false; 32 | }); 33 | 34 | } 35 | 36 | 37 | private boolean contains(List serverList, Weighted weighted) { 38 | return serverList.stream().anyMatch(it -> { 39 | URL url = URL.valueOf(it); 40 | if (url.getAddress().equals(weighted.server) && url.getParameter("weight").equals(String.valueOf(weighted.weight))) { 41 | return true; 42 | } 43 | return false; 44 | }); 45 | } 46 | 47 | 48 | /** 49 | * 有可能会有服务器下线或上线 50 | * 51 | * @param serviceList 52 | */ 53 | public void updateWeighteds(List serviceList) { 54 | 55 | this.weighteds = weighteds.stream().filter(it -> { 56 | return contains(serviceList, it); 57 | }).collect(Collectors.toList()); 58 | 59 | serviceList.stream().forEach(it -> { 60 | URL url = URL.valueOf(it); 61 | if (!contains(url)) { 62 | weighteds.add(new Weighted(url.getAddress(), Integer.parseInt(url.getParameter("weight")))); 63 | } 64 | }); 65 | 66 | } 67 | 68 | 69 | public WeightedRountRobin(List serviceList) { 70 | Weighted[] weighteds = serviceList.stream().map(it -> { 71 | URL url = URL.valueOf(it); 72 | Weighted weighted = new Weighted(url.getAddress(), Integer.parseInt(url.getParameter("weight"))); 73 | return weighted; 74 | }).toArray(Weighted[]::new); 75 | this.weighteds = Arrays.asList(weighteds); 76 | } 77 | 78 | public Weighted nextWeighted() { 79 | Weighted best = null; 80 | 81 | int total = 0; 82 | 83 | for (int i = 0; i < weighteds.size(); i++) { 84 | Weighted w = weighteds.get(i); 85 | 86 | if (w == null) { 87 | continue; 88 | } 89 | //if w is down, continue 90 | 91 | w.currentWeight += w.effectiveWeight; 92 | total += w.effectiveWeight; 93 | if (w.effectiveWeight < w.weight) { 94 | w.effectiveWeight++; 95 | } 96 | 97 | if (best == null || w.currentWeight > best.currentWeight) { 98 | best = w; 99 | } 100 | 101 | } 102 | 103 | if (best == null) { 104 | return null; 105 | } 106 | 107 | best.currentWeight -= total; 108 | return best; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/tps/DefaultTPSLimiter.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.tps; 2 | 3 | 4 | import com.colobu.rpcx.config.Constants; 5 | import com.colobu.rpcx.rpc.Invocation; 6 | import com.colobu.rpcx.rpc.URL; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import java.util.concurrent.ConcurrentHashMap; 11 | import java.util.concurrent.ConcurrentMap; 12 | 13 | /** 14 | * @author goodjava@qq.com 15 | */ 16 | public class DefaultTPSLimiter implements TPSLimiter { 17 | 18 | private static final Logger logger = LoggerFactory.getLogger(DefaultTPSLimiter.class); 19 | 20 | private final ConcurrentMap stats = new ConcurrentHashMap<>(); 21 | 22 | @Override 23 | public boolean isAllowable(URL url, Invocation invocation) { 24 | int rate = url.getParameter(Constants.TPS_LIMIT_RATE_KEY, -1); 25 | //默认时间间隔是60秒 26 | long interval = url.getParameter(Constants.TPS_LIMIT_INTERVAL_KEY, Constants.DEFAULT_TPS_LIMIT_INTERVAL); 27 | String serviceKey = url.getServiceKey(); 28 | logger.debug("DefaultTPSLimiter interval:{} serviceKey:{}",interval,serviceKey); 29 | if (rate > 0) { 30 | StatItem statItem = stats.get(serviceKey); 31 | if (statItem == null) { 32 | stats.putIfAbsent(serviceKey, 33 | new StatItem(serviceKey, rate, interval)); 34 | statItem = stats.get(serviceKey); 35 | } 36 | return statItem.isAllowable(); 37 | } else {//如果不开启,删除之前记录的即可 38 | StatItem statItem = stats.get(serviceKey); 39 | if (statItem != null) { 40 | stats.remove(serviceKey); 41 | } 42 | } 43 | 44 | return true; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/tps/StatItem.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.tps; 2 | 3 | 4 | import java.util.concurrent.atomic.AtomicInteger; 5 | 6 | class StatItem { 7 | 8 | private String name; 9 | 10 | private long lastResetTime; 11 | 12 | private long interval; 13 | 14 | private AtomicInteger token; 15 | 16 | private int rate; 17 | 18 | StatItem(String name, int rate, long interval) { 19 | this.name = name; 20 | this.rate = rate; 21 | this.interval = interval; 22 | this.lastResetTime = System.currentTimeMillis(); 23 | this.token = new AtomicInteger(rate); 24 | } 25 | 26 | public boolean isAllowable() { 27 | long now = System.currentTimeMillis(); 28 | if (now > lastResetTime + interval) {//如果超过了限流时间,则数量和时间和rate都重置 29 | token.set(rate); 30 | lastResetTime = now; 31 | } 32 | 33 | int value = token.get(); 34 | boolean flag = false; 35 | while (value > 0 && !flag) {//如果小于0了则直接返回false 36 | flag = token.compareAndSet(value, value - 1); 37 | value = token.get(); 38 | } 39 | 40 | return flag; 41 | } 42 | 43 | long getLastResetTime() { 44 | return lastResetTime; 45 | } 46 | 47 | int getToken() { 48 | return token.get(); 49 | } 50 | 51 | @Override 52 | public String toString() { 53 | return new StringBuilder(32).append("StatItem ") 54 | .append("[name=").append(name).append(", ") 55 | .append("rate = ").append(rate).append(", ") 56 | .append("interval = ").append(interval).append("]") 57 | .toString(); 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/tps/TPSLimiter.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.tps; 2 | 3 | 4 | import com.colobu.rpcx.rpc.Invocation; 5 | import com.colobu.rpcx.rpc.URL; 6 | 7 | public interface TPSLimiter { 8 | 9 | /** 10 | * 根据 tps 限流规则判断是否限制此次调用. 11 | * 12 | * @param url url 13 | * @param invocation invocation 14 | * @return true 则允许调用,否则不允许 15 | */ 16 | boolean isAllowable(URL url, Invocation invocation); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /common/src/main/java/com/colobu/rpcx/utils/PathStatus.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.utils; 2 | 3 | import com.colobu.rpcx.common.Pair; 4 | 5 | /** 6 | * @author zhangzhiyong 7 | * @date 2018/7/4 8 | */ 9 | public class PathStatus { 10 | 11 | private String type; 12 | private Pair value; 13 | private String path; 14 | 15 | private boolean stop; 16 | 17 | public PathStatus(String type, Pair value, String path) { 18 | this.type = type; 19 | this.value = value; 20 | this.path = path; 21 | } 22 | 23 | 24 | public PathStatus(boolean stop) { 25 | this.stop = stop; 26 | } 27 | 28 | public String getType() { 29 | return type; 30 | } 31 | 32 | public void setType(String type) { 33 | this.type = type; 34 | } 35 | 36 | public Pair getValue() { 37 | return value; 38 | } 39 | 40 | public void setValue(Pair value) { 41 | this.value = value; 42 | } 43 | 44 | public String getPath() { 45 | return path; 46 | } 47 | 48 | public void setPath(String path) { 49 | this.path = path; 50 | } 51 | 52 | @Override 53 | public String toString() { 54 | return "PathStatus{" + 55 | "type='" + type + '\'' + 56 | ", value='" + value + '\'' + 57 | '}'; 58 | } 59 | 60 | public boolean isStop() { 61 | return stop; 62 | } 63 | 64 | public void setStop(boolean stop) { 65 | this.stop = stop; 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /common/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /common/src/main/resources/test: -------------------------------------------------------------------------------- 1 | 1=a 2 | 2=b 3 | 3=c 4 | 4=d -------------------------------------------------------------------------------- /common/src/test/java/com/colobu/rpcx/common/TestPoolFactory.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.common; 2 | 3 | import com.colobu.rpcx.protocol.Message; 4 | import com.colobu.rpcx.protocol.RemotingCommand; 5 | import org.apache.commons.pool2.BasePooledObjectFactory; 6 | import org.apache.commons.pool2.PooledObject; 7 | import org.apache.commons.pool2.impl.DefaultPooledObject; 8 | 9 | public class TestPoolFactory extends BasePooledObjectFactory { 10 | 11 | @Override 12 | public RemotingCommand create() { 13 | return RemotingCommand.createRequestCommand(new Message()); 14 | } 15 | 16 | @Override 17 | public PooledObject wrap(RemotingCommand remotingCommand) { 18 | return new DefaultPooledObject<>(remotingCommand); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /common/src/test/java/com/colobu/rpcx/common/WeightedRountRobinTest.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.common; 2 | 3 | import com.colobu.rpcx.selector.Weighted; 4 | import com.colobu.rpcx.selector.WeightedRountRobin; 5 | import com.google.common.collect.Lists; 6 | import org.junit.Test; 7 | 8 | import java.util.Arrays; 9 | import java.util.List; 10 | 11 | public class WeightedRountRobinTest { 12 | 13 | 14 | @Test 15 | public void testWeightedRountRobin() { 16 | Weighted[] array = new Weighted[3]; 17 | array[0] = new Weighted("a", 5); 18 | array[1] = new Weighted("b", 1); 19 | array[2] = new Weighted("c", 1); 20 | 21 | WeightedRountRobin weightedRountRobin = new WeightedRountRobin(array); 22 | 23 | 24 | weightedRountRobin.updateWeighteds(Arrays.asList()); 25 | 26 | for (int i = 0; i < 7; i++) { 27 | Weighted a = weightedRountRobin.nextWeighted(); 28 | System.out.println(a.getServer()); 29 | } 30 | } 31 | 32 | 33 | @Test 34 | public void testUpdateWeightedRountRobin() { 35 | 36 | List serviceList = Arrays.asList("127.0.0.1:8001?weight=10"); 37 | WeightedRountRobin weightedRountRobin = new WeightedRountRobin(serviceList); 38 | weightedRountRobin.updateWeighteds(Arrays.asList("127.0.0.1:8002?weight=10","127.0.0.1:8001?weight=9")); 39 | 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /common/src/test/java/com/colobu/rpcx/common/YamlTest.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.common; 2 | 3 | import com.colobu.rpcx.config.RpcxConfig; 4 | import org.junit.Test; 5 | import org.yaml.snakeyaml.DumperOptions; 6 | import org.yaml.snakeyaml.Yaml; 7 | 8 | import java.util.Map; 9 | 10 | public class YamlTest { 11 | 12 | 13 | @Test 14 | public void testYaml() { 15 | String yamlStr = "key: hello yaml"; 16 | Yaml yaml = new Yaml(); 17 | Map ret = yaml.load(yamlStr); 18 | System.out.println(ret); 19 | System.out.println(ret.get("key")); 20 | } 21 | 22 | 23 | @Test 24 | public void testDump() { 25 | System.out.println(dump()); 26 | } 27 | 28 | private String dump() { 29 | DumperOptions options = new DumperOptions(); 30 | options.setPrettyFlow(true); 31 | Yaml yaml = new Yaml(options); 32 | RpcxConfig config = new RpcxConfig(); 33 | config.setConsumerPackage("com.test.consumer"); 34 | config.setFilterPackage("com.test.filter"); 35 | return yaml.dump(config); 36 | } 37 | 38 | 39 | @Test 40 | public void testLoad() { 41 | Yaml yaml = new Yaml(); 42 | RpcxConfig config = yaml.load(dump()); 43 | System.out.println(config.getConsumerPackage()); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /common/src/test/java/com/colobu/rpcx/filter/FilterTest.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.filter; 2 | 3 | import com.colobu.rpcx.filter.impl.EchoFilter; 4 | import org.junit.Test; 5 | 6 | public class FilterTest { 7 | 8 | 9 | @Test 10 | public void testName() { 11 | EchoFilter filter = new EchoFilter(); 12 | System.out.println(filter.name()); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /common/src/test/java/com/colobu/rpcx/protocol/MessageTest.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.protocol; 2 | 3 | import org.junit.Test; 4 | 5 | 6 | public class MessageTest { 7 | 8 | 9 | @Test 10 | public void encodeAndDecode() { 11 | 12 | } 13 | } -------------------------------------------------------------------------------- /common/src/test/java/com/colobu/rpcx/rpc/A.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.rpc; 2 | 3 | import java.io.Serializable; 4 | 5 | public class A implements Serializable { 6 | } 7 | -------------------------------------------------------------------------------- /common/src/test/java/com/colobu/rpcx/rpc/ExporterTest.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.rpc; 2 | 3 | import com.colobu.rpcx.rpc.impl.Exporter; 4 | import org.junit.Test; 5 | 6 | /** 7 | * Created by goodjava@qq.com. 8 | */ 9 | public class ExporterTest { 10 | 11 | 12 | @Test 13 | public void testExport() { 14 | System.out.println(new Exporter(null,"1:2").export("com.colobu.rpcx")); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /common/src/test/java/com/colobu/rpcx/rpc/IA.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.rpc; 2 | 3 | public interface IA { 4 | 5 | String call(); 6 | 7 | 8 | int sum(int a, int b); 9 | } 10 | -------------------------------------------------------------------------------- /common/src/test/java/com/colobu/rpcx/rpc/ProxyTest.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.rpc; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * Created by goodjava@qq.com. 7 | */ 8 | public class ProxyTest { 9 | 10 | 11 | 12 | @Test 13 | public void testCglib() { 14 | IA proxy = new CglibProxy().getProxy(IA.class,(m,args)->{ 15 | return "dddd"; 16 | }); 17 | String res = proxy.call(); 18 | System.out.println(res); 19 | 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /common/src/test/java/com/colobu/rpcx/rpc/ReflectUtilsTest.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.rpc; 2 | 3 | import org.junit.Test; 4 | 5 | import java.lang.reflect.Method; 6 | import java.util.Arrays; 7 | 8 | /** 9 | * Created by goodjava@qq.com. 10 | */ 11 | public class ReflectUtilsTest { 12 | 13 | 14 | @Test 15 | public void testForName() throws ClassNotFoundException { 16 | int i = 12; 17 | System.out.println(ReflectUtils.getDesc(int.class)); 18 | System.out.println(ReflectUtils.getDesc(A.class)); 19 | 20 | 21 | String str = ReflectUtils.getDesc(int.class); 22 | System.out.println(ReflectUtils.name2class(ReflectUtils.desc2name(str))); 23 | } 24 | 25 | 26 | @Test 27 | public void testMethod() throws NoSuchMethodException { 28 | Method m = IA.class.getMethod("sum", int.class, int.class); 29 | System.out.println(m); 30 | 31 | Class[] types = m.getParameterTypes(); 32 | System.out.println(Arrays.toString(types)); 33 | 34 | Class resType = m.getReturnType(); 35 | System.out.println(resType); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /common/src/test/java/com/colobu/rpcx/url/URLTest.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.url; 2 | 3 | import com.colobu.rpcx.rpc.URL; 4 | import org.junit.Test; 5 | 6 | public class URLTest { 7 | 8 | 9 | @Test 10 | public void testUrl() { 11 | URL url = new URL("rpcx","",0); 12 | url.setPath("com.test.Service"); 13 | url = url.addParameter("weight",22); 14 | url = url.addParameter("name","zzy"); 15 | System.out.println(url.toFullString()); 16 | 17 | System.out.println(url.getParameter("weight")); 18 | System.out.println(url.getPath()); 19 | 20 | System.out.println(url.toParameterString()); 21 | 22 | 23 | URL url2 = URL.valueOf("123.0.0.1:8888?a=3&b=2"); 24 | System.out.println(url2.getAddress()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /common/src/test/java/com/colobu/rpcx/utils/ZkClientTest.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.utils; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.HashSet; 6 | import java.util.concurrent.LinkedBlockingQueue; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | /** 10 | * Created by goodjava@qq.com. 11 | */ 12 | public class ZkClientTest { 13 | 14 | 15 | @Test 16 | public void testWatch() throws Exception { 17 | // ZkClient.ins().watch(); 18 | // 19 | // LinkedBlockingQueue queue = new LinkedBlockingQueue<>(); 20 | // new Thread(()->{ 21 | // while(true) { 22 | // try { 23 | // PathStatus ps = queue.take(); 24 | // System.out.println("---------->"+ps); 25 | // } catch (InterruptedException e) { 26 | // e.printStackTrace(); 27 | // } 28 | // } 29 | // }).start(); 30 | // 31 | // ZkClient.ins().watch(queue,""); 32 | // TimeUnit.HOURS.sleep(1); 33 | } 34 | 35 | 36 | @Test 37 | public void testCreate() throws Exception { 38 | ZkClient.ins().create("",new HashSet<>(),""); 39 | TimeUnit.HOURS.sleep(1); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /container/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.colobu 8 | container 9 | 1.3-SNAPSHOT 10 | 11 | 12 | 1.3-SNAPSHOT 13 | 14 | 15 | 16 | 17 | 18 | 19 | org.springframework.boot 20 | spring-boot-starter-web 21 | 2.5.12 22 | 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-test 27 | 2.0.2.RELEASE 28 | test 29 | 30 | 31 | 32 | org.springframework 33 | spring-context 34 | 5.0.6.RELEASE 35 | 36 | 37 | 38 | org.aspectj 39 | aspectjweaver 40 | 1.8.12 41 | compile 42 | 43 | 44 | 45 | 46 | com.colobu 47 | common 48 | ${rpcx.version} 49 | 50 | 51 | 52 | 53 | com.colobu 54 | client 55 | ${rpcx.version} 56 | 57 | 58 | 59 | 60 | com.colobu 61 | server 62 | ${rpcx.version} 63 | 64 | 65 | 66 | org.projectlombok 67 | lombok 68 | 1.16.20 69 | provided 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | org.apache.maven.plugins 80 | maven-compiler-plugin 81 | 3.1 82 | 83 | 1.8 84 | 1.8 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /container/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.colobu.rpcx.spring.RpcxAutoConfigure -------------------------------------------------------------------------------- /demo/api/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | demo 7 | com.colobu 8 | 1.3-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | api 13 | 14 | 15 | -------------------------------------------------------------------------------- /demo/api/src/main/java/com/colobu/rpcx/service/DemoService.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.service; 2 | 3 | 4 | import com.colobu.rpcx.rpc.annotation.Consumer; 5 | 6 | /** 7 | * @author goodjava@qq.com 8 | */ 9 | @Consumer(impl = "com.colobu.rpcx.service.DemoServiceImpl") 10 | public interface DemoService { 11 | 12 | String test(String str); 13 | } 14 | -------------------------------------------------------------------------------- /demo/api/src/main/java/com/colobu/rpcx/service/IArith.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.service; 2 | 3 | import com.colobu.rpcx.rpc.annotation.Consumer; 4 | 5 | /** 6 | * @author goodjava@qq.com 7 | */ 8 | @Consumer(impl = "com.colobu.rpcx.service.Arith") 9 | public interface IArith { 10 | 11 | Integer sum(Integer a, Integer b); 12 | 13 | int sum2(int a, int b); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /demo/api/src/main/java/com/colobu/rpcx/service/ITest2Service.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.service; 2 | 3 | 4 | import com.colobu.rpcx.rpc.annotation.Consumer; 5 | 6 | @Consumer(impl = "com.colobu.rpcx.service.Test2Service") 7 | public interface ITest2Service { 8 | 9 | int num(); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /demo/api/src/main/java/com/colobu/rpcx/service/ITestService.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.service; 2 | 3 | import com.colobu.rpcx.rpc.annotation.Consumer; 4 | 5 | /** 6 | * @author goodjava@qq.com 7 | */ 8 | @Consumer(impl = "com.colobu.rpcx.service.TestService") 9 | public interface ITestService { 10 | 11 | String hi(String str); 12 | 13 | 14 | byte[] golangHi(byte[] data); 15 | 16 | 17 | int sum(int a, int b); 18 | 19 | 20 | int sum2(int a, int b); 21 | 22 | /** 23 | * 异步调用 24 | * @return 25 | */ 26 | String async(); 27 | 28 | } 29 | -------------------------------------------------------------------------------- /demo/demmoserver/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | demo 7 | com.colobu 8 | 1.3-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | demmoserver 13 | 14 | 15 | 16 | 17 | 18 | com.colobu 19 | api 20 | 1.3-SNAPSHOT 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /demo/demmoserver/src/main/java/com/colobu/rpcx/bootstrap/Bootstrap.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.bootstrap; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 7 | import org.springframework.context.annotation.ComponentScan; 8 | import org.springframework.web.bind.annotation.RestController; 9 | 10 | 11 | /** 12 | * @author goodjava@qq.com 13 | */ 14 | @EnableAutoConfiguration 15 | @ComponentScan(basePackages = {"com.colobu.rpcx"}) 16 | @RestController 17 | public class Bootstrap { 18 | 19 | private static final Logger logger = LoggerFactory.getLogger(Bootstrap.class); 20 | 21 | public static void main(String... args) { 22 | try { 23 | SpringApplication.run(Bootstrap.class, args); 24 | } catch (Throwable ex) { 25 | logger.error(ex.getMessage(), ex); 26 | System.exit(0); 27 | } 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /demo/demmoserver/src/main/java/com/colobu/rpcx/config/ConsumerConfig.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.config; 2 | 3 | 4 | import com.colobu.rpcx.rpc.impl.ConsumerConfig.ConsumerConfigBuilder; 5 | import com.colobu.rpcx.service.ITest2Service; 6 | import com.colobu.rpcx.spring.RpcxConsumer; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | 11 | /** 12 | * @author goodjava@qq.com 13 | */ 14 | @Configuration 15 | public class ConsumerConfig { 16 | 17 | @Autowired 18 | private RpcxConsumer rpcxConsumer; 19 | 20 | 21 | @Bean 22 | public ITest2Service test2Service() { 23 | return rpcxConsumer.wrap(ITest2Service.class, new ConsumerConfigBuilder().setRetryNum(3)); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /demo/demmoserver/src/main/java/com/colobu/rpcx/demo/Server.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.demo; 2 | 3 | import com.colobu.rpcx.register.IServiceRegister; 4 | import com.colobu.rpcx.server.NettyServer; 5 | import com.colobu.rpcx.server.ZkServiceRegister; 6 | 7 | 8 | /** 9 | * @author goodjava@qq.com 10 | */ 11 | public class Server { 12 | 13 | public static void main(String... args) { 14 | NettyServer server = new NettyServer(); 15 | server.start(); 16 | IServiceRegister reg = new ZkServiceRegister("/youpin/services/", server.getAddr() + ":" + server.getPort(), "com.colobu", null); 17 | reg.register(); 18 | reg.start(); 19 | server.await(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /demo/demmoserver/src/main/java/com/colobu/rpcx/service/Arith.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.service; 2 | 3 | import com.colobu.rpcx.rpc.annotation.Provider; 4 | import org.springframework.stereotype.Service; 5 | 6 | /** 7 | * @author goodjava@qq.com 8 | */ 9 | @Provider 10 | @Service 11 | public class Arith implements IArith { 12 | 13 | /** 14 | * golang 调用 15 | */ 16 | public byte[] Echo(byte[] params) { 17 | return (new String(params) + " java server!!!").getBytes(); 18 | } 19 | 20 | public Integer sum(Integer a, Integer b) { 21 | return a + b; 22 | } 23 | 24 | public int sum2(int a, int b) { 25 | return a + b; 26 | } 27 | 28 | 29 | } 30 | -------------------------------------------------------------------------------- /demo/demmoserver/src/main/java/com/colobu/rpcx/service/DemoServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.service; 2 | 3 | 4 | import com.colobu.rpcx.rpc.annotation.Provider; 5 | import org.springframework.stereotype.Service; 6 | 7 | /** 8 | * @author goodjava@qq.com 9 | */ 10 | @Service 11 | @Provider 12 | public class DemoServiceImpl implements DemoService { 13 | 14 | 15 | public String test(String str) { 16 | return "test" + "," + str; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /demo/demmoserver/src/main/java/com/colobu/rpcx/service/TestService.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.service; 2 | 3 | import com.colobu.rpcx.rpc.annotation.Provider; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Service; 8 | 9 | import java.util.Random; 10 | import java.util.concurrent.TimeUnit; 11 | 12 | 13 | /** 14 | * @author goodjava@qq.com 15 | */ 16 | @Service 17 | //@Provider(name = "TestService", version = "0.0.2", token = "zzy123", timeout = 1000, cache = true) 18 | //@Provider(name = "TestService", version = "0.0.2", token = "zzy123", tps = 1) 19 | //@Provider(name = "TestService", version = "0.0.2", weight = "service_weight", group = "test") 20 | @Provider(name = "TestService", version = "0.0.2", weight = "rpc.service.weight") 21 | public class TestService implements ITestService { 22 | 23 | private static final Logger logger = LoggerFactory.getLogger(TestService.class); 24 | 25 | 26 | @Autowired 27 | private ITest2Service test2Service; 28 | 29 | private Random random = new Random(); 30 | 31 | public String hi(String str) { 32 | 33 | // logger.info("-------------->call hi:{}", str); 34 | // int i = random.nextInt(6); 35 | // if (i != 5) { 36 | // logger.info("-------------->|||call error " + i); 37 | // throw new RuntimeException("call hi error!!!!"); 38 | // } 39 | // logger.info("-------------->call success " + i); 40 | 41 | // try { 42 | // TimeUnit.SECONDS.sleep(15); 43 | // } catch (InterruptedException e) { 44 | // e.printStackTrace(); 45 | // } 46 | return "hi ####" + str; 47 | } 48 | 49 | public String async() { 50 | return "result:" + System.currentTimeMillis(); 51 | } 52 | 53 | 54 | public byte[] golangHi(byte[] data) { 55 | return ("hi " + new String(data)).getBytes(); 56 | } 57 | 58 | public int sum(int a, int b) { 59 | return a + b; 60 | } 61 | 62 | /** 63 | * 再次调用其他服务 64 | * @param a 65 | * @param b 66 | * @return 67 | */ 68 | public int sum2(int a, int b) { 69 | return a + b + test2Service.num(); 70 | } 71 | 72 | /** 73 | * 测试错误信息 74 | * 75 | * @param a 76 | * @param b 77 | * @return 78 | */ 79 | public int error(int a, int b) { 80 | if (1 == 1) { 81 | throw new RuntimeException("system error!!!!"); 82 | } 83 | return a + b; 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /demo/demmoserver/src/main/java/com/demo/filter/DemoFilter.java: -------------------------------------------------------------------------------- 1 | package com.demo.filter; 2 | 3 | import com.colobu.rpcx.config.Constants; 4 | import com.colobu.rpcx.filter.Filter; 5 | import com.colobu.rpcx.rpc.Invoker; 6 | import com.colobu.rpcx.rpc.Result; 7 | import com.colobu.rpcx.rpc.RpcException; 8 | import com.colobu.rpcx.rpc.annotation.RpcFilter; 9 | import com.colobu.rpcx.rpc.impl.RpcInvocation; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | 14 | /** 15 | * @author goodjava@qq.com 16 | */ 17 | @RpcFilter(group = {Constants.PROVIDER}) 18 | public class DemoFilter implements Filter { 19 | 20 | private static final Logger logger = LoggerFactory.getLogger(DemoFilter.class); 21 | 22 | public Result invoke(Invoker invoker, RpcInvocation invocation) throws RpcException { 23 | logger.info("----------->demoFilter url:{}", invocation.url.toFullString()); 24 | return invoker.invoke(invocation); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /demo/demmoserver/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | server.type: 2 | dev 3 | server.port: 4 | 8017 5 | server.debug: 6 | true 7 | rpcx.port: 8 | 8033 9 | rpcx.provider.package.path: 10 | com.colobu 11 | rpcx.consumer.package.path: 12 | com.colobu 13 | rpcx.base.path: 14 | /youpin/services/ 15 | rpcx.zk.connect.string: 16 | 127.0.0.1:2181 17 | rpcx.debug: 18 | false 19 | rpcx.http.processor.num: 20 | 50 21 | rpcx.worker.processor.num: 22 | 50 23 | rpcx.biz.processor.num: 24 | 500 25 | 26 | -------------------------------------------------------------------------------- /demo/demmoserver/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | logs/rpcx/demo_server.log 6 | 7 | %d|%-5level|%thread|%logger{40}|%L|%msg%n 8 | 9 | 10 | logs/rpcx/demo_server.log.%d{yyyy-MM-dd-HH} 11 | 12 | 13 | 14 | 15 | 16 | logs/rpcx/demo_server_error.log 17 | 18 | %d|%-5level|%thread|%logger{40}|%L|%msg%n 19 | 20 | 21 | logs/rpcx/demo_error.log.%d{yyyy-MM-dd-HH} 22 | 23 | 24 | ERROR 25 | ACCEPT 26 | DENY 27 | 28 | 29 | 30 | 31 | 32 | %d|%-5level|%thread|%logger{40}|%L|%msg%n 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /demo/demmoserver/src/test/java/com/colobu/rpcx/rpc/test/ExporterTest.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.rpc.test; 2 | 3 | import com.colobu.rpcx.rpc.impl.Exporter; 4 | import org.junit.Test; 5 | 6 | public class ExporterTest { 7 | 8 | @Test 9 | public void testExport() { 10 | System.out.println(new Exporter(null,"1:2").export("com.colobu.rpcx")); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /demo/democlient/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | demo 7 | com.colobu 8 | 1.3-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | democlient 13 | 14 | 15 | 1.3-SNAPSHOT 16 | 17 | 18 | 19 | 20 | 21 | com.colobu 22 | common 23 | ${rpcx.version} 24 | 25 | 26 | 27 | com.colobu 28 | client 29 | ${rpcx.version} 30 | 31 | 32 | 33 | com.colobu 34 | container 35 | ${rpcx.version} 36 | 37 | 38 | 39 | com.colobu 40 | api 41 | ${rpcx.version} 42 | 43 | 44 | 45 | com.colobu 46 | client 47 | ${rpcx.version} 48 | compile 49 | 50 | 51 | 52 | 53 | org.projectlombok 54 | lombok 55 | 1.16.20 56 | provided 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /demo/democlient/src/main/java/com/colobu/rpcx/bootstrap/Bootstrap.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.bootstrap; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 7 | import org.springframework.context.annotation.ComponentScan; 8 | 9 | 10 | /** 11 | * @author goodjava@qq.com 12 | */ 13 | @EnableAutoConfiguration 14 | @ComponentScan(basePackages = {"com.colobu.rpcx"}) 15 | public class Bootstrap { 16 | 17 | private static final Logger logger = LoggerFactory.getLogger(Bootstrap.class); 18 | 19 | public static void main(String... args) { 20 | try { 21 | SpringApplication.run(Bootstrap.class, args); 22 | } catch (Exception ex) { 23 | logger.error(ex.getMessage(), ex); 24 | System.exit(0); 25 | } 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /demo/democlient/src/main/java/com/colobu/rpcx/config/ConsumerConfig.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.config; 2 | 3 | 4 | import com.colobu.rpcx.fail.FailType; 5 | import com.colobu.rpcx.selector.SelectMode; 6 | import com.colobu.rpcx.service.IArith; 7 | import com.colobu.rpcx.service.ITestService; 8 | import com.colobu.rpcx.spring.RpcxConsumer; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.context.annotation.Bean; 11 | import org.springframework.context.annotation.Configuration; 12 | import com.colobu.rpcx.rpc.impl.ConsumerConfig.ConsumerConfigBuilder; 13 | 14 | /** 15 | * @author goodjava@qq.com 16 | */ 17 | @Configuration 18 | public class ConsumerConfig { 19 | 20 | @Autowired 21 | private RpcxConsumer rpcxConsumer; 22 | 23 | @Bean 24 | public IArith arith() { 25 | return rpcxConsumer.wrap(IArith.class); 26 | } 27 | 28 | @Bean 29 | public ITestService testService() { 30 | return rpcxConsumer.wrap(ITestService.class, new ConsumerConfigBuilder() 31 | // .setGroup("test") 32 | // .setToken("zzy123") 33 | .setSendType(Constants.SYNC_KEY) 34 | .setTimeout(600000) 35 | .setFailType(FailType.FailTry) 36 | .setSelectMode(SelectMode.WeightedRoundRobin) 37 | .setRetryNum(3)); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /demo/democlient/src/main/java/com/colobu/rpcx/demo/Client.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.demo; 2 | 3 | import com.colobu.rpcx.discovery.IServiceDiscovery; 4 | import com.colobu.rpcx.client.NettyClient; 5 | import com.colobu.rpcx.client.ZkServiceDiscovery; 6 | import com.colobu.rpcx.netty.IClient; 7 | import com.colobu.rpcx.rpc.impl.ConsumerConfig; 8 | import com.colobu.rpcx.service.IArith; 9 | 10 | 11 | /** 12 | * @author goodjava@qq.com 13 | */ 14 | public class Client { 15 | 16 | public static void main(String... args) { 17 | IServiceDiscovery serviceDiscovery = new ZkServiceDiscovery("/youpin/services/",""); 18 | IClient client = new NettyClient(serviceDiscovery); 19 | IArith arith = new ConsumerConfig(client).refer(IArith.class); 20 | //// System.out.println(arith.sum(1111, 222)); 21 | //// System.out.println(arith.sum2(1111, 222)); 22 | for (int i = 0; i < 1; i++) { 23 | System.out.println(arith.sum(11,22)); 24 | } 25 | // 26 | serviceDiscovery.close(); 27 | System.out.println("client call finish"); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /demo/democlient/src/main/java/com/colobu/rpcx/handler/TestController.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.handler; 2 | 3 | import com.colobu.rpcx.netty.ResponseFuture; 4 | import com.colobu.rpcx.rpc.RpcContext; 5 | import com.colobu.rpcx.service.ITestService; 6 | import com.colobu.rpcx.spring.RpcxConsumer; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.context.ApplicationContext; 9 | import org.springframework.web.bind.annotation.GetMapping; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | import java.io.IOException; 13 | 14 | /** 15 | * @author goodjava@qq.com 16 | */ 17 | @RestController 18 | public class TestController { 19 | 20 | @Autowired 21 | private ITestService testService; 22 | 23 | @Autowired 24 | private ApplicationContext context; 25 | 26 | 27 | @Autowired 28 | private RpcxConsumer consumer; 29 | 30 | 31 | @GetMapping("/hi") 32 | public String input(String word) { 33 | String s = testService.hi(word); 34 | return s; 35 | } 36 | 37 | 38 | @GetMapping("/sum") 39 | public String sum() { 40 | String s = String.valueOf(testService.sum(22, 33)); 41 | return s; 42 | } 43 | 44 | @GetMapping("/sum2") 45 | public String sum2() { 46 | String s = String.valueOf(testService.sum2(22, 33)); 47 | return s; 48 | } 49 | 50 | /** 51 | * 测试echo filter 52 | * 53 | * @return 54 | */ 55 | @GetMapping("/echo") 56 | public String echo() { 57 | String s = consumer.echo("com.colobu.rpcx.service.TestService", "echo"); 58 | return s; 59 | } 60 | 61 | /** 62 | * 泛化调用 63 | * 64 | * @return 65 | */ 66 | @GetMapping("/generic") 67 | public String generic() { 68 | Object s = consumer.invoke("com.colobu.rpcx.service.TestService", "sum", new String[]{"int", "int"}, new String[]{"11", "22"}); 69 | return s.toString(); 70 | } 71 | 72 | /** 73 | * 异步模式(必须consumer 开启 异步模式) 74 | * ConsumerConfigBuilder.setSendType(Constants.ASYNC_KEY) 75 | * @return 76 | * @throws InterruptedException 77 | */ 78 | @GetMapping("/async") 79 | public String async() throws InterruptedException { 80 | testService.async(); 81 | ResponseFuture f1 = RpcContext.getContext().getFuture(); 82 | //需要自己手动清理 83 | RpcContext.removeContext(); 84 | testService.async(); 85 | ResponseFuture f2 = RpcContext.getContext().getFuture(); 86 | RpcContext.removeContext(); 87 | String result = ""; 88 | if (null != f1 && f2 != null) { 89 | String s1 = f1.get(2000); 90 | String s2 = f2.get(2000); 91 | result = s1 + s2; 92 | } 93 | 94 | return result; 95 | } 96 | 97 | /** 98 | * 测试热更新 99 | * 100 | * @return 101 | * @throws IOException 102 | */ 103 | @GetMapping("/deploy") 104 | public String deploy() throws IOException { 105 | Object s = consumer.deploy("com.colobu.rpcx.service.TestService", "/Users/zhangzhiyong/IdeaProjects/rpcx-java/demo/demmoserver/target/classes/com/colobu/rpcx/service/TestService.class", "123abc"); 106 | return s.toString(); 107 | } 108 | 109 | 110 | } 111 | -------------------------------------------------------------------------------- /demo/democlient/src/main/java/com/demo/client/filter/DemoClientFilter.java: -------------------------------------------------------------------------------- 1 | package com.demo.client.filter; 2 | 3 | 4 | import com.colobu.rpcx.config.Constants; 5 | import com.colobu.rpcx.filter.Filter; 6 | import com.colobu.rpcx.rpc.Invoker; 7 | import com.colobu.rpcx.rpc.Result; 8 | import com.colobu.rpcx.rpc.RpcException; 9 | import com.colobu.rpcx.rpc.annotation.RpcFilter; 10 | import com.colobu.rpcx.rpc.impl.RpcInvocation; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | 15 | /** 16 | * @author goodjava@qq.com 17 | */ 18 | @RpcFilter(group = {Constants.CONSUMER}) 19 | public class DemoClientFilter implements Filter { 20 | 21 | private static final Logger logger = LoggerFactory.getLogger(DemoClientFilter.class); 22 | 23 | public Result invoke(Invoker invoker, RpcInvocation invocation) throws RpcException { 24 | logger.info("DemoClientFilter invoke"); 25 | return invoker.invoke(invocation); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /demo/democlient/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.type=dev 2 | server.port=8019 3 | server.debug=true 4 | spring.main.banner-mode=off 5 | 6 | #rpcx 7 | rpcx.provider.package.path=com.colobu 8 | rpcx.consumer.package.path=com.colobu 9 | rpcx.base.path=/youpin/services/ 10 | rpcx.zk.connect.string=127.0.0.1:2181 11 | rpcx.filter.package=com.demo.client.filter 12 | rpcx.port=8028 -------------------------------------------------------------------------------- /demo/democlient/src/main/resources/client/nodejs/client.js: -------------------------------------------------------------------------------- 1 | var request = require('request'); 2 | 3 | var options = { 4 | url: 'http://10.231.72.221:8033/', 5 | headers: { 6 | 'User-Agent': 'Easy_Go_NodeJs_Client', 7 | 'X-RPCX-ServicePath':'com.colobu.rpcx.service.TestService', 8 | 'X-RPCX-ServiceMethod':'sum', 9 | 'connection':'close' 10 | }, 11 | method: 'POST', 12 | json:true, 13 | body:{"parameterTypeNames":["int","int"],"arguments":["11","22"]} 14 | }; 15 | 16 | function callback(error, response, body) { 17 | if (!error && response.statusCode == 200) { 18 | console.log(body); 19 | console.log(body.payload) 20 | console.log(new Buffer(body.payload).toString('ascii')) 21 | } else { 22 | console.log(error) 23 | } 24 | } 25 | 26 | request(options, callback) -------------------------------------------------------------------------------- /demo/democlient/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | logs/rpcx/demo_client.log 6 | 7 | %d|%-5level|%thread|%logger{40}|%L|%msg%n 8 | 9 | 10 | logs/push.log.%d{yyyy-MM-dd-HH} 11 | 12 | 13 | 14 | 15 | 16 | logs/rpcx/demo_client_error.log 17 | 18 | %d|%-5level|%thread|%logger{40}|%L|%msg%n 19 | 20 | 21 | logs/error.log.%d{yyyy-MM-dd-HH} 22 | 23 | 24 | ERROR 25 | ACCEPT 26 | DENY 27 | 28 | 29 | 30 | 31 | 32 | %d|%-5level|%thread|%logger{40}|%L|%msg%n 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /demo/democlient/src/test/java/com/colobu/rpcx/test/ClientTest.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.test; 2 | 3 | 4 | import com.colobu.rpcx.bootstrap.Bootstrap; 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | import org.springframework.test.context.junit4.SpringRunner; 9 | 10 | @RunWith(SpringRunner.class) 11 | @SpringBootTest(classes = Bootstrap.class) 12 | public class ClientTest { 13 | 14 | 15 | @Test 16 | public void testStartSpring() { 17 | 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /demo/demoserver2/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | demo 7 | com.colobu 8 | 1.3-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | demoserver2 13 | 14 | 15 | 16 | 17 | 18 | com.colobu 19 | api 20 | 1.3-SNAPSHOT 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /demo/demoserver2/src/main/java/com/colobu/rpcx/bootstrap/Server2Bootstrap.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.bootstrap; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 7 | import org.springframework.context.annotation.ComponentScan; 8 | import org.springframework.web.bind.annotation.RestController; 9 | 10 | 11 | /** 12 | * @author goodjava@qq.com 13 | */ 14 | @EnableAutoConfiguration 15 | @ComponentScan(basePackages = {"com.colobu.rpcx"}) 16 | @RestController 17 | public class Server2Bootstrap { 18 | 19 | private static final Logger logger = LoggerFactory.getLogger(Server2Bootstrap.class); 20 | 21 | public static void main(String... args) { 22 | logger.info("Server2Bootstrap start"); 23 | try { 24 | SpringApplication.run(Server2Bootstrap.class, args); 25 | } catch (Throwable ex) { 26 | logger.error(ex.getMessage(), ex); 27 | System.exit(0); 28 | } 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /demo/demoserver2/src/main/java/com/colobu/rpcx/service/Test2Service.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.service; 2 | 3 | import com.colobu.rpcx.rpc.annotation.Provider; 4 | import com.colobu.rpcx.service.ITest2Service; 5 | import org.springframework.stereotype.Service; 6 | 7 | /** 8 | * @author goodjava@qq.com 9 | */ 10 | @Service 11 | @Provider(name = "Test2Service") 12 | public class Test2Service implements ITest2Service { 13 | 14 | public int num() { 15 | return 100; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /demo/demoserver2/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | server.type: 2 | dev 3 | server.port: 4 | 8018 5 | server.debug: 6 | true 7 | rpcx.port: 8 | 8034 9 | rpcx.provider.package.path: 10 | com.colobu 11 | rpcx.consumer.package.path: 12 | com.colobu 13 | rpcx.base.path: 14 | /youpin/services/ 15 | rpcx.zk.connect.string: 16 | 127.0.0.1:2181 17 | rpcx.debug: 18 | false 19 | rpcx.http.processor.num: 20 | 50 21 | rpcx.worker.processor.num: 22 | 50 23 | rpcx.biz.processor.num: 24 | 500 25 | 26 | -------------------------------------------------------------------------------- /demo/demoserver2/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | logs/rpcx/demo_server.log 6 | 7 | %d|%-5level|%thread|%logger{40}|%L|%msg%n 8 | 9 | 10 | logs/rpcx/demo_server2.log.%d{yyyy-MM-dd-HH} 11 | 12 | 13 | 14 | 15 | 16 | logs/rpcx/demo_server2_error.log 17 | 18 | %d|%-5level|%thread|%logger{40}|%L|%msg%n 19 | 20 | 21 | logs/rpcx/demo_server2_error.log.%d{yyyy-MM-dd-HH} 22 | 23 | 24 | ERROR 25 | ACCEPT 26 | DENY 27 | 28 | 29 | 30 | 31 | 32 | %d|%-5level|%thread|%logger{40}|%L|%msg%n 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /demo/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.colobu 8 | demo 9 | pom 10 | 1.3-SNAPSHOT 11 | 12 | 13 | api 14 | demmoserver 15 | democlient 16 | demoserver2 17 | 18 | 19 | 20 | 1.3-SNAPSHOT 21 | 22 | 23 | 24 | 25 | 26 | com.colobu 27 | server 28 | ${rpcx.version} 29 | 30 | 31 | 32 | com.colobu 33 | client 34 | ${rpcx.version} 35 | 36 | 37 | 38 | com.colobu 39 | container 40 | ${rpcx.version} 41 | 42 | 43 | 44 | org.springframework.boot 45 | spring-boot-starter-logging 46 | 2.0.2.RELEASE 47 | 48 | 49 | 50 | 51 | org.springframework 52 | spring-context 53 | 5.0.6.RELEASE 54 | 55 | 56 | 57 | 58 | org.aspectj 59 | aspectjweaver 60 | 1.8.12 61 | compile 62 | 63 | 64 | 65 | ch.qos.logback 66 | logback-classic 67 | 1.2.0 68 | 69 | 70 | 71 | ch.qos.logback 72 | logback-core 73 | 1.2.9 74 | 75 | 76 | 77 | org.springframework.boot 78 | spring-boot-starter-test 79 | 2.0.2.RELEASE 80 | test 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## rpcx-java 2 | 3 | **Unmaintained**: 目前没有资源维护这个项目。欢迎有时间的开发者接手。 4 | 5 | ### example 6 | assume you have started a Go rpcx server: 7 | ```go 8 | package main 9 | 10 | import ( 11 | "context" 12 | "flag" 13 | 14 | "github.com/smallnest/rpcx/server" 15 | ) 16 | 17 | var ( 18 | addr = flag.String("addr", "192.168.31.82:8997", "server address") 19 | ) 20 | 21 | type Echo int 22 | 23 | func (t *Echo) Echo(ctx context.Context, args []byte, reply *[]byte) error { 24 | *reply = []byte("hello" + string(args)) 25 | return nil 26 | } 27 | 28 | func main() { 29 | flag.Parse() 30 | 31 | s := server.NewServer() 32 | s.RegisterName("echo", new(Echo), "") 33 | s.Serve("tcp", *addr) 34 | } 35 | 36 | ``` 37 | 38 | You can run it as: 39 | ```sh 40 | go run main.go 41 | ``` 42 | 43 | Then you can write the java client: 44 | 45 | ```java 46 | @Test 47 | public void testSendMsg() throws Exception { 48 | Message req = new Message("Echo", "Echo"); 49 | req.setVersion((byte) 0); 50 | req.setMessageType(MessageType.Request); 51 | req.setHeartbeat(false); 52 | req.setOneway(false); 53 | req.setCompressType(CompressType.None); 54 | req.setSerializeType(SerializeType.SerializeNone); 55 | req.setSeq(123); 56 | req.metadata.put("test", "1234"); 57 | req.payload = "world".getBytes("UTF-8"); 58 | 59 | NettyClient client = new NettyClient(null); 60 | Message res = client.call("192.168.31.82:8997", req); 61 | System.out.println(new String(res.payload)); 62 | } 63 | ``` 64 | 65 | 66 | ## 借鉴项目 67 | - dubbo 68 | - rocketmq 69 | 70 | ## feature 71 | - 支持和spring-boot的集成 72 | - 支持服务发现和注册 73 | - 支持扩展(client 和 server都可扩展) 74 | - 支持多语言调用 75 | - 支持qps限流 76 | - 支持accesslog记录 77 | - 支持泛化调用 78 | - 支持同步 异步 oneway调用 79 | - 支持token调用 80 | - 支持client端重试 81 | - 支持调用数据采集 82 | - 支持结果缓存 83 | - 支持热更新 84 | - 支持http gateway访问模式 85 | - 调用失败支持(FailFast Failover Failtry) 86 | - 支持select模式(RandomSelect RoundRobin WeightedRoundRobin SelectByUser) 87 | - 支持优雅关机 88 | - 支持服务治理(通过rpcx-ui) 89 | - 支持服务分组 90 | -------------------------------------------------------------------------------- /server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.colobu 8 | server 9 | 1.3-SNAPSHOT 10 | 11 | 12 | 1.3-SNAPSHOT 13 | 14 | 15 | 16 | 17 | 18 | com.colobu 19 | common 20 | ${rpcx.version} 21 | 22 | 23 | 24 | 25 | org.projectlombok 26 | lombok 27 | 1.16.20 28 | provided 29 | 30 | 31 | 32 | junit 33 | junit 34 | 4.13.1 35 | test 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | org.apache.maven.plugins 45 | maven-compiler-plugin 46 | 3.1 47 | 48 | 1.8 49 | 1.8 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /server/src/main/java/com/colobu/rpcx/handler/RpcxHttpHandler.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.handler; 2 | 3 | import com.colobu.rpcx.common.StringUtils; 4 | import com.colobu.rpcx.config.Constants; 5 | import com.colobu.rpcx.protocol.LanguageCode; 6 | import com.colobu.rpcx.protocol.Message; 7 | import com.colobu.rpcx.protocol.MessageType; 8 | import com.colobu.rpcx.protocol.RemotingCommand; 9 | import com.colobu.rpcx.server.NettyServer; 10 | import io.netty.buffer.ByteBuf; 11 | import io.netty.channel.ChannelHandlerContext; 12 | import io.netty.channel.SimpleChannelInboundHandler; 13 | import io.netty.handler.codec.http.FullHttpRequest; 14 | import io.netty.handler.codec.http.HttpHeaders; 15 | import org.jboss.netty.handler.codec.socks.SocksMessage; 16 | import org.slf4j.Logger; 17 | import org.slf4j.LoggerFactory; 18 | 19 | import java.net.InetSocketAddress; 20 | import java.util.HashMap; 21 | 22 | /** 23 | * XVersion = "X-RPCX-Version" 24 | * XMessageType = "X-RPCX-MesssageType" 25 | * XHeartbeat = "X-RPCX-Heartbeat" 26 | * XOneway = "X-RPCX-Oneway" 27 | * XMessageStatusType = "X-RPCX-MessageStatusType" 28 | * XSerializeType = "X-RPCX-SerializeType" 29 | * XMessageID = "X-RPCX-MessageID" 30 | * XServicePath = "X-RPCX-ServicePath" 31 | * XServiceMethod = "X-RPCX-ServiceMethod" 32 | * XMeta = "X-RPCX-Meta" 33 | * XErrorMessage = "X-RPCX-ErrorMessage" 34 | * 35 | * @author goodjava@qq.com 36 | */ 37 | public class RpcxHttpHandler extends SimpleChannelInboundHandler { 38 | 39 | private static final Logger logger = LoggerFactory.getLogger(RpcxHttpHandler.class); 40 | 41 | private NettyServer nettyServer; 42 | 43 | public RpcxHttpHandler(NettyServer nettyServer) { 44 | this.nettyServer = nettyServer; 45 | } 46 | 47 | @Override 48 | protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) { 49 | String servicePath = msg.headers().get(Constants.X_RPCX_SERVICEPATH); 50 | String serviceMethod = msg.headers().get(Constants.X_RPCX_SERVICEMETHOD); 51 | String traceId = msg.headers().get(Constants.X_RPCX_TRACEID); 52 | 53 | logger.info("service:{} method:{} traceId:{}", servicePath, serviceMethod, traceId); 54 | 55 | ByteBuf buf = msg.content(); 56 | int len = buf.readableBytes(); 57 | 58 | byte[] payload = new byte[len]; 59 | buf.readBytes(payload); 60 | 61 | Message message = new Message(); 62 | message.metadata.put("language", LanguageCode.HTTP.name()); 63 | message.metadata.put("_host", getClientIp(ctx, msg)); 64 | message.metadata.put("_port", "0"); 65 | message.metadata.put(Constants.X_RPCX_TRACEID, traceId == null ? "" : traceId); 66 | message.servicePath = servicePath; 67 | message.serviceMethod = serviceMethod; 68 | message.payload = payload; 69 | message.setMessageType(MessageType.Request); 70 | message.setOneway(true); 71 | RemotingCommand command = RemotingCommand.createRequestCommand(message); 72 | command.setCode(1984); 73 | //这里会异步处理 74 | nettyServer.processRequestCommand(ctx, command); 75 | } 76 | 77 | 78 | private String getClientIp(ChannelHandlerContext ctx, FullHttpRequest request) { 79 | HttpHeaders httpHeaders = request.headers(); 80 | String remoteIP = httpHeaders.get("X-Forwarded-For"); 81 | if (remoteIP == null) { 82 | remoteIP = httpHeaders.get("X-Real-IP"); 83 | } 84 | if (remoteIP != null) { 85 | return remoteIP; 86 | } else { // request取不到就从channel里取 87 | return ((InetSocketAddress) ctx.channel().remoteAddress()).getHostName(); 88 | } 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /server/src/main/java/com/colobu/rpcx/handler/RpcxProcessHandler.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.handler; 2 | 3 | import com.colobu.rpcx.netty.NettyConnetManageHandler; 4 | import com.colobu.rpcx.netty.NettyDecoder; 5 | import com.colobu.rpcx.netty.NettyEncoder; 6 | import com.colobu.rpcx.netty.NettyServerHandler; 7 | import com.colobu.rpcx.server.NettyServer; 8 | import io.netty.buffer.ByteBuf; 9 | import io.netty.channel.ChannelHandlerContext; 10 | import io.netty.channel.ChannelPipeline; 11 | import io.netty.handler.codec.ByteToMessageDecoder; 12 | import io.netty.handler.codec.http.HttpObjectAggregator; 13 | import io.netty.handler.codec.http.HttpServerCodec; 14 | import io.netty.handler.timeout.IdleStateHandler; 15 | 16 | import java.util.List; 17 | 18 | /** 19 | * @author goodjava@qq.com 20 | */ 21 | public class RpcxProcessHandler extends ByteToMessageDecoder { 22 | 23 | private int serverChannelMaxIdleTimeSeconds; 24 | 25 | private NettyServer nettyServer; 26 | 27 | public RpcxProcessHandler(int serverChannelMaxIdleTimeSeconds, NettyServer nettyServer) { 28 | this.serverChannelMaxIdleTimeSeconds = serverChannelMaxIdleTimeSeconds; 29 | this.nettyServer = nettyServer; 30 | } 31 | 32 | @Override 33 | protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { 34 | 35 | if (in.readableBytes() < 1) { 36 | return; 37 | } 38 | 39 | final int magic = in.getByte(in.readerIndex()); 40 | ChannelPipeline p = ctx.pipeline(); 41 | //处理http 42 | if (isHttp(magic)) { 43 | p.addLast(new HttpServerCodec()); 44 | p.addLast(new HttpObjectAggregator(1048576)); 45 | p.addLast(new RpcxHttpHandler(nettyServer)); 46 | p.remove(this); 47 | } else {//处理二进制 48 | p.addLast(new NettyEncoder()); 49 | p.addLast(new NettyDecoder()); 50 | p.addLast(new IdleStateHandler(0, 0, serverChannelMaxIdleTimeSeconds)); 51 | p.addLast(new NettyConnetManageHandler(nettyServer)); 52 | p.addLast(new NettyServerHandler(nettyServer)); 53 | p.remove(this); 54 | } 55 | 56 | } 57 | 58 | 59 | // G for GET, and P for POST 60 | private static boolean isHttp(int magic) { 61 | return magic == 'G' || magic == 'P'; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /server/src/main/java/com/colobu/rpcx/processor/RpcProcessor.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.processor; 2 | 3 | import com.colobu.rpcx.common.ClassUtils; 4 | import com.colobu.rpcx.config.Constants; 5 | import com.colobu.rpcx.netty.NettyRequestProcessor; 6 | import com.colobu.rpcx.protocol.LanguageCode; 7 | import com.colobu.rpcx.protocol.RemotingCommand; 8 | import com.colobu.rpcx.protocol.RemotingSysResponseCode; 9 | import com.colobu.rpcx.rpc.HessianUtils; 10 | import com.colobu.rpcx.rpc.Invoker; 11 | import com.colobu.rpcx.rpc.Result; 12 | import com.colobu.rpcx.rpc.URL; 13 | import com.colobu.rpcx.rpc.impl.Exporter; 14 | import com.colobu.rpcx.rpc.impl.RpcInvocation; 15 | import io.netty.channel.ChannelHandlerContext; 16 | import org.slf4j.Logger; 17 | import org.slf4j.LoggerFactory; 18 | 19 | import java.io.UnsupportedEncodingException; 20 | 21 | /** 22 | * @author goodjava@qq.com 23 | * 处理远程rpc调用 24 | */ 25 | public class RpcProcessor implements NettyRequestProcessor { 26 | 27 | private static final Logger logger = LoggerFactory.getLogger(RpcProcessor.class); 28 | 29 | @Override 30 | public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request) throws UnsupportedEncodingException { 31 | request.getMessage().decode(request.getData()); 32 | 33 | String language = request.getMessage().metadata.get(Constants.LANGUAGE); 34 | String className = request.getMessage().servicePath; 35 | String methodName = request.getMessage().serviceMethod; 36 | RpcInvocation invocation = null; 37 | //golang调用是没有language的 38 | if (null == language) { 39 | //golang 是没有invocation的 40 | invocation = new RpcInvocation(); 41 | invocation.setClassName(className); 42 | invocation.setMethodName(methodName); 43 | invocation.setLanguageCode(LanguageCode.GO); 44 | invocation.setParameterTypeNames(new String[]{"byte[]"}); 45 | String path = ClassUtils.getMethodKey(className, methodName, new String[]{"byte[]"}); 46 | invocation.url = new URL("rpcx", "", 0, path); 47 | //golang 参数是byte[] 48 | invocation.setParameterTypeNames(new String[]{"byte[]"}); 49 | //参数就是payload数据 50 | invocation.setArguments(new Object[]{request.getMessage().payload}); 51 | } else if (LanguageCode.JAVA.name().equals(language)) { 52 | invocation = (RpcInvocation) HessianUtils.read(request.getMessage().payload); 53 | } 54 | 55 | Invoker wrapperInvoker = null; 56 | 57 | //request -> response 58 | RemotingCommand res = request.requestToResponse(); 59 | 60 | String key = ""; 61 | 62 | 63 | if (methodName.equals(Constants.$ECHO)) { 64 | //echo 65 | key = Constants.$ECHO; 66 | } else if (methodName.equals(Constants.$INVOKE)) { 67 | //泛化调用 68 | key = Constants.$INVOKE; 69 | } else { 70 | key = ClassUtils.getMethodKey(className, methodName, invocation.getParameterTypeNames()); 71 | } 72 | 73 | wrapperInvoker = Exporter.invokerMap.get(key); 74 | 75 | if (null == wrapperInvoker) { 76 | logger.warn("get invoker is null key:{}", key); 77 | res.setErrorMessage(RemotingSysResponseCode.SYSTEM_ERROR, "get invoker is null key:" + key); 78 | return res; 79 | } 80 | 81 | Result rpcResult = wrapperInvoker.invoke(invocation); 82 | res.getMessage().metadata.put(Constants.TRACE_ID, rpcResult.getAttachment(Constants.TRACE_ID, "")); 83 | res.getMessage().metadata.put(Constants.SPAN_ID, rpcResult.getAttachment(Constants.SPAN_ID, "")); 84 | 85 | if (invocation.languageCode.equals(LanguageCode.JAVA)) { 86 | res.getMessage().payload = HessianUtils.write(rpcResult.getValue()); 87 | } else { 88 | res.getMessage().payload = (byte[]) rpcResult.getValue(); 89 | } 90 | if (rpcResult.hasException()) { 91 | logger.error(rpcResult.getException().getMessage(), rpcResult.getException()); 92 | res.setErrorMessage(RemotingSysResponseCode.SYSTEM_ERROR, rpcResult.getException().getMessage()); 93 | } 94 | return res; 95 | } 96 | 97 | 98 | @Override 99 | public boolean rejectRequest() { 100 | return false; 101 | } 102 | 103 | 104 | } 105 | -------------------------------------------------------------------------------- /server/src/main/java/com/colobu/rpcx/server/ZkServiceRegister.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.server; 2 | 3 | import com.colobu.rpcx.register.IServiceRegister; 4 | import com.colobu.rpcx.rpc.impl.Exporter; 5 | import com.colobu.rpcx.utils.ZkClient; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import java.util.Set; 10 | import java.util.concurrent.ScheduledThreadPoolExecutor; 11 | import java.util.concurrent.TimeUnit; 12 | import java.util.function.Function; 13 | 14 | /** 15 | * @author goodjava@qq.com 16 | */ 17 | public class ZkServiceRegister implements IServiceRegister { 18 | 19 | private static final Logger logger = LoggerFactory.getLogger(ZkServiceRegister.class); 20 | 21 | private String basePath; 22 | private Set serviceNameSet; 23 | private String addr; 24 | 25 | public ZkServiceRegister(String basePath, String addr, String providerPackage, Function getBeanFunc) { 26 | this.basePath = basePath; 27 | this.addr = addr; 28 | //导出所有有注解的service 29 | this.serviceNameSet = new Exporter(getBeanFunc, addr).export(providerPackage); 30 | logger.info("export service names:{}", this.serviceNameSet); 31 | } 32 | 33 | /** 34 | * 服务注册 35 | */ 36 | @Override 37 | public void register() { 38 | try { 39 | ZkClient.ins().create(this.basePath, this.serviceNameSet, this.addr); 40 | } catch (Exception e) { 41 | e.printStackTrace(); 42 | } 43 | } 44 | 45 | /** 46 | * 周期性的注册 47 | */ 48 | @Override 49 | public void start() { 50 | new ScheduledThreadPoolExecutor(1).scheduleWithFixedDelay(() -> { 51 | register(); 52 | }, 0, 5, TimeUnit.SECONDS); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /server/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | logs/rpcx/rpcx.log 6 | 7 | %d|%-5level|%thread|%logger{40}|%L|%msg%n 8 | 9 | 10 | logs/push.log.%d{yyyy-MM-dd-HH} 11 | 12 | 13 | 14 | 15 | 16 | logs/rpcx/error.log 17 | 18 | %d|%-5level|%thread|%logger{40}|%L|%msg%n 19 | 20 | 21 | logs/error.log.%d{yyyy-MM-dd-HH} 22 | 23 | 24 | ERROR 25 | ACCEPT 26 | DENY 27 | 28 | 29 | 30 | 31 | 32 | %d|%-5level|%thread|%logger{40}|%L|%msg%n 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /server/src/test/java/com/colobu/rpcx/server/NettyServerTest.java: -------------------------------------------------------------------------------- 1 | package com.colobu.rpcx.server; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.concurrent.TimeUnit; 6 | 7 | 8 | /** 9 | * Created by goodjava@qq.com. 10 | */ 11 | public class NettyServerTest { 12 | 13 | 14 | @Test 15 | public void testNettyServer() throws InterruptedException { 16 | NettyServer server = new NettyServer(); 17 | server.start(); 18 | ZkServiceRegister reg = new ZkServiceRegister("/youpin/services/", server.getAddr() + ":" + server.getPort(), "", null); 19 | reg.register(); 20 | reg.start(); 21 | TimeUnit.HOURS.sleep(1); 22 | } 23 | } 24 | --------------------------------------------------------------------------------