├── .gitignore ├── cluster ├── pom.xml └── src │ └── main │ └── java │ └── cn │ └── thinkinjava │ ├── Cluster.java │ ├── ClusterInovker.java │ ├── LoadBalance.java │ ├── cluster │ └── AbstractCluster.java │ ├── failover │ └── Failover.java │ └── loadBlancer │ └── AbstractLoadBalance.java ├── common └── pom.xml ├── config └── pom.xml ├── core ├── pom.xml └── src │ ├── main │ ├── java │ │ └── thinkinjava │ │ │ ├── LifeCycle.java │ │ │ ├── api │ │ │ ├── client │ │ │ │ ├── LuConsumer.java │ │ │ │ └── LuConsumerConfig.java │ │ │ └── server │ │ │ │ ├── LuProvider.java │ │ │ │ ├── LuProviderConfig.java │ │ │ │ └── ProviderManager.java │ │ │ ├── breaker │ │ │ ├── CircuitBreaker.java │ │ │ ├── CircuitBreakerEvent.java │ │ │ ├── CircuitBreakerFilter.java │ │ │ ├── CircuitBreakerStatFilter.java │ │ │ ├── CircuitRenewEvent.java │ │ │ ├── CircuitState.java │ │ │ ├── CircuitStateManager.java │ │ │ ├── Metrics.java │ │ │ ├── TimeWindow.java │ │ │ ├── WindowsManager.java │ │ │ └── package-info.java │ │ │ ├── conf │ │ │ ├── Callback.java │ │ │ ├── Config.java │ │ │ ├── ConfigBuilder.java │ │ │ ├── Constant.java │ │ │ ├── DefaultConfig.java │ │ │ ├── DefaultDynamicProperties.java │ │ │ ├── DynamicProperties.java │ │ │ ├── DynamicProperty.java │ │ │ ├── Plugins.java │ │ │ ├── Property.java │ │ │ ├── ServerConfig.java │ │ │ ├── ServerConstants.java │ │ │ └── package-info.java │ │ │ ├── core │ │ │ ├── BaseServiceConfig.java │ │ │ ├── ConsumerInvoker.java │ │ │ ├── Invoker.java │ │ │ ├── ProviderInvoker.java │ │ │ └── ServiceConfig.java │ │ │ ├── event │ │ │ ├── Event.java │ │ │ ├── EventBus.java │ │ │ ├── Subscriber.java │ │ │ └── package-info.java │ │ │ ├── exception │ │ │ ├── CircuitBreakerException.java │ │ │ ├── FlowBufferAddException.java │ │ │ ├── LimitException.java │ │ │ ├── LuTimeoutException.java │ │ │ └── UserOperationException.java │ │ │ ├── filter │ │ │ ├── ExampleFilter.java │ │ │ ├── ExampleFilter2.java │ │ │ ├── Filter.java │ │ │ ├── FilterChain.java │ │ │ ├── FilterWrapper.java │ │ │ ├── LoadFilters.java │ │ │ └── package-info.java │ │ │ ├── flow │ │ │ └── limit │ │ │ │ ├── FlowBufferManager.java │ │ │ │ ├── LimitEvent.java │ │ │ │ ├── LimitFilter.java │ │ │ │ ├── SemaphoreManager.java │ │ │ │ └── package-info.java │ │ │ ├── proxy │ │ │ ├── ConsumerInterceptor.java │ │ │ ├── ProviderInterceptor.java │ │ │ ├── ProxyFactory.java │ │ │ └── package-info.java │ │ │ ├── rpc │ │ │ ├── Request.java │ │ │ ├── Response.java │ │ │ └── remoting │ │ │ │ ├── LuClient.java │ │ │ │ ├── LuServer.java │ │ │ │ ├── LuUserProcessor.java │ │ │ │ └── Url.java │ │ │ ├── util │ │ │ ├── CloseUtil.java │ │ │ ├── SimpleDateFormatUtil.java │ │ │ └── currence │ │ │ │ ├── ChannelType.java │ │ │ │ ├── FlowBuffer.java │ │ │ │ ├── LuRejectedExecutionHandler.java │ │ │ │ ├── LuThreadFactory.java │ │ │ │ ├── LuThreadPool.java │ │ │ │ ├── LuThreadPoolFactory.java │ │ │ │ └── Semaphore.java │ │ │ └── vmZK │ │ │ ├── LocalFileRegister.java │ │ │ └── ServiceRegisterDisCover.java │ └── resources │ │ ├── application.properties │ │ └── log4j.xml │ └── test │ └── java │ └── thinkinjava │ ├── proxy │ └── InterceptorTest.java │ ├── rpc │ └── remoting │ │ ├── LuServerTest.java │ │ ├── MonaLuClientTest.java │ │ ├── RpcTest.java │ │ └── testService │ │ ├── Demo.java │ │ └── DemoImpl.java │ └── vmZK │ └── LocalFileRegisterTest.java ├── example ├── pom.xml └── src │ └── main │ └── java │ └── cn.thinkinjava │ ├── ClientTest.java │ ├── Demo.java │ ├── DemoImpl.java │ └── ServerTest.java ├── extension └── pom.xml ├── filter └── pom.xml ├── lu-netty-remoting └── pom.xml ├── pom.xml ├── proxy └── pom.xml ├── raft-register └── pom.xml ├── readme.md ├── remoting └── pom.xml ├── serializer └── pom.xml └── serviceMesh └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | .mvn 19 | 20 | ### NetBeans ### 21 | /nbproject/private/ 22 | /build/ 23 | /nbbuild/ 24 | /dist/ 25 | /nbdist/ 26 | /.nb-gradle/ 27 | 28 | */target 29 | *.cmd 30 | mvnw 31 | cluster/src/main/resources/ 32 | cluster/src/test/ 33 | common/src/ 34 | config/src/ 35 | extension/src/ 36 | filter/src/ 37 | lu-netty-remoting/src/ 38 | proxy/src/ 39 | raft-register/src/ 40 | remoting/src/ 41 | serializer/src/ 42 | serviceMesh/src/ 43 | -------------------------------------------------------------------------------- /cluster/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Lu-Rpc-parent 7 | cn.thinkinjava 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | cluster 13 | 用于包装多个 invoker,可添加负载均衡,路由等 cluster 类型功能 14 | 15 | 16 | 17 | cn.thinkinjava 18 | core 19 | 0.0.1-SNAPSHOT 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /cluster/src/main/java/cn/thinkinjava/Cluster.java: -------------------------------------------------------------------------------- 1 | package cn.thinkinjava; 2 | 3 | import thinkinjava.core.Invoker; 4 | 5 | /** 6 | * 7 | * @author 莫那·鲁道 8 | * @date 2018/10/19-下午11:03 9 | */ 10 | public interface Cluster { 11 | 12 | void add(Invoker invoker); 13 | 14 | Invoker getWrapperInvoker(); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /cluster/src/main/java/cn/thinkinjava/ClusterInovker.java: -------------------------------------------------------------------------------- 1 | package cn.thinkinjava; 2 | 3 | import thinkinjava.core.Invoker; 4 | import thinkinjava.core.ServiceConfig; 5 | import thinkinjava.rpc.Request; 6 | import thinkinjava.rpc.Response; 7 | 8 | /** 9 | * 10 | * @author 莫那·鲁道 11 | * @date 2018/10/19-下午11:06 12 | */ 13 | public abstract class ClusterInovker implements Invoker { 14 | 15 | public Response invoke(Request req) { 16 | return null; 17 | } 18 | 19 | public ServiceConfig getConfig() { 20 | return null; 21 | } 22 | 23 | protected abstract Response doInvoke(Request req); 24 | } 25 | -------------------------------------------------------------------------------- /cluster/src/main/java/cn/thinkinjava/LoadBalance.java: -------------------------------------------------------------------------------- 1 | package cn.thinkinjava; 2 | 3 | import java.util.List; 4 | 5 | import thinkinjava.core.Invoker; 6 | 7 | /** 8 | * 9 | * 10 | * @author 莫那·鲁道 11 | * @date 2018/10/19-下午10:56 12 | */ 13 | public interface LoadBalance { 14 | 15 | Invoker select(List invokers); 16 | 17 | 18 | } 19 | -------------------------------------------------------------------------------- /cluster/src/main/java/cn/thinkinjava/cluster/AbstractCluster.java: -------------------------------------------------------------------------------- 1 | package cn.thinkinjava.cluster; 2 | 3 | import cn.thinkinjava.Cluster; 4 | import thinkinjava.core.Invoker; 5 | 6 | /** 7 | * 8 | * @author 莫那·鲁道 9 | * @date 2018/10/19-下午11:05 10 | */ 11 | public abstract class AbstractCluster implements Cluster { 12 | 13 | 14 | public void add(Invoker invoker) { 15 | 16 | } 17 | 18 | public Invoker getWrapperInvoker() { 19 | return null; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /cluster/src/main/java/cn/thinkinjava/failover/Failover.java: -------------------------------------------------------------------------------- 1 | package cn.thinkinjava.failover; 2 | 3 | /** 4 | * 5 | * @author 莫那·鲁道 6 | * @date 2018-12-15-11:53 7 | */ 8 | public interface Failover { 9 | 10 | 11 | 12 | } 13 | -------------------------------------------------------------------------------- /cluster/src/main/java/cn/thinkinjava/loadBlancer/AbstractLoadBalance.java: -------------------------------------------------------------------------------- 1 | package cn.thinkinjava.loadBlancer; 2 | 3 | import java.util.List; 4 | 5 | import cn.thinkinjava.LoadBalance; 6 | import thinkinjava.core.Invoker; 7 | 8 | /** 9 | * 10 | * 11 | * @author 莫那·鲁道 12 | * @date 2018/10/19-下午11:00 13 | */ 14 | public abstract class AbstractLoadBalance implements LoadBalance { 15 | 16 | protected List invokers; 17 | 18 | public AbstractLoadBalance(List invokers) { 19 | this.invokers = invokers; 20 | } 21 | 22 | public Invoker select(List invokers) { 23 | return doSelect(invokers); 24 | } 25 | 26 | protected abstract Invoker doSelect(List invokers); 27 | } 28 | -------------------------------------------------------------------------------- /common/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Lu-Rpc-parent 7 | cn.thinkinjava 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | common 13 | 一些公用的组件 14 | 15 | 16 | -------------------------------------------------------------------------------- /config/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Lu-Rpc-parent 7 | cn.thinkinjava 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | config 13 | RPC 框架的各种配置 14 | 15 | 16 | -------------------------------------------------------------------------------- /core/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Lu-Rpc-parent 7 | cn.thinkinjava 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | core 13 | 核心模块, 尽量不要在此模块添加功能. 核心层应当只包括 invoker, 14 | 15 | 16 | 17 | org.apache.maven.plugins 18 | maven-compiler-plugin 19 | 20 | 8 21 | 8 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/LifeCycle.java: -------------------------------------------------------------------------------- 1 | package thinkinjava; 2 | 3 | public interface LifeCycle { 4 | 5 | /** 初始化资源 */ 6 | void init() throws Throwable; 7 | 8 | /** 关闭资源 */ 9 | void destroy() throws Throwable; 10 | 11 | } 12 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/api/client/LuConsumer.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.api.client; 2 | 3 | import thinkinjava.core.ConsumerInvoker; 4 | import thinkinjava.proxy.ConsumerInterceptor; 5 | import thinkinjava.proxy.ProxyFactory; 6 | 7 | /** 8 | * 服务消费者 API 9 | * 10 | * @author 莫那·鲁道 11 | * @date 2018/10/14-下午10:13 12 | */ 13 | public class LuConsumer { 14 | 15 | private LuConsumerConfig config; 16 | 17 | private T proxy; 18 | 19 | public LuConsumer(LuConsumerConfig config) { 20 | this.config = config; 21 | } 22 | 23 | /** 24 | * 从注册中心引用一个服务. 即接口类型. 25 | */ 26 | @SuppressWarnings("unchecked") 27 | public T ref() { 28 | 29 | if (proxy != null) { 30 | return proxy; 31 | } 32 | proxy = (T) ProxyFactory.getProxy(config.getService(), new ConsumerInterceptor(new ConsumerInvoker(config))); 33 | return proxy; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/api/client/LuConsumerConfig.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.api.client; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import thinkinjava.core.BaseServiceConfig; 7 | import thinkinjava.exception.UserOperationException; 8 | import thinkinjava.rpc.remoting.Url; 9 | 10 | /** 11 | * 12 | * 13 | * @author 莫那·鲁道 14 | * @date 2018/10/14-下午10:14 15 | */ 16 | public class LuConsumerConfig extends BaseServiceConfig { 17 | 18 | private static final Logger LOGGER = LoggerFactory.getLogger("LuConsumerConfig"); 19 | 20 | 21 | @Override 22 | public Url getServiceUrl() { 23 | try { 24 | return serviceRegisterDisCover.getServiceUrl(getServiceName()); 25 | 26 | } catch (UserOperationException e) { 27 | LOGGER.error(e.getMessage(), e); 28 | System.exit(1); 29 | } 30 | return null; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/api/server/LuProvider.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.api.server; 2 | 3 | import thinkinjava.rpc.remoting.LuServer; 4 | 5 | /** 6 | * 服务提供者 API 7 | * 8 | * @author 莫那·鲁道 9 | * @date 2018/10/14-下午10:18 10 | */ 11 | @SuppressWarnings("unchecked") 12 | public class LuProvider { 13 | 14 | private LuProviderConfig config; 15 | 16 | public LuProvider(LuProviderConfig config) { 17 | this.config = config; 18 | } 19 | 20 | /** 21 | * 发布到注册中心,同时启动 RPC 服务器. 端口 8081 22 | */ 23 | public void export() { 24 | // 注册到一个地方. 代表发布出去. 例如 zk 25 | config.registerService(config.getService(), config.getServiceUrl()); 26 | 27 | ProviderManager.putProvider(config.getServiceName(), this); 28 | 29 | LuServer.create(8081).start(); 30 | } 31 | 32 | public LuProviderConfig getConfig() { 33 | return config; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/api/server/LuProviderConfig.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.api.server; 2 | 3 | import thinkinjava.core.BaseServiceConfig; 4 | import thinkinjava.core.ProviderInvoker; 5 | import thinkinjava.proxy.ProviderInterceptor; 6 | import thinkinjava.proxy.ProxyFactory; 7 | import thinkinjava.rpc.remoting.Url; 8 | 9 | /** 10 | * 11 | * 12 | * @author 莫那·鲁道 13 | * @date 2018/10/14-下午10:31 14 | */ 15 | public class LuProviderConfig extends BaseServiceConfig { 16 | 17 | private Object ref; 18 | 19 | private Object refProxy; 20 | 21 | public Object getRef() { 22 | return ref; 23 | } 24 | 25 | 26 | public void setRef(Class ref) { 27 | try { 28 | this.ref = ref.newInstance(); 29 | this.refProxy = ProxyFactory.getProxy(getService(), new ProviderInterceptor(new ProviderInvoker(this.ref,this))); 30 | } catch (InstantiationException e) { 31 | e.printStackTrace(); 32 | } catch (IllegalAccessException e) { 33 | e.printStackTrace(); 34 | } 35 | } 36 | 37 | public void setRef(Object ref) { 38 | this.ref = ref; 39 | this.refProxy = ProxyFactory.getProxy(getService(), new ProviderInterceptor(new ProviderInvoker(this.ref, this))); 40 | } 41 | 42 | public Object getRefProxy() { 43 | return refProxy; 44 | } 45 | 46 | public void setRefProxy(Object refProxy) { 47 | this.refProxy = refProxy; 48 | } 49 | 50 | public Url getServiceUrl() { 51 | return serviceRegisterDisCover.getServiceUrl(getServiceName()); 52 | } 53 | 54 | public void setServiceUrl(Url url) { 55 | serviceRegisterDisCover.registerService(getServiceName(), url); 56 | } 57 | 58 | void registerService(Class serviceClass, Url url) { 59 | serviceRegisterDisCover.registerService(serviceClass.getName(), url); 60 | } 61 | 62 | void registerService(Class serviceClass) { 63 | registerService(serviceClass, new Url()); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/api/server/ProviderManager.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.api.server; 2 | 3 | import java.util.Map; 4 | import java.util.concurrent.ConcurrentHashMap; 5 | 6 | /** 7 | * 8 | * 9 | * @author 莫那·鲁道 10 | * @date 2018/10/16-下午7:12 11 | */ 12 | public class ProviderManager { 13 | 14 | private static Map cache = new ConcurrentHashMap(); 15 | 16 | public static LuProvider getProvider(String name) { 17 | return cache.get(name); 18 | } 19 | 20 | public static void putProvider(String name, LuProvider luProvider) { 21 | cache.put(name, luProvider); 22 | } 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/breaker/CircuitBreaker.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.breaker; 2 | 3 | import java.util.Date; 4 | 5 | import thinkinjava.conf.DynamicProperties; 6 | import thinkinjava.conf.DynamicProperty; 7 | import thinkinjava.conf.Plugins; 8 | import thinkinjava.event.EventBus; 9 | 10 | import static thinkinjava.breaker.CircuitBreaker.State.CLOSE; 11 | import static thinkinjava.breaker.CircuitBreaker.State.HALF_OPEN; 12 | import static thinkinjava.breaker.CircuitBreaker.State.OPEN; 13 | import static thinkinjava.conf.Constant.DEFAULT_EXCEPTION_RATIO; 14 | import static thinkinjava.conf.Constant.DEFAULT_LESS_REQUEST; 15 | import static thinkinjava.conf.Constant.DEFAULT_SLEEP_TIME_SECONDS; 16 | import static thinkinjava.conf.Constant.EXCEPTION_RATIO; 17 | import static thinkinjava.conf.Constant.LESS_REQUEST; 18 | import static thinkinjava.conf.Constant.SLEEP_TIME_SECONDS; 19 | 20 | /** 21 | * 22 | * 熔断器. 23 | * 24 | * 4 种状态变化: 25 | * 1. CLOSE to OPEN 26 | * 2. OPEN to HALF_OPEN 27 | * 3. HALF_OPEN to OPEN 28 | * 4. HALF_OPEN to CLOSE 29 | * 30 | */ 31 | public class CircuitBreaker { 32 | 33 | public static CircuitBreaker getInstance() { 34 | return CircuitBreakerInner.INSTANCE; 35 | } 36 | 37 | private volatile int sleepTime; 38 | private volatile int less; 39 | private volatile int expRatio; 40 | 41 | private DynamicProperty sleepTime_; 42 | private DynamicProperty less_; 43 | private DynamicProperty expRatio_; 44 | 45 | DynamicProperties properties = Plugins.getInstance().getDynamicProperties(); 46 | 47 | private CircuitBreaker() { 48 | init(); 49 | } 50 | 51 | private static class CircuitBreakerInner { 52 | 53 | private static final CircuitBreaker INSTANCE = new CircuitBreaker(); 54 | } 55 | 56 | private void init() { 57 | sleepTime_ = properties.getInteger(SLEEP_TIME_SECONDS, DEFAULT_SLEEP_TIME_SECONDS); 58 | sleepTime = sleepTime_.get(); 59 | sleepTime_.addCallback(() -> sleepTime = sleepTime_.get()); 60 | 61 | less_ = properties.getInteger(LESS_REQUEST, DEFAULT_LESS_REQUEST); 62 | less = less_.get(); 63 | less_.addCallback(() -> less = less_.get()); 64 | 65 | expRatio_ = properties.getInteger(EXCEPTION_RATIO, DEFAULT_EXCEPTION_RATIO); 66 | expRatio = expRatio_.get(); 67 | expRatio_.addCallback(() -> expRatio = expRatio_.get()); 68 | } 69 | 70 | /** 71 | * 尝试调用: 72 | * 如果是 CLOSE 状态, 立即调用. 73 | * 如果是 HALF_OPEN 状态, 停止调用. 74 | * 如果是 OPEN 状态, 检查是否超过休眠时间, 如果超过, 尝试修改为半开并调用, 防止并发时过多请求进入. 75 | * @param state 76 | * @return true 表示可以调用, 反之不能调用. 77 | */ 78 | public boolean tryInvoke(CircuitState state) { 79 | if (state.getState().get() == CLOSE) { 80 | return true; 81 | } 82 | if (state.getState().get() == HALF_OPEN) { 83 | return false; 84 | } 85 | 86 | if (state.getStartTime() + sleepTime < System.currentTimeMillis()) { 87 | // open to half_open 88 | return state.getState().compareAndSet(OPEN, HALF_OPEN); 89 | } 90 | return true; 91 | 92 | 93 | } 94 | 95 | /** 96 | * 当 HALF_OPEN 时调用成功. 97 | * @param state 98 | */ 99 | public void success(CircuitState state) { 100 | // half_open To Close 101 | if (state.getState().compareAndSet(HALF_OPEN, CLOSE)) { 102 | state.setStartTime(-1); 103 | // 发布恢复事件. 104 | publishRenewEvent(state); 105 | } 106 | } 107 | 108 | /** 109 | * HALF_OPEN 调用失败: 修改为 OPEN. 110 | * CLOSE 调用失败, 判断是否超过错误百分比. 111 | * @param state 112 | */ 113 | public void fail(CircuitState state) { 114 | if (state.getState().get() == HALF_OPEN) { 115 | tryHalfOpen2open(state); 116 | } else if (state.getState().get() == CLOSE) { 117 | tryClose2open(state); 118 | } 119 | } 120 | 121 | private void tryClose2open(CircuitState state) { 122 | long total = WindowsManager.getTotal(state.getUnique()); 123 | 124 | // 最少得 {xxx} 个请求.才触发熔断逻辑 125 | if (total < less) { 126 | return; 127 | } 128 | // 例如大于 {xxx}% ,熔断. 129 | if (WindowsManager.getExceptionRatio(state.getUnique()) >= expRatio) { 130 | if (state.getState().compareAndSet(CLOSE, OPEN)) { 131 | // 更新时间 132 | state.setStartTime(System.currentTimeMillis()); 133 | 134 | // 发布熔断事件. 135 | publishBreakerEvent(state); 136 | } 137 | } 138 | } 139 | 140 | private void tryHalfOpen2open(CircuitState state) { 141 | if (state.getState().compareAndSet(HALF_OPEN, OPEN)) { 142 | state.setStartTime(System.currentTimeMillis()); 143 | 144 | // 发布熔断事件. 相当于没 sleepTime 发布一次事件. 145 | publishBreakerEvent(state); 146 | } 147 | 148 | } 149 | 150 | 151 | /** 152 | * 发布熔断事件. 153 | */ 154 | private void publishBreakerEvent(CircuitState state) { 155 | // 发布熔断事件 156 | CircuitBreakerEvent event = CircuitBreakerEvent.newBuilder().unique(state.getUnique()).startTime(new Date()).build(); 157 | EventBus.post(event); 158 | } 159 | 160 | /** 161 | * 发布恢复事件. 162 | */ 163 | private void publishRenewEvent(CircuitState state) { 164 | // 发布恢复事件. 165 | CircuitRenewEvent renewEvent = CircuitRenewEvent.newBuilder().unique(state.getUnique()).endTime(new Date()).build(); 166 | EventBus.post(renewEvent); 167 | } 168 | 169 | 170 | public enum State { 171 | /** 熔断器打开 */ 172 | OPEN, 173 | /** 熔断器半开 */ 174 | HALF_OPEN, 175 | /** 熔断器关闭 */ 176 | CLOSE 177 | } 178 | 179 | } 180 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/breaker/CircuitBreakerEvent.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.breaker; 2 | 3 | import java.util.Date; 4 | 5 | import thinkinjava.event.Event; 6 | import thinkinjava.util.SimpleDateFormatUtil; 7 | 8 | /** 9 | * 10 | * 熔断事件. 11 | * 12 | */ 13 | public class CircuitBreakerEvent implements Event { 14 | 15 | private String unique; 16 | 17 | private Date startTime; 18 | 19 | private CircuitBreakerEvent(Builder builder) { 20 | setUnique(builder.unique); 21 | setStartTime(builder.startTime); 22 | } 23 | 24 | public static Builder newBuilder() { 25 | return new Builder(); 26 | } 27 | 28 | public String getUnique() { 29 | return unique; 30 | } 31 | 32 | public void setUnique(String unique) { 33 | this.unique = unique; 34 | } 35 | 36 | public Date getStartTime() { 37 | return startTime; 38 | } 39 | 40 | public void setStartTime(Date startTime) { 41 | this.startTime = startTime; 42 | } 43 | 44 | @Override 45 | public String toString() { 46 | return "CircuitBreakerEvent{" + 47 | "unique='" + unique + '\'' + 48 | ", startTime=" + SimpleDateFormatUtil.format1(startTime) + 49 | '}'; 50 | } 51 | 52 | public static final class Builder { 53 | 54 | private String unique; 55 | private Date startTime; 56 | 57 | private Builder() { 58 | } 59 | 60 | public Builder unique(String val) { 61 | unique = val; 62 | return this; 63 | } 64 | 65 | public Builder startTime(Date val) { 66 | startTime = val; 67 | return this; 68 | } 69 | 70 | public CircuitBreakerEvent build() { 71 | return new CircuitBreakerEvent(this); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/breaker/CircuitBreakerFilter.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.breaker; 2 | 3 | 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import thinkinjava.core.Invoker; 8 | import thinkinjava.exception.CircuitBreakerException; 9 | import thinkinjava.filter.Filter; 10 | import thinkinjava.rpc.Request; 11 | import thinkinjava.rpc.Response; 12 | 13 | /** 14 | * 熔断检查过滤器 15 | */ 16 | public class CircuitBreakerFilter implements Filter { 17 | 18 | private static final Logger LOGGER = LoggerFactory.getLogger(CircuitBreakerFilter.class); 19 | 20 | 21 | 22 | private CircuitBreaker circuitBreaker = CircuitBreaker.getInstance(); 23 | 24 | public static CircuitBreakerFilter getInstance() { 25 | return CircuitBreakerFilterInner.INSTANCE; 26 | } 27 | 28 | 29 | private static class CircuitBreakerFilterInner { 30 | 31 | private static final CircuitBreakerFilter INSTANCE = new CircuitBreakerFilter(); 32 | } 33 | 34 | private CircuitBreakerFilter() { 35 | } 36 | 37 | 38 | @Override 39 | public Response filter(Invoker invoker, Request request) throws Throwable { 40 | 41 | LOGGER.info("CircuitBreakerFilter filtering"); 42 | 43 | String unique = request.getUnique(); 44 | CircuitState cs = CircuitStateManager.getInstance().getCircuitState(unique); 45 | 46 | // 可能是 CLOSE, 也可能是 HALF_OPEN 47 | if (circuitBreaker.tryInvoke(cs)) { 48 | try { 49 | Response res = invoker.invoke(request); 50 | 51 | // 调用成功, 关闭 HALF_OPEN. 52 | circuitBreaker.success(cs); 53 | 54 | return res; 55 | } catch (Throwable throwable) { 56 | // 处理异常. 57 | circuitBreaker.fail(cs); 58 | throw throwable; 59 | } 60 | } 61 | throw new CircuitBreakerException("CircuitBreaker State : " + cs.getState().get().name() + ", unique : " + unique); 62 | 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/breaker/CircuitBreakerStatFilter.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.breaker; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import thinkinjava.core.Invoker; 7 | import thinkinjava.filter.Filter; 8 | import thinkinjava.rpc.Request; 9 | import thinkinjava.rpc.Response; 10 | 11 | /** 12 | * 13 | * 熔断数据统计. 14 | */ 15 | public class CircuitBreakerStatFilter implements Filter { 16 | 17 | private static final Logger LOGGER = LoggerFactory.getLogger(CircuitBreakerStatFilter.class); 18 | 19 | 20 | private CircuitStateManager circuitStateManager = CircuitStateManager.getInstance(); 21 | 22 | 23 | private CircuitBreakerStatFilter() { 24 | } 25 | 26 | public static CircuitBreakerStatFilter getInstance() { 27 | return CircuitBreakerStatFilterLazyHolder.INSTANCE; 28 | } 29 | 30 | private static class CircuitBreakerStatFilterLazyHolder { 31 | 32 | private static final CircuitBreakerStatFilter INSTANCE = new CircuitBreakerStatFilter(); 33 | } 34 | 35 | @Override 36 | public Response filter(Invoker invoker, Request request) throws Throwable { 37 | 38 | LOGGER.info("CircuitBreakerStatFilter filtering"); 39 | 40 | String unique = request.getUnique(); 41 | // 无论成功失败, 都要统计. 42 | circuitStateManager.handlerNormal(unique); 43 | 44 | Response res = null; 45 | try { 46 | res = invoker.invoke(request); 47 | } catch (Throwable throwable) { 48 | circuitStateManager.handlerError(unique); 49 | throw throwable; 50 | } 51 | return res; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/breaker/CircuitRenewEvent.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.breaker; 2 | 3 | import java.util.Date; 4 | 5 | import thinkinjava.event.Event; 6 | import thinkinjava.util.SimpleDateFormatUtil; 7 | 8 | /** 9 | * 10 | * 电路恢复事件. 11 | */ 12 | public class CircuitRenewEvent implements Event { 13 | 14 | private String unique; 15 | 16 | private Date endTime; 17 | 18 | 19 | public CircuitRenewEvent(String unique, Date endTime) { 20 | this.unique = unique; 21 | this.endTime = endTime; 22 | } 23 | 24 | private CircuitRenewEvent(Builder builder) { 25 | setUnique(builder.unique); 26 | setEndTime(builder.endTime); 27 | } 28 | 29 | public static Builder newBuilder() { 30 | return new Builder(); 31 | } 32 | 33 | public String getUnique() { 34 | return unique; 35 | } 36 | 37 | public void setUnique(String unique) { 38 | this.unique = unique; 39 | } 40 | 41 | public Date getEndTime() { 42 | return endTime; 43 | } 44 | 45 | public void setEndTime(Date endTime) { 46 | this.endTime = endTime; 47 | } 48 | 49 | @Override 50 | public String toString() { 51 | return "CircuitRenewEvent{" + 52 | "unique='" + unique + '\'' + 53 | ", endTime=" + SimpleDateFormatUtil.format1(endTime) + 54 | '}'; 55 | } 56 | 57 | public static final class Builder { 58 | 59 | private String unique; 60 | private Date endTime; 61 | 62 | private Builder() { 63 | } 64 | 65 | public Builder unique(String val) { 66 | unique = val; 67 | return this; 68 | } 69 | 70 | public Builder endTime(Date val) { 71 | endTime = val; 72 | return this; 73 | } 74 | 75 | public CircuitRenewEvent build() { 76 | return new CircuitRenewEvent(this); 77 | } 78 | } 79 | } 80 | 81 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/breaker/CircuitState.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.breaker; 2 | 3 | import java.io.Serializable; 4 | import java.util.concurrent.atomic.AtomicLong; 5 | import java.util.concurrent.atomic.AtomicReference; 6 | 7 | public class CircuitState implements Serializable { 8 | 9 | private static final long serialVersionUID = 3911162672779172131L; 10 | 11 | private String unique; 12 | 13 | private final AtomicReference state = new AtomicReference<>(CircuitBreaker.State.CLOSE); 14 | 15 | private AtomicLong startTime; 16 | 17 | public CircuitState(String unique) { 18 | this.unique = unique; 19 | } 20 | 21 | private CircuitState(Builder builder) { 22 | setUnique(builder.unique); 23 | startTime = builder.startTime; 24 | } 25 | 26 | public static Builder newBuilder() { 27 | return new Builder(); 28 | } 29 | 30 | 31 | public String getUnique() { 32 | return unique; 33 | } 34 | 35 | public void setUnique(String unique) { 36 | this.unique = unique; 37 | } 38 | 39 | public AtomicReference getState() { 40 | return state; 41 | } 42 | 43 | public void setState(CircuitBreaker.State state) { 44 | this.state.set(state); 45 | } 46 | 47 | public long getStartTime() { 48 | return startTime.get(); 49 | } 50 | 51 | public void setStartTime(long startTime) { 52 | this.startTime.set(startTime); 53 | } 54 | 55 | @Override 56 | public String toString() { 57 | return "CircuitState{" + 58 | "unique='" + unique + '\'' + 59 | ", state=" + state + 60 | '}'; 61 | } 62 | 63 | 64 | public static final class Builder { 65 | 66 | private String unique; 67 | private AtomicLong startTime; 68 | 69 | private Builder() { 70 | } 71 | 72 | public Builder unique(String val) { 73 | unique = val; 74 | return this; 75 | } 76 | 77 | public Builder startTime(AtomicLong val) { 78 | startTime = val; 79 | return this; 80 | } 81 | 82 | public CircuitState build() { 83 | return new CircuitState(this); 84 | } 85 | } 86 | } 87 | 88 | 89 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/breaker/CircuitStateManager.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.breaker; 2 | 3 | import java.util.concurrent.ConcurrentHashMap; 4 | 5 | /** 6 | * 7 | * 熔断状态管理器. 8 | */ 9 | public class CircuitStateManager { 10 | 11 | private static final ConcurrentHashMap CACHE = new ConcurrentHashMap<>(); 12 | 13 | public static CircuitStateManager getInstance() { 14 | return CircuitStateManagerInner.INSTANCE; 15 | } 16 | 17 | private CircuitStateManager() { 18 | } 19 | 20 | 21 | private static class CircuitStateManagerInner { 22 | 23 | private static final CircuitStateManager INSTANCE = new CircuitStateManager(); 24 | } 25 | 26 | /** 27 | * 获取状态. 28 | */ 29 | public CircuitState getCircuitState(String unique) { 30 | CircuitState cs = CACHE.get(unique); 31 | if (cs == null) { 32 | cs = new CircuitState(unique); 33 | CircuitState old = CACHE.putIfAbsent(unique, cs); 34 | if (old != null) { 35 | cs = old; 36 | } 37 | } 38 | return cs; 39 | } 40 | 41 | /** 42 | * 处理错误信息. 43 | */ 44 | public void handlerError(String unique) { 45 | WindowsManager.statisticError(unique); 46 | } 47 | 48 | /** 49 | * 50 | * 处理所有信息. 51 | * 52 | * @param unique 53 | */ 54 | public void handlerNormal(String unique) { 55 | WindowsManager.statisticNormal(unique); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/breaker/Metrics.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.breaker; 2 | 3 | import java.util.concurrent.atomic.LongAdder; 4 | 5 | 6 | public class Metrics { 7 | 8 | /** 请求总数量 */ 9 | private LongAdder total = new LongAdder(); 10 | /** 异常数量 */ 11 | private LongAdder exception = new LongAdder(); 12 | /** 此桶的计数开始时间 */ 13 | private long startTime; 14 | 15 | public Metrics(long startTime) { 16 | this.startTime = startTime; 17 | } 18 | 19 | public void addException() { 20 | exception.add(1L); 21 | } 22 | 23 | public long getException() { 24 | return exception.sum(); 25 | } 26 | 27 | public void addTotal() { 28 | total.add(1L); 29 | } 30 | 31 | public long getTotal() { 32 | return this.total.sum(); 33 | } 34 | 35 | public long getStartTime() { 36 | return startTime; 37 | } 38 | 39 | public void setStartTime(long startTime) { 40 | this.startTime = startTime; 41 | } 42 | 43 | public Metrics reset(long time) { 44 | total.reset(); 45 | exception.reset(); 46 | startTime = time; 47 | return this; 48 | } 49 | 50 | public Metrics reset() { 51 | total.reset(); 52 | exception.reset(); 53 | return this; 54 | } 55 | 56 | @Override 57 | public String toString() { 58 | return "\r\nMetrics{" + 59 | "total=" + total + 60 | ", exception=" + exception + 61 | ", startTime=" + startTime + 62 | '}'; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/breaker/TimeWindow.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.breaker; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.concurrent.atomic.AtomicReferenceArray; 6 | import java.util.concurrent.locks.ReentrantLock; 7 | 8 | import thinkinjava.conf.DynamicProperties; 9 | import thinkinjava.conf.Plugins; 10 | 11 | import static thinkinjava.conf.Constant.BUCKET_COUNT; 12 | import static thinkinjava.conf.Constant.DEFAULT_BUCKET_COUNT; 13 | import static thinkinjava.conf.Constant.DEFAULT_WINDOWS_LENGTH; 14 | import static thinkinjava.conf.Constant.WINDOWS_LENGTH; 15 | 16 | /** 17 | * 18 | * @author 莫那·鲁道 19 | * @date 2018-12-15-10:29 20 | */ 21 | public class TimeWindow { 22 | private static final long serialVersionUID = 4303657461699755715L; 23 | 24 | private transient DynamicProperties properties = Plugins.getInstance().getDynamicProperties(); 25 | 26 | /** 窗口长度(单个时间长度) {} 秒 */ 27 | private int windowsLength = properties.getInteger(WINDOWS_LENGTH, DEFAULT_WINDOWS_LENGTH).get(); 28 | /** 桶的数量(10 个,也就是10秒) */ 29 | private int bucketCount = properties.getInteger(BUCKET_COUNT, DEFAULT_BUCKET_COUNT).get(); 30 | 31 | private int windowsTime = windowsLength * bucketCount; 32 | 33 | /** 滑动数组 */ 34 | private AtomicReferenceArray array = new AtomicReferenceArray<>(bucketCount); 35 | 36 | private final ReentrantLock lock = new ReentrantLock(); 37 | 38 | public TimeWindow() { 39 | } 40 | 41 | /** 42 | * 43 | * @param bucketCount 可以认为单位就是秒. 因为单个滑动窗口的时间长度是 1000 毫秒. 44 | */ 45 | public TimeWindow(int bucketCount) { 46 | this.windowsLength = DEFAULT_WINDOWS_LENGTH; 47 | this.bucketCount = bucketCount; 48 | this.windowsTime = this.windowsLength * bucketCount; 49 | this.array = new AtomicReferenceArray<>(bucketCount); 50 | } 51 | 52 | /** 53 | * 54 | * 获取当前秒时间的桶. 55 | */ 56 | public Metrics getCurrentWindow() { 57 | // 毫秒 58 | long time = System.currentTimeMillis(); 59 | // 秒 60 | long s = time / windowsLength; 61 | // 获取桶的下标(循环数组) 62 | int idx = (int) (s % bucketCount); 63 | // 让该时间从零开始计数 64 | time = time - time % windowsLength; 65 | 66 | for (; ; ) { 67 | Metrics old = array.get(idx); 68 | if (old == null) { 69 | old = new Metrics(time); 70 | if (array.compareAndSet(idx, null, old)) { 71 | return old; 72 | } else { 73 | Thread.yield(); 74 | } 75 | } else if (time == old.getStartTime()) { 76 | // 就是这个 77 | return old; 78 | } else if (time > old.getStartTime()) { 79 | if (lock.tryLock()) { 80 | try { 81 | // 重置 82 | return old.reset(time); 83 | } finally { 84 | lock.unlock(); 85 | } 86 | } else { 87 | Thread.yield(); 88 | } 89 | } else if (time < old.getStartTime()) { 90 | // 通常不会发生. 91 | throw new RuntimeException(); 92 | } 93 | } 94 | } 95 | 96 | public List values() { 97 | List list = new ArrayList<>(); 98 | for (int i = 0; i < array.length(); i++) { 99 | Metrics mb = array.get(i); 100 | // 必须在当前时间的窗口中 101 | if (mb == null || System.currentTimeMillis() - windowsTime > mb.getStartTime()) { 102 | continue; 103 | } 104 | list.add(mb); 105 | } 106 | return list; 107 | } 108 | 109 | public void reset() { 110 | for (int i = 0; i < array.length(); i++) { 111 | Metrics mb = array.get(i); 112 | if (mb != null) { 113 | mb.reset(); 114 | } 115 | } 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/breaker/WindowsManager.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.breaker; 2 | 3 | 4 | import java.util.List; 5 | import java.util.Map; 6 | import java.util.concurrent.ConcurrentHashMap; 7 | 8 | /** 9 | * 时间窗口生命周期管理器. 10 | */ 11 | public class WindowsManager { 12 | 13 | private static final Map map = new ConcurrentHashMap<>(); 14 | 15 | 16 | public static WindowsManager getInstance() { 17 | return StatisticManagerInner.INSTANCE; 18 | } 19 | 20 | private WindowsManager() { 21 | } 22 | 23 | private static class StatisticManagerInner { 24 | 25 | private static final WindowsManager INSTANCE = new WindowsManager(); 26 | } 27 | 28 | /** 29 | * 处理异常.(对异常数加一) 30 | * @param unique 31 | */ 32 | public static void statisticError(String unique) { 33 | TimeWindow sw = getTimeWindow(unique); 34 | Metrics mb = sw.getCurrentWindow(); 35 | mb.addException(); 36 | } 37 | 38 | /** 39 | * 处理请求(对总数 加一). 40 | * @param unique 41 | */ 42 | public static void statisticNormal(String unique) { 43 | TimeWindow sw = getTimeWindow(unique); 44 | Metrics mb = sw.getCurrentWindow(); 45 | mb.addTotal(); 46 | } 47 | 48 | /** 49 | * 获取异常数. 50 | * @param unique 51 | * @return 52 | */ 53 | public static long getexception(String unique) { 54 | TimeWindow sw = getTimeWindow(unique); 55 | List list = sw.values(); 56 | long exception = 0; 57 | for (Metrics metricsBucket : list) { 58 | exception += metricsBucket.getException(); 59 | } 60 | return exception; 61 | } 62 | 63 | 64 | /** 65 | * 获取总数 66 | * @param unique 67 | * @return 68 | */ 69 | public static long getTotal(String unique) { 70 | TimeWindow sw = getTimeWindow(unique); 71 | List list = sw.values(); 72 | long total = 0; 73 | for (Metrics metrics : list) { 74 | total += metrics.getTotal(); 75 | } 76 | return total; 77 | } 78 | 79 | /** 80 | * 获取该时间窗口的异常比例 81 | */ 82 | public static double getExceptionRatio(String unique) { 83 | TimeWindow sw = getTimeWindow(unique); 84 | List list = sw.values(); 85 | long total = 0; 86 | long exception = 0; 87 | for (Metrics metricsBucket : list) { 88 | total += metricsBucket.getTotal(); 89 | exception += metricsBucket.getException(); 90 | } 91 | if (total == 0) { 92 | return 0.0; 93 | } 94 | return (double) exception / (double) total; 95 | } 96 | 97 | private static TimeWindow getTimeWindow(String unique) { 98 | TimeWindow sw = map.get(unique); 99 | if (sw == null) { 100 | sw = new TimeWindow(); 101 | 102 | TimeWindow old = map.putIfAbsent(unique, sw); 103 | if (old != null) { 104 | sw = old; 105 | } 106 | } 107 | return sw; 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/breaker/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @author 莫那·鲁道 4 | * @date 2019-01-26-11:16 5 | */ 6 | package thinkinjava.breaker; 7 | 8 | /** 9 | * 熔断模块. 类似 hystrix 的熔断设计. 10 | * */ -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/conf/Callback.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.conf; 2 | 3 | public interface Callback { 4 | 5 | void apply(); 6 | } 7 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/conf/Config.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.conf; 2 | 3 | public interface Config { 4 | 5 | /** 6 | * @param key String 7 | * @param defaultValue 默认值 8 | * @return 覆盖默认值. 9 | */ 10 | String getProperty(String key, String defaultValue); 11 | 12 | /** 保持接口语义一致 */ 13 | void setProperty(String key, String val); 14 | } 15 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/conf/ConfigBuilder.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.conf; 2 | 3 | import java.util.Iterator; 4 | import java.util.ServiceLoader; 5 | 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | public class ConfigBuilder { 10 | 11 | private static final Logger LOGGER = LoggerFactory.getLogger(ConfigBuilder.class); 12 | 13 | /** 单例全局, 系统依赖此配置对象. */ 14 | private Config config; 15 | 16 | private static ConfigBuilder getInstance() { 17 | return ConfigBuilderInner.INSTANCE; 18 | } 19 | 20 | private ConfigBuilder() { 21 | init(); 22 | } 23 | 24 | public void init() { 25 | ServiceLoader configs = ServiceLoader.load(Config.class); 26 | 27 | Iterator iterator = configs.iterator(); 28 | while (iterator.hasNext()) { 29 | config = iterator.next(); 30 | LOGGER.info("SPI Config Load Success , Config Implement Class : [{}]", config.getClass().getName()); 31 | break; 32 | } 33 | if (config == null) { 34 | config = new DefaultConfig(); 35 | LOGGER.info("No SPI Config, Config Implement Class : [{}]", config.getClass().getName()); 36 | } 37 | } 38 | 39 | private static class ConfigBuilderInner { 40 | 41 | private static final ConfigBuilder INSTANCE = new ConfigBuilder(); 42 | } 43 | 44 | public static ConfigBuilder create() { 45 | return getInstance(); 46 | } 47 | 48 | /** 49 | * 返回的必须是单例. 50 | * @return 单例 config 对象. 51 | */ 52 | public Config build() { 53 | return config; 54 | } 55 | 56 | 57 | @Override 58 | public String toString() { 59 | return "ConfigBuilder{" + 60 | "config=" + config + 61 | '}'; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/conf/Constant.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.conf; 2 | 3 | /** 4 | * 5 | * @author 莫那·鲁道 6 | * @date 2018-12-15-10:42 7 | */ 8 | public interface Constant { 9 | 10 | /** 异常比例 double */ 11 | String EXCEPTION_RATIO = "exception.ratio"; 12 | int DEFAULT_EXCEPTION_RATIO = 50; 13 | 14 | 15 | /** 最少请求量 int */ 16 | String LESS_REQUEST = "less.request"; 17 | int DEFAULT_LESS_REQUEST = 20; 18 | 19 | /** 熔断后休眠时间 int 单位毫秒 */ 20 | String SLEEP_TIME_SECONDS = "sleep.time.seconds"; 21 | // 5 * 1000; 22 | int DEFAULT_SLEEP_TIME_SECONDS = 5000; 23 | 24 | /** 单个滑动窗口的时间长度, int 单位 : 毫秒; 注意: 必须能被 1000 整除*/ 25 | String WINDOWS_LENGTH = "windows.length"; 26 | int DEFAULT_WINDOWS_LENGTH = 1000; 27 | 28 | /** 滑动窗口的窗口数量; int; */ 29 | String BUCKET_COUNT = "bucket.count"; 30 | int DEFAULT_BUCKET_COUNT = 10; 31 | 32 | /** 控制台端口号 */ 33 | String ADMIN_PORT = "admin.port"; 34 | int DEFAULT_ADMIN_PORT = 8321; 35 | 36 | /** 第三方服务被访问需要统计, 这个是统计的时间间隔 */ 37 | String UNIQUE_HINT_COUNT_STATISTICS_INTERVAL = "unique.hint.count.statistics.interval"; 38 | /** 5 * 60 (不能超过 int 最大值)*/ 39 | int DEFAULT_UNIQUE_HINT_COUNT_STATISTICS_INTERVAL = 10; 40 | 41 | /** 流量缓冲区的队列长度, 超过长度则直接抛出限流异常 */ 42 | String FLOW_BUFFER_QUEUE_MAX_SIZE = "flow.buffer.queue.max.size"; 43 | int DEFAULT_FLOW_BUFFER_QUEUE_MAX_SIZE = 32; 44 | 45 | /** 流量缓冲区请求的缓冲时间, 单位毫秒 */ 46 | String FLOW_BUFFER_WAIT_TIME_OUT = "flow.buffer.wait.time.out"; 47 | long DEFAULT_FLOW_BUFFER_WAIT_TIME_OUT = 200; 48 | 49 | } 50 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/conf/DefaultConfig.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.conf; 2 | 3 | import java.util.concurrent.ConcurrentHashMap; 4 | 5 | public class DefaultConfig implements Config { 6 | 7 | private ConcurrentHashMap concurrentHashMap = new ConcurrentHashMap<>(); 8 | 9 | @Override 10 | public String getProperty(String key, String defaultValue) { 11 | String v = concurrentHashMap.get(key); 12 | if (v == null) { 13 | v = defaultValue; 14 | } 15 | return v; 16 | } 17 | 18 | @Override 19 | public void setProperty(String key, String val) { 20 | concurrentHashMap.put(key, val); 21 | } 22 | 23 | @Override 24 | public String toString() { 25 | return "DefaultConfig{" + 26 | "concurrentHashMap=" + concurrentHashMap + 27 | '}'; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/conf/DefaultDynamicProperties.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.conf; 2 | 3 | import java.util.Map; 4 | import java.util.concurrent.ConcurrentHashMap; 5 | import java.util.concurrent.CopyOnWriteArrayList; 6 | import java.util.concurrent.ThreadPoolExecutor; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | import com.alipay.sofa.common.profile.StringUtil; 10 | 11 | import thinkinjava.LifeCycle; 12 | import thinkinjava.util.currence.LuThreadPoolFactory; 13 | 14 | 15 | public class DefaultDynamicProperties implements DynamicProperties, LifeCycle { 16 | 17 | private Map> callbacks = new ConcurrentHashMap<>(); 18 | 19 | private Config config = ConfigBuilder.create().build(); 20 | 21 | private ThreadPoolExecutor pool = LuThreadPoolFactory.getThreadPool(1, getClass().getName()); 22 | 23 | private DefaultDynamicProperties() { 24 | init(); 25 | } 26 | 27 | public static DefaultDynamicProperties getInstance() { 28 | return SystemDynamicPropertiesLazyHolder.INSTANCE; 29 | } 30 | 31 | private static class SystemDynamicPropertiesLazyHolder { 32 | 33 | private static final DefaultDynamicProperties INSTANCE = new DefaultDynamicProperties(); 34 | } 35 | 36 | @Override 37 | public void init() { 38 | pool.execute(new Runnable() { 39 | @Override 40 | public void run() { 41 | for (; ; ) { 42 | try { 43 | TimeUnit.SECONDS.sleep(1); 44 | for (Map.Entry> e : callbacks.entrySet()) { 45 | for (Callback callback : e.getValue()) { 46 | callback.apply(); 47 | } 48 | } 49 | } catch (Exception e) { 50 | // ignore 51 | } 52 | } 53 | } 54 | }); 55 | } 56 | 57 | @Override 58 | public void destroy() throws Exception { 59 | pool.shutdown(); 60 | } 61 | 62 | @Override 63 | public DynamicProperty getString(String name, String defaultVal) { 64 | return new DynamicProperty() { 65 | @Override 66 | public String getName() { 67 | return name; 68 | } 69 | 70 | @Override 71 | public void addCallback(Callback callback) { 72 | addCallback0(this, callback); 73 | } 74 | 75 | @Override 76 | public String get() { 77 | return config.getProperty(name, defaultVal); 78 | } 79 | }; 80 | } 81 | 82 | @Override 83 | public DynamicProperty getInteger(String name, Integer defaultVal) { 84 | return new DynamicProperty() { 85 | @Override 86 | public String getName() { 87 | return name; 88 | } 89 | 90 | @Override 91 | public void addCallback(Callback callback) { 92 | addCallback0(this, callback); 93 | } 94 | 95 | @Override 96 | public Integer get() { 97 | String r = config.getProperty(name, ""); 98 | 99 | if (StringUtil.isBlank(r)) { 100 | return defaultVal; 101 | } 102 | return Integer.valueOf(r); 103 | } 104 | }; 105 | } 106 | 107 | @Override 108 | public DynamicProperty getLong(String name, Long defaultVal) { 109 | return new DynamicProperty() { 110 | @Override 111 | public String getName() { 112 | return name; 113 | } 114 | 115 | @Override 116 | public void addCallback(Callback callback) { 117 | addCallback0(this, callback); 118 | } 119 | 120 | @Override 121 | public Long get() { 122 | String r = config.getProperty(name, ""); 123 | 124 | if (StringUtil.isBlank(r)) { 125 | return defaultVal; 126 | } 127 | return Long.valueOf(r); 128 | } 129 | }; 130 | } 131 | 132 | 133 | @Override 134 | public DynamicProperty getBoolean(String name, Boolean defaultVal) { 135 | return new DynamicProperty() { 136 | @Override 137 | public String getName() { 138 | return name; 139 | } 140 | 141 | @Override 142 | public void addCallback(Callback callback) { 143 | addCallback0(this, callback); 144 | } 145 | 146 | @Override 147 | public Boolean get() { 148 | String r = config.getProperty(name, ""); 149 | 150 | if (StringUtil.isBlank(r)) { 151 | return defaultVal; 152 | } 153 | return Boolean.valueOf(r); 154 | } 155 | }; 156 | } 157 | 158 | private void addCallback0(DynamicProperty dynamicProperty, Callback callback) { 159 | if (callbacks.get(dynamicProperty) == null) { 160 | CopyOnWriteArrayList list = new CopyOnWriteArrayList<>(); 161 | list.add(callback); 162 | callbacks.put(dynamicProperty, list); 163 | } else { 164 | callbacks.get(dynamicProperty).add(callback); 165 | } 166 | 167 | } 168 | 169 | 170 | } 171 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/conf/DynamicProperties.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.conf; 2 | 3 | public interface DynamicProperties { 4 | 5 | DynamicProperty getString(String name, String defaultVal); 6 | 7 | DynamicProperty getInteger(String name, Integer defaultVal); 8 | 9 | DynamicProperty getLong(String name, Long defaultVal); 10 | 11 | DynamicProperty getBoolean(String name, Boolean defaultVal); 12 | 13 | 14 | } 15 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/conf/DynamicProperty.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.conf; 2 | 3 | public interface DynamicProperty extends Property { 4 | 5 | String getName(); 6 | 7 | void addCallback(Callback callback); 8 | } 9 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/conf/Plugins.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.conf; 2 | 3 | import java.util.ServiceLoader; 4 | 5 | 6 | public class Plugins { 7 | 8 | private final DynamicProperties dynamicProperties; 9 | 10 | private Plugins() { 11 | dynamicProperties = loadDynamicProperties(); 12 | } 13 | 14 | 15 | public static Plugins getInstance() { 16 | return PluginsLazyHolder.INSTANCE; 17 | } 18 | 19 | private static class PluginsLazyHolder { 20 | 21 | private static final Plugins INSTANCE = new Plugins(); 22 | } 23 | 24 | 25 | public DynamicProperties getDynamicProperties() { 26 | return dynamicProperties; 27 | } 28 | 29 | private DynamicProperties loadDynamicProperties() { 30 | DynamicProperties d = getPluginImpl(DynamicProperties.class, DefaultDynamicProperties.getInstance()); 31 | 32 | if (d == null) { 33 | d = findSPI(DynamicProperties.class, getClass().getClassLoader()); 34 | } 35 | if (d == null) { 36 | d = DefaultDynamicProperties.getInstance(); 37 | } 38 | return d; 39 | } 40 | 41 | 42 | /** 43 | * 先加载配置文件. 再加载 SPI. 最后使用默认(从系统环境变量获取). 44 | * 45 | * @param pluginClass 46 | * @param dynamicProperties 47 | * @param 48 | * @return 49 | */ 50 | private static T getPluginImpl(Class pluginClass, DynamicProperties dynamicProperties) { 51 | String name = pluginClass.getSimpleName(); 52 | 53 | String propertyName = "lu-rpc.config.plugin." + name + ".impl"; 54 | 55 | String impl = dynamicProperties.getString(propertyName, null).get(); 56 | if (impl != null) { 57 | try { 58 | Class cls = Class.forName(impl); 59 | // narrow the scope (cast) to the type we're expecting 60 | cls = cls.asSubclass(pluginClass); 61 | return (T) cls.newInstance(); 62 | } catch (ClassCastException e) { 63 | throw new RuntimeException( 64 | name + " implementation is not an instance of " + name + ": " + impl); 65 | } catch (ClassNotFoundException e) { 66 | throw new RuntimeException(name + " implementation class not found: " + impl, e); 67 | } catch (InstantiationException e) { 68 | throw new RuntimeException(name + " implementation not able to be instantiated: " + impl, e); 69 | } catch (IllegalAccessException e) { 70 | throw new RuntimeException(name + " implementation not able to be accessed: " + impl, e); 71 | } 72 | } else { 73 | return null; 74 | } 75 | } 76 | 77 | private static T findSPI(Class spi, ClassLoader classLoader) { 78 | ServiceLoader sl = ServiceLoader.load(spi, 79 | classLoader); 80 | for (T s : sl) { 81 | if (s != null) { 82 | return s; 83 | } 84 | } 85 | return null; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/conf/Property.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.conf; 2 | 3 | public interface Property { 4 | 5 | T get(); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/conf/ServerConfig.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.conf; 2 | 3 | import java.util.Map; 4 | import java.util.concurrent.ConcurrentHashMap; 5 | 6 | /** 7 | * 8 | * 9 | * @author 莫那·鲁道 10 | * @date 2018/10/16-下午8:29 11 | */ 12 | public class ServerConfig { 13 | 14 | private final static Map CONFIG = new ConcurrentHashMap(); 15 | 16 | public static Object getProperty(String key) { 17 | Object v = System.getProperty(key); 18 | if (v == null) { 19 | return CONFIG.get(key); 20 | } 21 | 22 | return null; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/conf/ServerConstants.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.conf; 2 | 3 | /** 4 | * 5 | * 6 | * @author 莫那·鲁道 7 | * @date 2018/10/16-下午8:32 8 | */ 9 | public interface ServerConstants { 10 | 11 | String IP = "127.0.0.1"; 12 | int PORT = 8081; 13 | 14 | 15 | } 16 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/conf/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 4 | * @author 莫那·鲁道 5 | * @date 2019-01-26-11:06 6 | */ 7 | package thinkinjava.conf; 8 | 9 | /** 10 | * 11 | * 这是一个动态配置, 配合分布式配置中心(例如 Apollo) 可动态修改配置. 12 | * 13 | * */ -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/core/BaseServiceConfig.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.core; 2 | 3 | import thinkinjava.vmZK.LocalFileRegister; 4 | import thinkinjava.vmZK.ServiceRegisterDisCover; 5 | 6 | /** 7 | * 8 | * 9 | * @author 莫那·鲁道 10 | * @date 2018/10/15-下午9:41 11 | */ 12 | public abstract class BaseServiceConfig implements ServiceConfig { 13 | 14 | protected ServiceRegisterDisCover serviceRegisterDisCover = new LocalFileRegister(); 15 | 16 | private Class service; 17 | 18 | public String getServiceName() { 19 | return service.getName(); 20 | } 21 | 22 | public void setService(Class service) { 23 | this.service = service; 24 | } 25 | 26 | public Class getService() { 27 | return service; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/core/ConsumerInvoker.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.core; 2 | 3 | import thinkinjava.api.client.LuConsumerConfig; 4 | import thinkinjava.rpc.Request; 5 | import thinkinjava.rpc.Response; 6 | import thinkinjava.rpc.remoting.LuClient; 7 | 8 | /** 9 | * 10 | * @author 莫那·鲁道 11 | * @date 2018/10/14-下午10:28 12 | */ 13 | public class ConsumerInvoker implements Invoker { 14 | 15 | private LuClient client; 16 | private LuConsumerConfig luConsumerConfig; 17 | 18 | public ConsumerInvoker(LuConsumerConfig luConsumerConfig) { 19 | this.luConsumerConfig = luConsumerConfig; 20 | this.client = LuClient.create(); 21 | } 22 | 23 | public Response invoke(Request req) { 24 | preHandlerRequest(req); 25 | Response res = client.invoke(req); 26 | postHandlerResponse(res); 27 | return res; 28 | } 29 | 30 | public ServiceConfig getConfig() { 31 | return luConsumerConfig; 32 | } 33 | 34 | 35 | protected void preHandlerRequest(Request req) { 36 | } 37 | 38 | protected void postHandlerResponse(Response res) { 39 | 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/core/Invoker.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.core; 2 | 3 | import thinkinjava.rpc.Request; 4 | import thinkinjava.rpc.Response; 5 | 6 | /** 7 | * @author 莫那·鲁道 8 | * @date 2018/10/15-下午3:59 9 | */ 10 | public interface Invoker { 11 | 12 | /** 13 | * Remote Calls 14 | * @param req 请求: 会话域 15 | * @return 结果:包装真正结果. 16 | */ 17 | Response invoke(Request req) throws Throwable; 18 | 19 | /** 20 | * 获取该服务的配置 21 | * 22 | * @return 获取该服务的配置 23 | */ 24 | ServiceConfig getConfig(); 25 | } 26 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/core/ProviderInvoker.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.core; 2 | 3 | import java.lang.reflect.InvocationTargetException; 4 | 5 | import thinkinjava.api.server.LuProviderConfig; 6 | import thinkinjava.rpc.Request; 7 | import thinkinjava.rpc.Response; 8 | 9 | /** 10 | * 11 | * 12 | * @author 莫那·鲁道 13 | * @date 2018/10/16-下午7:41 14 | */ 15 | @SuppressWarnings("unchecked") 16 | public class ProviderInvoker implements Invoker { 17 | 18 | private Object realObj; 19 | private ServiceConfig config; 20 | 21 | public ProviderInvoker(Object realObj, LuProviderConfig config) { 22 | this.realObj = realObj; 23 | this.config = config; 24 | } 25 | 26 | public Response invoke(Request req) { 27 | try { 28 | return new Response(req.getMethod().invoke(realObj, req.getArgs())); 29 | } catch (IllegalAccessException e) { 30 | e.printStackTrace(); 31 | } catch (InvocationTargetException e) { 32 | e.printStackTrace(); 33 | } 34 | return null; 35 | } 36 | 37 | public ServiceConfig getConfig() { 38 | return config; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/core/ServiceConfig.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.core; 2 | 3 | import thinkinjava.rpc.remoting.Url; 4 | 5 | /** 6 | * 7 | * 服务配置类, 无论是客户端还是服务端, 通常需要接口名称, 设置接口类型, 以及接口 URL. 8 | * 9 | * @author 莫那·鲁道 10 | * @date 2018/10/15-下午4:23 11 | */ 12 | public interface ServiceConfig { 13 | 14 | String getServiceName(); 15 | 16 | void setService(Class service); 17 | 18 | Url getServiceUrl(); 19 | } 20 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/event/Event.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.event; 2 | 3 | /** 4 | */ 5 | public interface Event { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/event/EventBus.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.event; 2 | 3 | import java.util.concurrent.ConcurrentHashMap; 4 | import java.util.concurrent.CopyOnWriteArraySet; 5 | import java.util.concurrent.ThreadPoolExecutor; 6 | import java.util.concurrent.atomic.AtomicBoolean; 7 | 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | import thinkinjava.util.currence.LuThreadPoolFactory; 12 | 13 | 14 | /** 15 | * 事件总线. 16 | */ 17 | public class EventBus { 18 | 19 | private static final Logger LOGGER = LoggerFactory.getLogger(EventBus.class); 20 | 21 | private static final ConcurrentHashMap, CopyOnWriteArraySet> MAP = new ConcurrentHashMap<>(); 22 | 23 | private static final ThreadPoolExecutor EXECUTOR = LuThreadPoolFactory.getThreadPool(EventBus.class.getName()); 24 | 25 | private static final AtomicBoolean flag = new AtomicBoolean(); 26 | 27 | static { 28 | EXECUTOR.prestartAllCoreThreads(); 29 | } 30 | 31 | private EventBus() { 32 | } 33 | 34 | public static void destroy() { 35 | EXECUTOR.shutdown(); 36 | flag.compareAndSet(false, true); 37 | } 38 | 39 | /** 40 | * 发布事件. 41 | * @param event 事件. 42 | */ 43 | public static void post(Event event) { 44 | if (flag.get()) { 45 | LOGGER.warn("EventBus always destroy, can not to be post event !"); 46 | return; 47 | } 48 | if (event == null) { 49 | return; 50 | } 51 | CopyOnWriteArraySet set = MAP.get(event.getClass()); 52 | if (set == null) { 53 | return; 54 | } 55 | for (Subscriber subscribe : set) { 56 | if (subscribe.isSync()) { 57 | handleEvent(event, subscribe); 58 | } else { 59 | EXECUTOR.execute(new Runnable() { 60 | @Override 61 | public void run() { 62 | handleEvent(event, subscribe); 63 | } 64 | }); 65 | 66 | } 67 | 68 | } 69 | } 70 | 71 | 72 | /** 73 | * 订阅事件. 74 | * @param eventClass 事件类型. 75 | * @param subscriber 订阅者. 76 | */ 77 | public static void register(Class eventClass, Subscriber subscriber) { 78 | CopyOnWriteArraySet set = MAP.get(eventClass); 79 | if (set == null) { 80 | set = new CopyOnWriteArraySet<>(); 81 | CopyOnWriteArraySet old = MAP.putIfAbsent(eventClass, set); 82 | if (old != null) { 83 | set = old; 84 | } 85 | 86 | } 87 | set.add(subscriber); 88 | 89 | LOGGER.debug("subscriber : {} register a event: {} ", subscriber, eventClass); 90 | } 91 | 92 | /** 93 | * 取消订阅事件. 94 | * 95 | * @param eventClass 事件类型. 96 | * @param subscriber 订阅者. 97 | */ 98 | public static void unRegister(Class eventClass, Subscriber subscriber) { 99 | CopyOnWriteArraySet set = MAP.get(eventClass); 100 | if (set == null) { 101 | set = new CopyOnWriteArraySet<>(); 102 | CopyOnWriteArraySet old = MAP.putIfAbsent(eventClass, set); 103 | if (old != null) { 104 | set = old; 105 | } 106 | 107 | } 108 | set.remove(subscriber); 109 | LOGGER.debug("subscriber : {} unRegister a event: {} ", subscriber, eventClass); 110 | 111 | } 112 | 113 | 114 | /** 115 | * 处理事件. 116 | * @param event 事件. 117 | * @param subscriber 订阅者. 118 | */ 119 | private static void handleEvent(final Event event, final Subscriber subscriber) { 120 | try { 121 | subscriber.onEvent(event); 122 | } catch (Exception e) { 123 | LOGGER.error("subscriber {} handler event {} fail ", subscriber, event, e); 124 | } 125 | } 126 | 127 | } 128 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/event/Subscriber.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.event; 2 | 3 | /** 4 | * 5 | * 事件订阅者. 6 | */ 7 | public interface Subscriber { 8 | 9 | /** 10 | * 发生事件时回调此方法. 11 | * @param event 12 | */ 13 | void onEvent(Event event); 14 | 15 | /** 16 | * 同步处理还是异步处理, 注意: 同步处理将会影响框架吞吐量. 17 | * @return 18 | */ 19 | default boolean isSync() { 20 | return false; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/event/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @author 莫那·鲁道 4 | * @date 2019-01-26-11:04 5 | */ 6 | package thinkinjava.event; 7 | /** 8 | * 类似 guava 的 EventBus 设计, 通过机制解耦模块之间的耦合关系. 9 | * */ -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/exception/CircuitBreakerException.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.exception; 2 | 3 | /** 4 | * 5 | * 熔断异常. 通常不能算做熔断统计的数据依据. 6 | */ 7 | public class CircuitBreakerException extends RuntimeException { 8 | 9 | public CircuitBreakerException() { 10 | } 11 | 12 | public CircuitBreakerException(String message) { 13 | super(message); 14 | } 15 | 16 | public CircuitBreakerException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | 20 | public CircuitBreakerException(Throwable cause) { 21 | super(cause); 22 | } 23 | 24 | public CircuitBreakerException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { 25 | super(message, cause, enableSuppression, writableStackTrace); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/exception/FlowBufferAddException.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.exception; 2 | 3 | /** 4 | * 5 | * 流量缓冲区溢出. 6 | */ 7 | public class FlowBufferAddException extends RuntimeException { 8 | 9 | public FlowBufferAddException() { 10 | } 11 | 12 | public FlowBufferAddException(String message) { 13 | super(message); 14 | } 15 | 16 | public FlowBufferAddException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | 20 | public FlowBufferAddException(Throwable cause) { 21 | super(cause); 22 | } 23 | 24 | public FlowBufferAddException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { 25 | super(message, cause, enableSuppression, writableStackTrace); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/exception/LimitException.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.exception; 2 | 3 | /** 4 | * 5 | * 限流异常. 通常不能算做熔断统计的数据依据. 6 | */ 7 | public class LimitException extends RuntimeException { 8 | 9 | public LimitException() { 10 | } 11 | 12 | public LimitException(String message) { 13 | super(message); 14 | } 15 | 16 | public LimitException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | 20 | public LimitException(Throwable cause) { 21 | super(cause); 22 | } 23 | 24 | public LimitException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { 25 | super(message, cause, enableSuppression, writableStackTrace); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/exception/LuTimeoutException.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.exception; 2 | 3 | /** 4 | * 5 | * 超时异常. 6 | */ 7 | public class LuTimeoutException extends RuntimeException { 8 | 9 | 10 | public LuTimeoutException() { 11 | } 12 | 13 | public LuTimeoutException(String message) { 14 | super(message); 15 | } 16 | 17 | public LuTimeoutException(String message, Throwable cause) { 18 | super(message, cause); 19 | } 20 | 21 | public LuTimeoutException(Throwable cause) { 22 | super(cause); 23 | } 24 | 25 | public LuTimeoutException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { 26 | super(message, cause, enableSuppression, writableStackTrace); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/exception/UserOperationException.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.exception; 2 | 3 | /** 4 | * 5 | * 用户操作错误异常. 6 | * 7 | * @author 莫那·鲁道 8 | * @date 2019-01-26-12:20 9 | */ 10 | public class UserOperationException extends RuntimeException { 11 | 12 | public UserOperationException() { 13 | } 14 | 15 | public UserOperationException(String message) { 16 | super(message); 17 | } 18 | 19 | public UserOperationException(String message, Throwable cause) { 20 | super(message, cause); 21 | } 22 | 23 | public UserOperationException(Throwable cause) { 24 | super(cause); 25 | } 26 | 27 | public UserOperationException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { 28 | super(message, cause, enableSuppression, writableStackTrace); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/filter/ExampleFilter.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.filter; 2 | 3 | import thinkinjava.core.Invoker; 4 | import thinkinjava.rpc.Request; 5 | import thinkinjava.rpc.Response; 6 | 7 | /** 8 | * @author 莫那·鲁道 9 | * @date 2018/10/14-下午10:04 10 | */ 11 | public class ExampleFilter implements Filter { 12 | 13 | @Override 14 | public Response filter(Invoker invoker, Request req) throws Throwable { 15 | if (req == null) { 16 | throw new IllegalArgumentException("req not be null"); 17 | } 18 | System.out.println("ExampleFilter "); 19 | return invoker.invoke(req); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/filter/ExampleFilter2.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.filter; 2 | 3 | import thinkinjava.core.Invoker; 4 | import thinkinjava.rpc.Request; 5 | import thinkinjava.rpc.Response; 6 | 7 | /** 8 | * @author 莫那·鲁道 9 | * @date 2018/10/14-下午10:04 10 | */ 11 | public class ExampleFilter2 implements Filter { 12 | 13 | @Override 14 | public Response filter(Invoker invoker, Request req) throws Throwable { 15 | if (req == null) { 16 | throw new IllegalArgumentException("req not be null"); 17 | } 18 | System.out.println("ExampleFilter 2 "); 19 | return invoker.invoke(req); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/filter/Filter.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.filter; 2 | 3 | import thinkinjava.core.Invoker; 4 | import thinkinjava.rpc.Request; 5 | import thinkinjava.rpc.Response; 6 | 7 | /** 8 | * @author 莫那·鲁道 9 | * @date 2018/10/14-下午10:02 10 | */ 11 | public interface Filter { 12 | 13 | /** 14 | * 过滤器设计 15 | * @param invoker 16 | * @param req 17 | * @return 18 | */ 19 | Response filter(Invoker invoker, Request req) throws Throwable; 20 | } 21 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/filter/FilterChain.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.filter; 2 | 3 | import java.util.List; 4 | 5 | import thinkinjava.core.Invoker; 6 | 7 | /** 8 | * 9 | * 10 | * @author 莫那·鲁道 11 | * @date 2018/10/14-下午10:02 12 | */ 13 | public class FilterChain { 14 | 15 | private List filters; 16 | 17 | private Invoker invoker; 18 | 19 | 20 | public FilterChain(List filters, Invoker invoker) { 21 | this.filters = filters; 22 | this.invoker = invoker; 23 | } 24 | 25 | public FilterChain(Invoker invoker) { 26 | this(LoadFilters.create().getFilters(), invoker); 27 | } 28 | 29 | public Invoker buildFilterChain() { 30 | // 最后一个 31 | Invoker last = invoker; 32 | 33 | for (int i = filters.size() - 1; i >= 0; i--) { 34 | last = new FilterWrapper(filters.get(i), last); 35 | } 36 | // 第一个 37 | return last; 38 | 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/filter/FilterWrapper.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.filter; 2 | 3 | import thinkinjava.core.Invoker; 4 | import thinkinjava.core.ServiceConfig; 5 | import thinkinjava.rpc.Request; 6 | import thinkinjava.rpc.Response; 7 | 8 | /** 9 | * @author 莫那·鲁道 10 | * @date 2018/10/16-下午5:01 11 | */ 12 | public class FilterWrapper implements Invoker { 13 | 14 | private Filter next; 15 | 16 | private Invoker invoker; 17 | 18 | private ServiceConfig config; 19 | 20 | public FilterWrapper(Filter next, Invoker invoker) { 21 | this.next = next; 22 | this.invoker = invoker; 23 | this.config = invoker.getConfig(); 24 | } 25 | 26 | 27 | @Override 28 | public Response invoke(Request args) throws Throwable { 29 | if (next != null) { 30 | return next.filter(invoker, args); 31 | } else { 32 | return invoker.invoke(args); 33 | } 34 | } 35 | 36 | public ServiceConfig getConfig() { 37 | return config; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/filter/LoadFilters.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.filter; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import thinkinjava.breaker.CircuitBreakerFilter; 7 | import thinkinjava.breaker.CircuitBreakerStatFilter; 8 | import thinkinjava.flow.limit.LimitFilter; 9 | 10 | /** 11 | * TODO 自动加载过滤器 12 | * 13 | * @author 莫那·鲁道 14 | * @date 2018/10/14-下午10:43 15 | */ 16 | public final class LoadFilters { 17 | 18 | private List filterList = new ArrayList(); 19 | 20 | private LoadFilters() { 21 | } 22 | 23 | public static LoadFilters create() { 24 | 25 | return new LoadFilters(); 26 | } 27 | 28 | public List getFilters() { 29 | this.filterList.add(new ExampleFilter()); 30 | this.filterList.add(new ExampleFilter2()); 31 | this.filterList.add(CircuitBreakerFilter.getInstance()); 32 | this.filterList.add(LimitFilter.getInstance()); 33 | this.filterList.add(CircuitBreakerStatFilter.getInstance()); 34 | return filterList; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/filter/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @author 莫那·鲁道 4 | * @date 2019-01-26-11:07 5 | */ 6 | package thinkinjava.filter; 7 | 8 | /** 9 | * RPC 框架过滤器, 使用责任链模式, 解耦组件之间的关系. 使用链表设计,可动态修改顺序. 10 | * */ -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/flow/limit/FlowBufferManager.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.flow.limit; 2 | 3 | import java.util.concurrent.ConcurrentHashMap; 4 | 5 | import thinkinjava.util.currence.FlowBuffer; 6 | 7 | public class FlowBufferManager { 8 | 9 | private ConcurrentHashMap cache = new ConcurrentHashMap<>(); 10 | 11 | 12 | public static FlowBufferManager getInstance() { 13 | return FlowBufferManagerInner.INSTANCE; 14 | } 15 | 16 | private FlowBufferManager() { 17 | } 18 | 19 | private static class FlowBufferManagerInner { 20 | 21 | private static final FlowBufferManager INSTANCE = new FlowBufferManager(); 22 | } 23 | 24 | /** 25 | * 获取 Buffer 26 | * @param unique .. 27 | * @return PairFlowBuffer 28 | */ 29 | public FlowBuffer getBuffer(String unique) { 30 | FlowBuffer buffer = cache.get(unique); 31 | if (buffer == null) { 32 | buffer = FlowBuffer.newBuilder().unique(unique).build(); 33 | FlowBuffer old = cache.putIfAbsent(unique, buffer); 34 | if (old != null) { 35 | buffer = old; 36 | } 37 | } 38 | return buffer; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/flow/limit/LimitEvent.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.flow.limit; 2 | 3 | import java.util.Date; 4 | 5 | import thinkinjava.event.Event; 6 | 7 | /** 8 | * 9 | * 限流异常导致的限流事件. 10 | */ 11 | public class LimitEvent implements Event { 12 | 13 | /** 限流时间 */ 14 | private Date date; 15 | 16 | 17 | private LimitEvent(Builder builder) { 18 | setDate(builder.date); 19 | } 20 | 21 | public static Builder newBuilder() { 22 | return new Builder(); 23 | } 24 | 25 | public Date getDate() { 26 | return date; 27 | } 28 | 29 | public void setDate(Date date) { 30 | this.date = date; 31 | } 32 | 33 | 34 | 35 | public static final class Builder { 36 | 37 | private boolean syncRequest; 38 | private Date date; 39 | 40 | private Builder() { 41 | } 42 | 43 | 44 | public Builder syncRequest(boolean val) { 45 | syncRequest = val; 46 | return this; 47 | } 48 | 49 | public Builder date(Date val) { 50 | date = val; 51 | return this; 52 | } 53 | 54 | public LimitEvent build() { 55 | return new LimitEvent(this); 56 | } 57 | } 58 | } 59 | 60 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/flow/limit/LimitFilter.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.flow.limit; 2 | 3 | import java.util.Date; 4 | 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import thinkinjava.core.Invoker; 9 | import thinkinjava.event.EventBus; 10 | import thinkinjava.exception.FlowBufferAddException; 11 | import thinkinjava.exception.LimitException; 12 | import thinkinjava.exception.LuTimeoutException; 13 | import thinkinjava.filter.Filter; 14 | import thinkinjava.rpc.Request; 15 | import thinkinjava.rpc.Response; 16 | import thinkinjava.util.currence.FlowBuffer; 17 | import thinkinjava.util.currence.Semaphore; 18 | 19 | 20 | /** 21 | * 限流过滤器. 22 | */ 23 | public class LimitFilter implements Filter { 24 | 25 | private static final Logger LOGGER = LoggerFactory.getLogger(LimitFilter.class); 26 | 27 | 28 | private static final int RETRY_COUNT = 1; 29 | 30 | private LimitFilter() { 31 | } 32 | 33 | public static LimitFilter getInstance() { 34 | return LimitFilterLazyHolder.INSTANCE; 35 | } 36 | 37 | private static class LimitFilterLazyHolder { 38 | 39 | private static final LimitFilter INSTANCE = new LimitFilter(); 40 | } 41 | 42 | 43 | @Override 44 | public Response filter(Invoker invoker, Request request) throws Throwable { 45 | 46 | LOGGER.info("LimitFilter filtering"); 47 | 48 | String unique = request.getUnique(); 49 | 50 | Semaphore semaphore = SemaphoreManager.getInstance().getSemaphore(unique); 51 | 52 | int count = 0; 53 | loop: 54 | for (; ; ) { 55 | 56 | FlowBuffer flowBuffer = FlowBufferManager.getInstance().getBuffer(unique); 57 | if (semaphore.tryAcquire()) { 58 | try { 59 | // 这里不处理异常, 直接抛出. 60 | return invoker.invoke(request); 61 | } finally { 62 | semaphore.release(); 63 | flowBuffer.notifyBuffer(); 64 | } 65 | } // 抢信号量失败 66 | else { 67 | try { 68 | // 仅仅等待一次 69 | if (++count <= RETRY_COUNT) { 70 | // 进入队列可能会失败, 也可能会等待超时. 我们都认为是限流异常. 71 | flowBuffer.addBufferAndWait(); 72 | // 唤醒后, 再次重新尝试获取信号量. 73 | continue loop; 74 | } 75 | break; 76 | } catch (LuTimeoutException | FlowBufferAddException e) { 77 | // 忽略, 认为是限流异常. 78 | } 79 | 80 | } 81 | } 82 | // 限流事件 83 | EventBus.post(LimitEvent.newBuilder().date(new Date()).build()); 84 | 85 | return throwsException(); 86 | } 87 | 88 | 89 | private Response throwsException() { 90 | throw new LimitException(); 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/flow/limit/SemaphoreManager.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.flow.limit; 2 | 3 | import java.util.concurrent.ConcurrentHashMap; 4 | 5 | import thinkinjava.util.currence.Semaphore; 6 | 7 | public class SemaphoreManager{ 8 | 9 | private ConcurrentHashMap map = new ConcurrentHashMap<>(); 10 | 11 | private SemaphoreManager(){} 12 | 13 | public static SemaphoreManager getInstance() { 14 | return SemaphoreManagerLazyHolder.INSTANCE; 15 | } 16 | 17 | private static class SemaphoreManagerLazyHolder { 18 | 19 | private static final SemaphoreManager INSTANCE = new SemaphoreManager(); 20 | } 21 | 22 | public void putSemaphore(String unique, Semaphore semaphore) { 23 | map.put(unique, semaphore); 24 | } 25 | 26 | public Semaphore getSemaphore(String unique) { 27 | Semaphore semaphore = map.get(unique); 28 | if (semaphore == null) { 29 | semaphore = new Semaphore(unique, 10); 30 | Semaphore old = map.putIfAbsent(unique, semaphore); 31 | if (old != null) { 32 | semaphore = old; 33 | } 34 | } 35 | return semaphore; 36 | } 37 | 38 | 39 | 40 | 41 | } 42 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/flow/limit/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @author 莫那·鲁道 4 | * @date 2019-01-26-11:08 5 | */ 6 | package thinkinjava.flow.limit; 7 | /** 8 | * 限流模块, 利用了 EventBus 和 Filter, 实现限流, 目前设计了缓存区. 即限流后,会被加入到一个限时缓存区. 9 | * */ -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/proxy/ConsumerInterceptor.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.proxy; 2 | 3 | import java.lang.reflect.InvocationHandler; 4 | import java.lang.reflect.Method; 5 | 6 | import thinkinjava.core.Invoker; 7 | import thinkinjava.filter.FilterChain; 8 | import thinkinjava.rpc.Request; 9 | import thinkinjava.rpc.Response; 10 | 11 | /** 12 | * 13 | * @author 莫那·鲁道 14 | * @date 2018/10/14-下午9:59 15 | */ 16 | public class ConsumerInterceptor implements InvocationHandler { 17 | 18 | private Invoker invoker; 19 | 20 | private FilterChain chain; 21 | 22 | public ConsumerInterceptor(Invoker invoker) { 23 | // 过滤器链,链尾是真正的 invoker 24 | this.chain = new FilterChain(invoker); 25 | this.invoker = this.chain.buildFilterChain(); 26 | } 27 | 28 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 29 | 30 | // 构造请求体 31 | Request req = buildRequest(method, args); 32 | 33 | // 2. 调用过滤器链 34 | Response res = invoker.invoke(req); 35 | return res.getResult(); 36 | } 37 | 38 | /** 39 | * 构造请求体 40 | */ 41 | private Request buildRequest(Method method, Object[] args) { 42 | Request req = new Request(); 43 | req.setServiceName(invoker.getConfig().getServiceName()); 44 | req.setArgs(args); 45 | req.setMethodName(method.getName()); 46 | req.setIp(invoker.getConfig().getServiceUrl().getIp()); 47 | req.setPort(invoker.getConfig().getServiceUrl().getPort()); 48 | req.setArgTypes(method.getParameterTypes()); 49 | 50 | return req; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/proxy/ProviderInterceptor.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.proxy; 2 | 3 | import java.lang.reflect.InvocationHandler; 4 | import java.lang.reflect.Method; 5 | 6 | import thinkinjava.core.Invoker; 7 | import thinkinjava.filter.FilterChain; 8 | import thinkinjava.rpc.Request; 9 | import thinkinjava.rpc.Response; 10 | 11 | /** 12 | * 13 | * @author 莫那·鲁道 14 | * @date 2018/10/14-下午9:59 15 | */ 16 | public class ProviderInterceptor implements InvocationHandler { 17 | 18 | private Invoker invoker; 19 | 20 | private FilterChain chain; 21 | 22 | public ProviderInterceptor(Invoker invoker) { 23 | // 过滤器链,链尾是真正的 invoker 24 | this.chain = new FilterChain(invoker); 25 | this.invoker = this.chain.buildFilterChain(); 26 | } 27 | 28 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 29 | 30 | // 构造请求体 31 | Request req = buildRequest(method, args); 32 | 33 | // 2. 调用过滤器链 34 | Response res = invoker.invoke(req); 35 | return res.getResult(); 36 | } 37 | 38 | /** 39 | * 构造请求体 40 | */ 41 | private Request buildRequest(Method method, Object[] args) { 42 | Request req = new Request(); 43 | req.setServiceName(invoker.getConfig().getServiceName()); 44 | req.setArgs(args); 45 | req.setMethodName(method.getName()); 46 | req.setIp(invoker.getConfig().getServiceUrl().getIp()); 47 | req.setPort(invoker.getConfig().getServiceUrl().getPort()); 48 | req.setArgTypes(method.getParameterTypes()); 49 | req.setMethod(method); 50 | 51 | return req; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/proxy/ProxyFactory.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.proxy; 2 | 3 | import java.lang.reflect.InvocationHandler; 4 | import java.lang.reflect.Proxy; 5 | 6 | /** 7 | * 8 | * 9 | * @author 莫那·鲁道 10 | * @date 2018/10/14-下午9:59 11 | */ 12 | public class ProxyFactory { 13 | 14 | public static Object getProxy(Class origin, InvocationHandler h) { 15 | return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{origin}, 16 | h); 17 | } 18 | 19 | 20 | 21 | 22 | } 23 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/proxy/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @author 莫那·鲁道 4 | * @date 2019-01-26-11:14 5 | */ 6 | package thinkinjava.proxy; 7 | 8 | /** 9 | * 动态代理相关, 例如代理类生成工厂, 消费者拦截器, 提供者拦截器. 10 | * */ -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/rpc/Request.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.rpc; 2 | 3 | import java.io.Serializable; 4 | import java.lang.reflect.Method; 5 | 6 | /** 7 | * @author 莫那·鲁道 8 | * @date 2018/10/14-下午9:39 9 | */ 10 | public class Request implements Serializable { 11 | 12 | private String serviceName; 13 | 14 | private String className; 15 | 16 | private String methodName; 17 | 18 | private Method method; 19 | 20 | private Object[] args; 21 | 22 | private Class[] argTypes; 23 | 24 | private String ip; 25 | 26 | private int port; 27 | 28 | public String getServiceName() { 29 | return serviceName; 30 | } 31 | 32 | public void setServiceName(String serviceName) { 33 | this.serviceName = serviceName; 34 | } 35 | 36 | public String getMethodName() { 37 | return methodName; 38 | } 39 | 40 | public void setMethodName(String methodName) { 41 | this.methodName = methodName; 42 | } 43 | 44 | public String getClassName() { 45 | return className; 46 | } 47 | 48 | public void setClassName(String className) { 49 | this.className = className; 50 | } 51 | 52 | public Object[] getArgs() { 53 | return args; 54 | } 55 | 56 | public void setArgs(Object[] args) { 57 | this.args = args; 58 | } 59 | 60 | public Method getMethod() { 61 | return method; 62 | } 63 | 64 | public void setMethod(Method method) { 65 | this.method = method; 66 | } 67 | 68 | public Class[] getArgTypes() { 69 | return argTypes; 70 | } 71 | 72 | public void setArgTypes(Class[] argTypes) { 73 | this.argTypes = argTypes; 74 | } 75 | 76 | public String getIp() { 77 | return ip; 78 | } 79 | 80 | public void setIp(String ip) { 81 | this.ip = ip; 82 | } 83 | 84 | public int getPort() { 85 | return port; 86 | } 87 | 88 | public String getUrl() { 89 | return ip + ":" + port; 90 | } 91 | 92 | public void setUrl(String url) { 93 | if (url != null) { 94 | String[] arr = url.split(":"); 95 | ip = arr[0]; 96 | port = Integer.valueOf(arr[1]); 97 | } 98 | } 99 | 100 | public void setPort(int port) { 101 | this.port = port; 102 | } 103 | 104 | public String getUnique() { 105 | return ip + ":" + port + "$" + serviceName; 106 | } 107 | 108 | 109 | } 110 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/rpc/Response.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.rpc; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * 7 | * @author 莫那·鲁道 8 | * @date 2018/10/14-下午9:39 9 | */ 10 | public class Response implements Serializable { 11 | 12 | private Object result; 13 | 14 | public Response(Object result) { 15 | this.result = result; 16 | } 17 | 18 | public Object getResult() { 19 | return result; 20 | } 21 | 22 | public void setResult(Object result) { 23 | this.result = result; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/rpc/remoting/LuClient.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.rpc.remoting; 2 | 3 | import com.alipay.remoting.exception.RemotingException; 4 | import com.alipay.remoting.rpc.RpcClient; 5 | 6 | import thinkinjava.rpc.Request; 7 | import thinkinjava.rpc.Response; 8 | 9 | /** 10 | * @author 莫那·鲁道 11 | * @date 2018/10/14-下午8:38 12 | */ 13 | public class LuClient { 14 | 15 | private final static RpcClient client = new RpcClient(); 16 | static { 17 | client.init(); 18 | } 19 | 20 | public static LuClient create() { 21 | return new LuClient(); 22 | } 23 | 24 | private LuClient() { 25 | } 26 | 27 | public Response invoke(Request req) { 28 | try { 29 | 30 | Object result = client.invokeSync(req.getUrl(), req, 2000); 31 | return new Response(result); 32 | 33 | } catch (RemotingException e) { 34 | e.printStackTrace(); 35 | } catch (InterruptedException e) { 36 | e.printStackTrace(); 37 | } 38 | throw new RuntimeException("invoke error"); 39 | } 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/rpc/remoting/LuServer.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.rpc.remoting; 2 | 3 | import com.alipay.remoting.rpc.RpcServer; 4 | import com.alipay.remoting.rpc.protocol.UserProcessor; 5 | 6 | /** 7 | * 8 | * @author 莫那·鲁道 9 | * @date 2018/10/14-下午8:49 10 | */ 11 | public class LuServer { 12 | 13 | private static RpcServer rpcServer; 14 | 15 | private volatile boolean flag; 16 | 17 | public static LuServer create(int port) { 18 | return new LuServer("127.0.0.1", port, false); 19 | } 20 | 21 | LuServer(String ip, int port, boolean manageConnection) { 22 | rpcServer = new RpcServer(ip, port, manageConnection); 23 | rpcServer.registerUserProcessor(new LuUserProcessor()); 24 | } 25 | 26 | public void start() { 27 | if (flag) { 28 | return; 29 | } 30 | rpcServer.start(); 31 | flag = true; 32 | } 33 | 34 | public void stop() { 35 | rpcServer.stop(); 36 | } 37 | 38 | public RpcServer getServer() { 39 | return rpcServer; 40 | } 41 | 42 | public void registerUserProcessor(UserProcessor userProcessor) { 43 | rpcServer.registerUserProcessor(userProcessor); 44 | } 45 | 46 | 47 | } 48 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/rpc/remoting/LuUserProcessor.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.rpc.remoting; 2 | 3 | import java.lang.reflect.Method; 4 | import java.util.Map; 5 | import java.util.concurrent.ConcurrentHashMap; 6 | 7 | import com.alipay.remoting.AsyncContext; 8 | import com.alipay.remoting.BizContext; 9 | import com.alipay.remoting.rpc.protocol.AbstractUserProcessor; 10 | 11 | import thinkinjava.api.server.LuProvider; 12 | import thinkinjava.api.server.ProviderManager; 13 | import thinkinjava.rpc.Request; 14 | 15 | /** 16 | * 17 | * 18 | * @author 莫那·鲁道 19 | * @date 2018/10/14-下午8:56 20 | */ 21 | @SuppressWarnings("unchecked") 22 | public class LuUserProcessor extends AbstractUserProcessor { 23 | 24 | /** Just for Test */ 25 | public static Map methods = new ConcurrentHashMap(); 26 | /** Just for Test */ 27 | public static Map targets = new ConcurrentHashMap(); 28 | 29 | 30 | public LuUserProcessor() { 31 | } 32 | 33 | public void handleRequest(BizContext bizCtx, AsyncContext asyncCtx, Request request) { 34 | // NOOP 35 | } 36 | 37 | public Object handleRequest(BizContext bizCtx, Request request) throws Exception { 38 | LuProvider provider = ProviderManager.getProvider(request.getServiceName()); 39 | request.setMethod(provider.getConfig().getService().getDeclaredMethod(request.getMethodName(), request.getArgTypes())); 40 | 41 | return request.getMethod().invoke(provider.getConfig().getRefProxy(), request.getArgs()); 42 | } 43 | 44 | 45 | /** 46 | * 用户请求的类名。 47 | * 使用String类型来避免类加载器问题。 48 | */ 49 | public String interest() { 50 | return Request.class.getName(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/rpc/remoting/Url.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.rpc.remoting; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * 7 | * 8 | * @author 莫那·鲁道 9 | * @date 2018/10/16-下午6:08 10 | */ 11 | public class Url implements Serializable { 12 | 13 | public static Url DEFAULT = new Url(); 14 | 15 | String ip = "127.0.0.1"; 16 | 17 | int port = 8081; 18 | 19 | String password = "helloWorld"; 20 | 21 | String token = "LoDao"; 22 | 23 | public Url() { 24 | } 25 | 26 | public Url(String ip, int port) { 27 | this.ip = ip; 28 | this.port = port; 29 | } 30 | 31 | public Url(int port) { 32 | this.port = port; 33 | } 34 | 35 | public String getIp() { 36 | return ip; 37 | } 38 | 39 | public void setIp(String ip) { 40 | this.ip = ip; 41 | } 42 | 43 | public int getPort() { 44 | return port; 45 | } 46 | 47 | public void setPort(int port) { 48 | this.port = port; 49 | } 50 | 51 | public String getPassword() { 52 | return password; 53 | } 54 | 55 | public void setPassword(String password) { 56 | this.password = password; 57 | } 58 | 59 | public String getToken() { 60 | return token; 61 | } 62 | 63 | public void setToken(String token) { 64 | this.token = token; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/util/CloseUtil.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.util; 2 | 3 | import java.io.Closeable; 4 | import java.io.IOException; 5 | 6 | /** 7 | * 简化 Java 里繁琐的 close. 8 | * 9 | * @author 莫那·鲁道 10 | * @date 2018/10/15-上午7:06 11 | */ 12 | public class CloseUtil { 13 | 14 | public static void close(Closeable closeable) { 15 | try { 16 | if (closeable != null) { 17 | closeable.close(); 18 | } 19 | } catch (IOException e) { 20 | e.printStackTrace(); 21 | } 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/util/SimpleDateFormatUtil.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.util; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.Date; 5 | 6 | /** 7 | * 8 | * 支持 3 种格式 9 | * 1. yyyy-MM-dd HH:mm:ss:sss 10 | * 2. yyyy-MM-dd HH:mm:ss 11 | * 3. yyyy-MM-dd HH:mm 12 | */ 13 | public class SimpleDateFormatUtil { 14 | 15 | /** 16 | * 使用 ThreadLocal 包装 SimpleDateFormat,防止并发问题, 相比较每次 new 节约资源, 加快速度. 17 | */ 18 | private final static ThreadLocal simpleDateFormat1 = new ThreadLocal() { 19 | @Override 20 | protected SimpleDateFormat initialValue() { 21 | return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:sss"); 22 | } 23 | }; 24 | 25 | private final static ThreadLocal simpleDateFormat2 = new ThreadLocal() { 26 | @Override 27 | protected SimpleDateFormat initialValue() { 28 | return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 29 | } 30 | }; 31 | 32 | private final static ThreadLocal simpleDateFormat3 = new ThreadLocal() { 33 | @Override 34 | protected SimpleDateFormat initialValue() { 35 | return new SimpleDateFormat("yyyy-MM-dd HH:mm"); 36 | } 37 | }; 38 | 39 | public static String format1(Date date) { 40 | return simpleDateFormat1.get().format(date); 41 | } 42 | 43 | public static String format2(Date date) { 44 | return simpleDateFormat2.get().format(date); 45 | } 46 | 47 | public static String format3(Date date) { 48 | return simpleDateFormat3.get().format(date); 49 | } 50 | 51 | 52 | } 53 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/util/currence/ChannelType.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.util.currence; 2 | 3 | /** 4 | * 用于细化流量类型, 即:将一个通道的流量分成 2 种类型, 可动态调控通道大小,达到细化流量分配. 5 | * 6 | * 使用场景: 同一个接口, 有 VIP 用户和普通用户, 不能让普通用户的流量占满流量通道,无论如何也要分出部分流量给 VIP 用户. 7 | */ 8 | public enum ChannelType { 9 | 10 | SYNC("sync", 0), ASYNC("async", 1); 11 | 12 | String name; 13 | int code; 14 | 15 | ChannelType(String name, int code) { 16 | this.name = name; 17 | this.code = code; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/util/currence/FlowBuffer.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.util.currence; 2 | 3 | import java.util.concurrent.ConcurrentLinkedQueue; 4 | import java.util.concurrent.TimeUnit; 5 | import java.util.concurrent.atomic.AtomicInteger; 6 | import java.util.concurrent.atomic.AtomicLong; 7 | import java.util.concurrent.atomic.AtomicReference; 8 | import java.util.concurrent.locks.LockSupport; 9 | 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | import thinkinjava.breaker.TimeWindow; 14 | import thinkinjava.conf.DynamicProperties; 15 | import thinkinjava.conf.DynamicProperty; 16 | import thinkinjava.conf.Plugins; 17 | import thinkinjava.exception.FlowBufferAddException; 18 | import thinkinjava.exception.LuTimeoutException; 19 | 20 | import static thinkinjava.conf.Constant.DEFAULT_FLOW_BUFFER_QUEUE_MAX_SIZE; 21 | import static thinkinjava.conf.Constant.DEFAULT_FLOW_BUFFER_WAIT_TIME_OUT; 22 | import static thinkinjava.conf.Constant.FLOW_BUFFER_QUEUE_MAX_SIZE; 23 | import static thinkinjava.conf.Constant.FLOW_BUFFER_WAIT_TIME_OUT; 24 | import static thinkinjava.util.currence.FlowBuffer.State.BLOCK; 25 | import static thinkinjava.util.currence.FlowBuffer.State.RELEASE_BY_OTHER; 26 | import static thinkinjava.util.currence.FlowBuffer.State.RELEASE_BY_SELF; 27 | 28 | 29 | /** 30 | * 31 | * 流量缓冲带. 32 | * 33 | * 该组件用于应对突发流量导致的毛刺. 当流量过大,就会将请求贮存在队列中(timeout), 当有空闲资源时, 就会唤醒请求线程. 34 | */ 35 | public class FlowBuffer { 36 | 37 | private static final Logger LOGGER = LoggerFactory.getLogger(FlowBuffer.class); 38 | 39 | private String unique; 40 | 41 | /** 通道类型. */ 42 | private ChannelType channelType; 43 | 44 | public ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue<>(); 45 | 46 | /** 47 | * 队列当前的大小. 48 | */ 49 | private AtomicInteger currentSize = new AtomicInteger(); 50 | 51 | /** 52 | * 时间窗口内, 进入缓冲区的请求数. 53 | */ 54 | private TimeWindow window = new TimeWindow(10); 55 | 56 | /** 57 | * 进入队列的总请求数, 用于调优. 58 | */ 59 | private AtomicLong record = new AtomicLong(); 60 | 61 | private DynamicProperties properties = Plugins.getInstance().getDynamicProperties(); 62 | 63 | private DynamicProperty bufferMaxSize_ = properties.getInteger(FLOW_BUFFER_QUEUE_MAX_SIZE, DEFAULT_FLOW_BUFFER_QUEUE_MAX_SIZE); 64 | private volatile int bufferMaxSize = bufferMaxSize_.get(); 65 | 66 | private DynamicProperty waitTime_ = properties.getLong(FLOW_BUFFER_WAIT_TIME_OUT, DEFAULT_FLOW_BUFFER_WAIT_TIME_OUT); 67 | private volatile long waitTime = waitTime_.get(); 68 | 69 | private FlowBuffer(Builder builder) { 70 | unique = builder.unique; 71 | channelType = builder.channelType; 72 | 73 | bufferMaxSize_.addCallback(() -> bufferMaxSize = bufferMaxSize_.get()); 74 | waitTime_.addCallback(() -> waitTime = waitTime_.get()); 75 | } 76 | 77 | public static Builder newBuilder() { 78 | return new Builder(); 79 | } 80 | 81 | /** 82 | * 将当前请求加入缓冲区并等待. 83 | */ 84 | public void addBufferAndWait() throws LuTimeoutException, FlowBufferAddException { 85 | Node node = new Node(Thread.currentThread(), BLOCK); 86 | 87 | if (currentSize.get() > bufferMaxSize) { 88 | throw new FlowBufferAddException("FlowBuffer Queue Full, Queue Size : " + bufferMaxSize); 89 | } 90 | 91 | boolean result = queue.offer(node); 92 | currentSize.incrementAndGet(); 93 | record.incrementAndGet(); 94 | window.getCurrentWindow().addTotal(); 95 | 96 | if (result) { 97 | LockSupport.parkNanos(Thread.currentThread(), TimeUnit.MILLISECONDS.toNanos(waitTime)); 98 | // 自己超时了, 释放一个空间. 99 | if (node.flag.compareAndSet(BLOCK, RELEASE_BY_SELF) && (currentSize.decrementAndGet() != -1)) { 100 | throw new LuTimeoutException("this request on Flow Buffer timeout, timeout time : " + waitTime + 101 | ", unique : " + unique + ", channelType : " + channelType + ", bufferMaxSize : " + bufferMaxSize 102 | + ", currentSize : " + currentSize.get()); 103 | } 104 | 105 | } else { 106 | throw new FlowBufferAddException("offer FlowBuffer Queue Fail"); 107 | } 108 | } 109 | 110 | /** 111 | * 唤醒缓冲区请求(顺手清理队列里超时的请求). 112 | */ 113 | public void notifyBuffer() { 114 | Node node; 115 | // 条件不能变序 116 | while ((node = queue.poll()) != null && node.flag.compareAndSet(BLOCK, RELEASE_BY_OTHER)) { 117 | 118 | currentSize.decrementAndGet(); 119 | 120 | LockSupport.unpark(node.currentThread); 121 | break; 122 | } 123 | } 124 | 125 | 126 | public enum State { 127 | /** 阻塞中 */ 128 | BLOCK, 129 | /** 被别人唤醒. */ 130 | RELEASE_BY_OTHER, 131 | /** 被自己唤醒. */ 132 | RELEASE_BY_SELF 133 | } 134 | 135 | 136 | public static class Node { 137 | 138 | volatile Thread currentThread; 139 | final AtomicReference flag; 140 | 141 | public Node(Thread currentThread, State flag) { 142 | this.currentThread = currentThread; 143 | this.flag = new AtomicReference<>(flag); 144 | } 145 | } 146 | 147 | public static final class Builder { 148 | 149 | String unique; 150 | private ChannelType channelType; 151 | 152 | private Builder() { 153 | } 154 | 155 | 156 | public FlowBuffer build() { 157 | return new FlowBuffer(this); 158 | } 159 | 160 | public Builder unique(String val) { 161 | unique = val; 162 | return this; 163 | } 164 | 165 | public Builder channelType(ChannelType val) { 166 | channelType = val; 167 | return this; 168 | } 169 | } 170 | 171 | 172 | } 173 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/util/currence/LuRejectedExecutionHandler.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.util.currence; 2 | 3 | import java.util.concurrent.RejectedExecutionHandler; 4 | import java.util.concurrent.ThreadPoolExecutor; 5 | 6 | /** 7 | * 8 | * @author 莫那·鲁道 9 | * @date 2018-12-15-10:36 10 | */ 11 | public class LuRejectedExecutionHandler implements RejectedExecutionHandler { 12 | 13 | @Override 14 | public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/util/currence/LuThreadFactory.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.util.currence; 2 | 3 | import java.util.concurrent.ThreadFactory; 4 | 5 | /** 6 | * 7 | * @author 莫那·鲁道 8 | * @date 2018-12-15-10:36 9 | */ 10 | public class LuThreadFactory implements ThreadFactory { 11 | 12 | private String name; 13 | 14 | public LuThreadFactory(String name) { 15 | this.name = name; 16 | } 17 | 18 | @Override 19 | public Thread newThread(Runnable r) { 20 | return null; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/util/currence/LuThreadPool.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.util.currence; 2 | 3 | import java.util.concurrent.BlockingQueue; 4 | import java.util.concurrent.ThreadPoolExecutor; 5 | import java.util.concurrent.TimeUnit; 6 | 7 | /** 8 | * 9 | * @author 莫那·鲁道 10 | * @date 2018-12-15-10:37 11 | */ 12 | public class LuThreadPool extends ThreadPoolExecutor { 13 | 14 | public LuThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, 15 | BlockingQueue workQueue, LuThreadFactory luThreadFactory, 16 | LuRejectedExecutionHandler luRejectedExecutionHandler) { 17 | super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); 18 | } 19 | 20 | 21 | } 22 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/util/currence/LuThreadPoolFactory.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.util.currence; 2 | 3 | import java.util.concurrent.LinkedBlockingQueue; 4 | import java.util.concurrent.ThreadPoolExecutor; 5 | import java.util.concurrent.TimeUnit; 6 | 7 | /** 8 | * 9 | * @author 莫那·鲁道 10 | * @date 2018-12-15-10:33 11 | */ 12 | public class LuThreadPoolFactory { 13 | 14 | private static int cpu = Runtime.getRuntime().availableProcessors(); 15 | private static long keepAlive = 60 * 1000; 16 | private static TimeUnit unit = TimeUnit.MILLISECONDS; 17 | private static int queueSize = 1024; 18 | private static String name = "default-lu-rpc-threadPool"; 19 | 20 | public static ThreadPoolExecutor getThreadPool(int core, String name) { 21 | return new LuThreadPool( 22 | core, 23 | core << 2, 24 | keepAlive, 25 | unit, 26 | new LinkedBlockingQueue(queueSize), 27 | new LuThreadFactory(name), 28 | new LuRejectedExecutionHandler()); 29 | } 30 | 31 | public static ThreadPoolExecutor getThreadPool( String name) { 32 | return new LuThreadPool( 33 | cpu, 34 | cpu << 2, 35 | keepAlive, 36 | unit, 37 | new LinkedBlockingQueue(queueSize), 38 | new LuThreadFactory(name), 39 | new LuRejectedExecutionHandler()); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/util/currence/Semaphore.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.util.currence; 2 | 3 | import java.util.concurrent.atomic.AtomicInteger; 4 | 5 | 6 | /** 7 | * 信号量(限流器). 8 | */ 9 | public class Semaphore implements java.io.Serializable { 10 | 11 | private static final long serialVersionUID = -3109378282317104994L; 12 | 13 | private String unique; 14 | 15 | private AtomicInteger counter = new AtomicInteger(0); 16 | 17 | private AtomicInteger permits; 18 | 19 | public Semaphore(String unique, int permits) { 20 | this.unique = unique; 21 | this.permits = new AtomicInteger(permits); 22 | } 23 | 24 | 25 | /** 获取信号量; 注意: 此处 while 在高并发下, 由于自旋, 可能引起 CPU 飙升 */ 26 | public boolean tryAcquire() { 27 | int expect; 28 | while ((expect = counter.get()) < permits.get()) { 29 | return counter.compareAndSet(expect, expect + 1); 30 | } 31 | return false; 32 | } 33 | 34 | 35 | /** 归还信号量 */ 36 | public void release() { 37 | if (counter.get() <= 0) { 38 | counter.set(0); 39 | } else { 40 | counter.decrementAndGet(); 41 | } 42 | } 43 | 44 | /** 减小信号量阈值 */ 45 | public void reducePermits(int reduction) { 46 | if (reduction < 0) { 47 | return; 48 | } 49 | if (permits.get() < reduction) { 50 | permits.set(0); 51 | } 52 | permits.compareAndSet(permits.get(), permits.get() - reduction); 53 | } 54 | 55 | /** 增加信号量阈值 */ 56 | public void incrementPermits(int reduction) { 57 | if (reduction < 0) { 58 | return; 59 | } 60 | permits.compareAndSet(permits.get(), permits.get() + reduction); 61 | } 62 | 63 | public String getUnique() { 64 | return unique; 65 | } 66 | 67 | public void setUnique(String unique) { 68 | this.unique = unique; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/vmZK/LocalFileRegister.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.vmZK; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileNotFoundException; 6 | import java.io.FileOutputStream; 7 | import java.io.PrintWriter; 8 | import java.util.Arrays; 9 | import java.util.List; 10 | import java.util.Map; 11 | import java.util.concurrent.ConcurrentHashMap; 12 | 13 | import thinkinjava.exception.UserOperationException; 14 | import thinkinjava.rpc.remoting.Url; 15 | import thinkinjava.util.CloseUtil; 16 | 17 | /** 18 | * 19 | * @author 莫那·鲁道 20 | * @date 2018/10/15-上午6:39 21 | */ 22 | public class LocalFileRegister implements ServiceRegisterDisCover { 23 | 24 | private static Map cache = new ConcurrentHashMap(); 25 | 26 | private static String userHome; 27 | private static String currentDir; 28 | private static String lineSeparator; 29 | private static String configHome; 30 | static { 31 | userHome = System.getProperty("user.home"); 32 | configHome = userHome + "/lu/config.conf"; 33 | currentDir = System.getProperty("user.dir"); 34 | lineSeparator = System.getProperty("line.separator"); 35 | 36 | } 37 | 38 | public static LocalFileRegister create() { 39 | return new LocalFileRegister(); 40 | } 41 | 42 | public void registerService(String serviceName, Url url) { 43 | File file = new File(userHome + "/lu"); 44 | PrintWriter pw = null; 45 | try { 46 | if (!file.exists()) { 47 | file.mkdirs(); 48 | } 49 | file = new File(configHome); 50 | pw = new PrintWriter((new FileOutputStream(file, true))); 51 | pw.append(serviceName).append("=").append("localhost").append(":").append(String.valueOf("8081")); 52 | pw.append(lineSeparator); 53 | pw.flush(); 54 | 55 | } catch (FileNotFoundException e) { 56 | e.printStackTrace(); 57 | } finally { 58 | CloseUtil.close(pw); 59 | } 60 | 61 | } 62 | 63 | public void unregisterService(String serviceName) { 64 | cache.remove(serviceName); 65 | 66 | flushCache(); 67 | } 68 | 69 | 70 | public Url getServiceUrl(String serviceName) { 71 | 72 | Url url = cache.get(serviceName); 73 | 74 | if (url != null) { 75 | return url; 76 | } 77 | 78 | readFileAndCache(); 79 | 80 | return cache.get(serviceName); 81 | } 82 | 83 | private void readFileAndCache() { 84 | File file = new File(userHome + "/lu"); 85 | if (!file.exists()) { 86 | file.mkdirs(); 87 | } 88 | file = new File(configHome); 89 | long length = file.length(); 90 | if (length <= 0) { 91 | throw new UserOperationException( 92 | "LocalFileRegister Center config is empty, maybe you should start server first! "); 93 | } 94 | byte[] content = new byte[(int) length]; 95 | FileInputStream is = null; 96 | try { 97 | 98 | is = new FileInputStream(file); 99 | is.read(content); 100 | 101 | String contentString = new String(content); 102 | String[] arr = contentString.split(lineSeparator); 103 | 104 | List data = Arrays.asList(arr); 105 | 106 | cacheData(data); 107 | 108 | } catch (java.io.IOException e) { 109 | e.printStackTrace(); 110 | } finally { 111 | CloseUtil.close(is); 112 | } 113 | } 114 | 115 | private void flushCache() { 116 | File file = new File(configHome); 117 | PrintWriter pw = null; 118 | try { 119 | if (!file.exists()) { 120 | File dir = new File(userHome + "lu"); 121 | if (dir.mkdirs()) { 122 | file = new File(configHome); 123 | } 124 | } 125 | 126 | pw = new PrintWriter((new FileOutputStream(file))); 127 | 128 | for (String k : cache.keySet()) { 129 | String serviceName = k; 130 | Url url = cache.get(k); 131 | pw.append(serviceName + "=" + url.getIp() + ":" + url.getPort()); 132 | pw.append(lineSeparator); 133 | } 134 | 135 | pw.flush(); 136 | } catch (Exception e) { 137 | e.printStackTrace(); 138 | } finally { 139 | CloseUtil.close(pw); 140 | } 141 | } 142 | 143 | 144 | private void cacheData(List data) { 145 | for (String item : data) { 146 | String[] arr = item.split("="); 147 | if (arr.length == 2) { 148 | String[] serverUrl = arr[1].split(":"); 149 | cache.put(arr[0], new Url(serverUrl[0], Integer.valueOf(serverUrl[1]))); 150 | } 151 | } 152 | } 153 | 154 | } 155 | -------------------------------------------------------------------------------- /core/src/main/java/thinkinjava/vmZK/ServiceRegisterDisCover.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.vmZK; 2 | 3 | import thinkinjava.rpc.remoting.Url; 4 | 5 | /** 6 | * 服务注册发现 ServiceRegisterDisCover 7 | * 8 | * 虚拟的zk 9 | * 10 | * @author 莫那·鲁道 11 | * @date 2018/10/14-下午10:22 12 | */ 13 | public interface ServiceRegisterDisCover { 14 | 15 | 16 | void registerService(String serviceName, Url url); 17 | 18 | void unregisterService(String serviceName); 19 | 20 | Url getServiceUrl(String serviceName); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /core/src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stateIs0/Lu-Rpc/fd821ad3fed83cbbfa7877ef9ee2740c1f1b82bc/core/src/main/resources/application.properties -------------------------------------------------------------------------------- /core/src/main/resources/log4j.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /core/src/test/java/thinkinjava/proxy/InterceptorTest.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.proxy; 2 | 3 | import thinkinjava.api.client.LuConsumer; 4 | import thinkinjava.api.client.LuConsumerConfig; 5 | import thinkinjava.api.server.LuProvider; 6 | import thinkinjava.api.server.LuProviderConfig; 7 | import thinkinjava.rpc.remoting.LuUserProcessor; 8 | import thinkinjava.rpc.remoting.Url; 9 | import thinkinjava.rpc.remoting.testService.Demo; 10 | import thinkinjava.rpc.remoting.testService.DemoImpl; 11 | import thinkinjava.vmZK.LocalFileRegister; 12 | 13 | /** 14 | * 15 | * 16 | * @author 莫那·鲁道 17 | * @date 2018/10/14-下午10:52 18 | */ 19 | public class InterceptorTest { 20 | 21 | 22 | public static void main(String[] args) throws NoSuchMethodException { 23 | LuUserProcessor.methods.put("hello", Demo.class.getMethod("hello", String.class)); 24 | LuUserProcessor.targets.put(Demo.class.getName(), new DemoImpl()); 25 | LuProviderConfig luProviderConfig = new LuProviderConfig(); 26 | luProviderConfig.setService(Demo.class); 27 | luProviderConfig.setRef(DemoImpl.class); 28 | 29 | LuProvider luProvider = new LuProvider(luProviderConfig); 30 | luProvider.export(); 31 | 32 | LocalFileRegister.create().registerService(Demo.class.getName(), new Url("localhost", 8081)); 33 | 34 | LuConsumerConfig luConsumerConfig = new LuConsumerConfig(); 35 | luConsumerConfig.setService(Demo.class); 36 | 37 | LuConsumer luConsumer = new LuConsumer(luConsumerConfig); 38 | Demo demo = luConsumer.ref(); 39 | 40 | System.out.println(demo.hello("hello")); 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /core/src/test/java/thinkinjava/rpc/remoting/LuServerTest.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.rpc.remoting; 2 | 3 | import org.junit.After; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | 7 | import static org.junit.Assert.*; 8 | 9 | /** 10 | * 莫那·鲁道 11 | * @date 2018/10/14-下午8:59 12 | */ 13 | public class LuServerTest { 14 | 15 | @Before 16 | public void setUp() throws Exception { 17 | 18 | } 19 | 20 | @After 21 | public void tearDown() throws Exception { 22 | } 23 | 24 | @Test 25 | public void start() { 26 | } 27 | 28 | @Test 29 | public void stop() { 30 | } 31 | 32 | @Test 33 | public void getServer() { 34 | } 35 | 36 | @Test 37 | public void registerUserProcessor() { 38 | } 39 | } -------------------------------------------------------------------------------- /core/src/test/java/thinkinjava/rpc/remoting/MonaLuClientTest.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.rpc.remoting; 2 | 3 | import org.junit.After; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | 7 | import static org.junit.Assert.*; 8 | 9 | /** 10 | * 11 | * 12 | * @author 莫那·鲁道 13 | * @date 2018/10/14-下午8:58 14 | */ 15 | public class MonaLuClientTest { 16 | 17 | @Before 18 | public void setUp() throws Exception { 19 | } 20 | 21 | @After 22 | public void tearDown() throws Exception { 23 | } 24 | 25 | @Test 26 | public void invoke() { 27 | } 28 | } -------------------------------------------------------------------------------- /core/src/test/java/thinkinjava/rpc/remoting/RpcTest.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.rpc.remoting; 2 | 3 | import java.lang.reflect.Method; 4 | import java.util.Map; 5 | import java.util.concurrent.ConcurrentHashMap; 6 | 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | 10 | import thinkinjava.rpc.Request; 11 | import thinkinjava.rpc.remoting.testService.Demo; 12 | import thinkinjava.rpc.remoting.testService.DemoImpl; 13 | 14 | public class RpcTest { 15 | 16 | public static Map methods = new ConcurrentHashMap(); 17 | 18 | public static Map targets = new ConcurrentHashMap(); 19 | 20 | 21 | @Before 22 | public void before() { 23 | try { 24 | LuUserProcessor.methods.put("hello", Demo.class.getMethod("hello", String.class)); 25 | LuUserProcessor.targets.put("Demo", new DemoImpl()); 26 | 27 | } catch (NoSuchMethodException e) { 28 | e.printStackTrace(); 29 | } 30 | } 31 | 32 | 33 | @Test 34 | public void test() { 35 | LuServer server = new LuServer("127.0.0.1", 8081, false); 36 | server.registerUserProcessor(new LuUserProcessor()); 37 | 38 | server.start(); 39 | 40 | LuClient client = LuClient.create(); 41 | 42 | Request req = new Request(); 43 | 44 | req.setClassName(Demo.class.getName()); 45 | req.setMethodName("hello"); 46 | req.setArgs(new Object[]{"client"}); 47 | req.setServiceName("Demo"); 48 | 49 | Object result = client.invoke(req); 50 | System.out.println(result); 51 | 52 | server.stop(); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /core/src/test/java/thinkinjava/rpc/remoting/testService/Demo.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.rpc.remoting.testService; 2 | 3 | /** 4 | * 5 | * 6 | * @author 莫那·鲁道 7 | * @date 2018/10/14-下午9:50 8 | */ 9 | public interface Demo { 10 | 11 | String hello(String string); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /core/src/test/java/thinkinjava/rpc/remoting/testService/DemoImpl.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.rpc.remoting.testService; 2 | 3 | /** 4 | * 5 | * 6 | * @author 莫那·鲁道 7 | * @date 2018/10/14-下午9:50 8 | */ 9 | public class DemoImpl implements Demo { 10 | 11 | 12 | public String hello(String string) { 13 | System.out.println("receive client : " + string); 14 | return "server reply --- >" + string; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /core/src/test/java/thinkinjava/vmZK/LocalFileRegisterTest.java: -------------------------------------------------------------------------------- 1 | package thinkinjava.vmZK; 2 | 3 | import org.junit.After; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | 7 | import thinkinjava.rpc.remoting.Url; 8 | 9 | /** 10 | * 11 | * 12 | * @author 莫那·鲁道 13 | * @date 2018/10/15-上午7:02 14 | */ 15 | public class LocalFileRegisterTest { 16 | 17 | private ServiceRegisterDisCover serviceRegisterDisCover; 18 | 19 | @Before 20 | public void setUp() throws Exception { 21 | 22 | serviceRegisterDisCover = LocalFileRegister.create(); 23 | } 24 | 25 | @After 26 | public void tearDown() throws Exception { 27 | } 28 | 29 | @Test 30 | public void registerService() { 31 | serviceRegisterDisCover.registerService("hello", new Url("localhost", 8081)); 32 | System.out.println(serviceRegisterDisCover.getServiceUrl("hello")); 33 | serviceRegisterDisCover.unregisterService("hello"); 34 | 35 | System.out.println(serviceRegisterDisCover.getServiceUrl("hello")); 36 | 37 | } 38 | 39 | @Test 40 | public void getServerUrl() { 41 | } 42 | } -------------------------------------------------------------------------------- /example/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Lu-Rpc-parent 7 | cn.thinkinjava 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | example 13 | 使用例子 14 | 15 | 16 | 17 | 18 | cn.thinkinjava 19 | core 20 | 0.0.1-SNAPSHOT 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /example/src/main/java/cn.thinkinjava/ClientTest.java: -------------------------------------------------------------------------------- 1 | package cn.thinkinjava; 2 | 3 | import thinkinjava.api.client.LuConsumer; 4 | import thinkinjava.api.client.LuConsumerConfig; 5 | 6 | /** 7 | * 8 | * @author 莫那·鲁道 9 | * @date 2018/10/19-下午11:25 10 | */ 11 | public class ClientTest { 12 | public static void main(String[] args) throws InterruptedException { 13 | LuConsumerConfig luConsumerConfig = new LuConsumerConfig(); 14 | luConsumerConfig.setService(Demo.class); 15 | LuConsumer luConsumer = new LuConsumer(luConsumerConfig); 16 | Demo demo = luConsumer.ref(); 17 | 18 | for (; ; ) { 19 | System.out.println(demo.hello("hello")); 20 | Thread.sleep(1111); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /example/src/main/java/cn.thinkinjava/Demo.java: -------------------------------------------------------------------------------- 1 | package cn.thinkinjava; 2 | 3 | /** 4 | * 5 | * @author 莫那·鲁道 6 | * @date 2018/10/19-下午11:26 7 | */ 8 | public interface Demo { 9 | 10 | String hello(String string); 11 | } 12 | -------------------------------------------------------------------------------- /example/src/main/java/cn.thinkinjava/DemoImpl.java: -------------------------------------------------------------------------------- 1 | package cn.thinkinjava; 2 | 3 | /** 4 | * 5 | * @author 莫那·鲁道 6 | * @date 2018/10/19-下午11:26 7 | */ 8 | public class DemoImpl implements Demo { 9 | 10 | public String hello(String string) { 11 | System.out.println("receive client : " + string); 12 | return "server reply --- >" + string; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /example/src/main/java/cn.thinkinjava/ServerTest.java: -------------------------------------------------------------------------------- 1 | package cn.thinkinjava; 2 | 3 | import thinkinjava.api.server.LuProvider; 4 | import thinkinjava.api.server.LuProviderConfig; 5 | import thinkinjava.rpc.remoting.LuUserProcessor; 6 | import thinkinjava.rpc.remoting.Url; 7 | 8 | /** 9 | * 10 | * @author 莫那·鲁道 11 | * @date 2018/10/19-下午11:25 12 | */ 13 | public class ServerTest { 14 | public static void main(String[] args) throws NoSuchMethodException { 15 | LuUserProcessor.methods.put("hello", Demo.class.getMethod("hello", String.class)); 16 | LuUserProcessor.targets.put("Demo", new DemoImpl()); 17 | LuProviderConfig luProviderConfig = new LuProviderConfig(); 18 | 19 | luProviderConfig.setService(Demo.class); 20 | luProviderConfig.setRef(DemoImpl.class); 21 | luProviderConfig.setServiceUrl(new Url("127.0.0.1", 8081)); 22 | 23 | 24 | LuProvider luProvider = new LuProvider(luProviderConfig); 25 | 26 | luProvider.export(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /extension/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Lu-Rpc-parent 7 | cn.thinkinjava 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | extension 13 | RPC 框架的扩展功能, 例如链路追踪,分布式配置中心等 14 | 15 | 16 | -------------------------------------------------------------------------------- /filter/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Lu-Rpc-parent 7 | cn.thinkinjava 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | filter 13 | 过滤器 14 | 15 | 16 | -------------------------------------------------------------------------------- /lu-netty-remoting/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Lu-Rpc-parent 7 | cn.thinkinjava 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | lu-netty-remoting 13 | 用于自己实现 Netty 远程调用 14 | 15 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | cn.thinkinjava 7 | Lu-Rpc-parent 8 | 0.0.1-SNAPSHOT 9 | 10 | core 11 | cluster 12 | 13 | example 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | pom 25 | 26 | Lu-Rpc 27 | Learning for RPC 28 | 29 | 30 | 31 | UTF-8 32 | UTF-8 33 | 1.8 34 | 35 | 36 | 37 | 38 | junit 39 | junit 40 | 4.12 41 | 42 | 43 | 44 | 45 | com.alipay.sofa 46 | bolt 47 | 1.5.0 48 | 49 | 50 | 51 | 52 | com.alipay.sofa 53 | hessian 54 | 3.3.2 55 | 56 | 57 | 58 | org.slf4j 59 | slf4j-api 60 | 1.7.7 61 | 62 | 63 | ch.qos.logback 64 | logback-core 65 | 1.1.7 66 | 67 | 68 | ch.qos.logback 69 | logback-access 70 | 1.1.7 71 | 72 | 73 | ch.qos.logback 74 | logback-classic 75 | 1.1.7 76 | 77 | 78 | 79 | 80 | 81 | Lu-Rpc 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /proxy/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Lu-Rpc-parent 7 | cn.thinkinjava 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | proxy 13 | 代理层, 属于扩展功能. 14 | 15 | 16 | -------------------------------------------------------------------------------- /raft-register/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Lu-Rpc-parent 7 | cn.thinkinjava 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | raft-register 13 | 基于 Raft 协议的注册中心 14 | 15 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## 开发者须知 4 | 开发者在修改、扩展框架时,需要阅读开发规范: 5 | 1. [框架设计原则(梁飞)](http://thinkinjava.cn/2018/10/%E6%A1%86%E6%9E%B6%E8%AE%BE%E8%AE%A1%E5%8E%9F%E5%88%99-%E6%A2%81%E9%A3%9E/) 6 | 2. [汇总梁飞博客设计文章](http://thinkinjava.cn/2018/10/汇总梁飞博客设计文章/) 7 | 3. [框架设计上的十点基本常识](http://thinkinjava.cn/2018/10/框架设计上的十点基本常识/) 8 | 4. [Java-并发编程常识-by-梁飞](http://thinkinjava.cn/2018/04/Java-并发编程常识-by-梁飞/) 9 | 10 | 关于修改配置: 11 | 1. [配置设计](http://javatar.iteye.com/blog/949527) 12 | 13 | ## Lu-Rpc 14 | 15 | Lu-Rpc 是个专为学习者准备的 RPC 框架, 初始架构非常简单, 可供初学者扩展和学习. 16 | 17 | Lu 可以认为是中文世界的撸, 即撸 Rpc--- 造个 Rpc 轮子. 18 | 19 | Lu-Rpc 架构图如下: 20 | 21 | ![](https://upload-images.jianshu.io/upload_images/4236553-a2bf8ddf71d1a993.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 22 | 23 | 24 | 25 | Lu-Rpc 的领域模型设计借鉴 Dubbo, 服务域没有明显的界限. 核心域就是 Invoker, 非常合适作为核心领域模型的接口. 26 | 27 | 会话域可以是Request,也可以是 Invocation. 这个问题不大. 28 | 29 | ## 快速开始 30 | 31 | 进入 example 模块 32 | 33 | 先启动 ServerTest, 再启动 ClientTest. 34 | 35 | 36 | ## 待开发功能 37 | 0. ~~自研基于 Raft 协议的注册中心~~(已开发结束,地址: https://github.com/stateIs0/lu-raft) 38 | 1. Lu-Service-mesh 39 | 2. 负载均衡 40 | 3. 异常处理 41 | 4. 异步调用,feature 调用。oneway 调用 42 | 5. 连接管理,心跳管理 43 | 6. 服务监控 44 | 7. 服务优雅下线 45 | 8. 无缝支持 SpringBoot 46 | 9. 服务故障转移 47 | 10. 服务链路追踪 48 | 11. 支持分布式配置中心(自研或使用第三方) 49 | 12. 自研网络通信框架。定义自己的 RPC 协议。 50 | 13. 支持零拷贝序列化。 51 | 14. 使用字节码增强,减少反射调用开销。 52 | 15. 增加扩展点机制。 53 | 16. ~~熔断~~(已开发结束) 54 | 17. ~~限流~~(已开发结束) 55 | 56 | 欢迎提交 PR,issue。 57 | 58 | 本人微信: 59 | 60 | ![image](https://user-images.githubusercontent.com/24973360/50372024-5f975d00-0601-11e9-8247-139e145b1123.png) 61 | -------------------------------------------------------------------------------- /remoting/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Lu-Rpc-parent 7 | cn.thinkinjava 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | remoting 13 | 远程模块, 可添加 netty, SOFABolt 等 14 | 15 | -------------------------------------------------------------------------------- /serializer/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Lu-Rpc-parent 7 | cn.thinkinjava 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | serializer 13 | 序列化模块 14 | 15 | 16 | -------------------------------------------------------------------------------- /serviceMesh/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Lu-Rpc-parent 7 | cn.thinkinjava 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | serviceMesh 13 | Lu-Rpc 的 Service Mesh 14 | 15 | 16 | --------------------------------------------------------------------------------