All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.zodiac.autoconfigure.netty2.client.DefaultNettyRpcClientProxy Maven / Gradle / Ivy

There is a newer version: 1.6.8
Show newest version
package org.zodiac.autoconfigure.netty2.client;

import io.netty.util.concurrent.FastThreadLocal;

import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.zodiac.commons.function.AnnotationMethodToMethodNameFunction;
import org.zodiac.commons.function.AnnotationMethodToParameterNamesFunction;
import org.zodiac.commons.util.Reflections;
import org.zodiac.commons.util.lang.Strings;
import org.zodiac.netty.annotation.nprc.NRpcMethod;
import org.zodiac.netty.annotation.nprc.NRpcParam;
import org.zodiac.netty.base.api.Recyclable;
import org.zodiac.netty.core.ApplicationXContainer;
import org.zodiac.netty.core.config.NettyServerInfo;
import org.zodiac.netty.core.protocol.remote.config.NettyServerNRpcInfo;
import org.zodiac.netty.protocol.nprc.RpcClient;
import org.zodiac.netty.protocol.nprc.RpcClientAop;
import org.zodiac.netty.protocol.nprc.RpcMethod;
import org.zodiac.netty.protocol.nprc.RpcServerChannelHandler;
import org.zodiac.netty.protocol.nprc.RpcServerInstance;
import org.zodiac.netty.protocol.nprc.exception.RpcConnectException;
import org.zodiac.netty.springboot2.client.NettyRpcClientProxy;
import org.zodiac.netty.springboot2.client.NettyRpcFilter;
import org.zodiac.netty.springboot2.client.NettyRpcFullRequest;
import org.zodiac.netty.springboot2.client.NettyRpcLoadBalanced;
import org.zodiac.netty.springboot2.client.NettyRpcRequest;

import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;

/**
 * RPC client proxy (thread safe).
 * 
*
    *
  1. Management rpc client different ip addresses. Ip address corresponds to a client only.
  2. *
  3. In selecting ip address, will call NettyRpcLoadBalanced.class.
  4. *
*
* * @see org.zodiac.netty.springboot2.client.NettyRpcLoadBalanced#chooseAddress(NettyRpcRequest) * @see org.zodiac.netty.protocol.nprc.RpcClient *

* ----------------------------------------------------------------------- *

* Support rpc method annotation list. * @see NRpcParam * @see RequestMapping * @see RequestParam * @see RequestBody * @see RequestHeader * @see PathVariable * @see CookieValue * @see RequestPart */ public class DefaultNettyRpcClientProxy implements NettyRpcClientProxy { private static final Map CLIENT_MAP = new ConcurrentHashMap<>(64); private static final FastThreadLocal REQUEST_THREAD_LOCAL = new FastThreadLocal() { @Override protected DefaultNettyRpcRequest initialValue() throws Exception { return new DefaultNettyRpcRequest(); } }; private static final FastThreadLocal FILTER_CHAIN_THREAD_LOCAL = new FastThreadLocal() { @Override protected NettyRpcFilterChain initialValue() throws Exception { return new NettyRpcFilterChain(); } }; private final String requestMappingName; private final Class interfaceClass; private final String rpcInstanceKey; private final String version; private final AnnotationMethodToParameterNamesFunction annotationMethodToParameterNamesFunction = new AnnotationMethodToParameterNamesFunction( NRpcParam.class, RequestParam.class, RequestBody.class, RequestHeader.class, PathVariable.class, CookieValue.class, RequestPart.class); private final AnnotationMethodToMethodNameFunction annotationMethodToMethodNameFunction = new AnnotationMethodToMethodNameFunction( NRpcMethod.class, RequestMapping.class); private String serviceName; private int timeout; private NettyServerInfo nettyServerInfo; private Supplier loadBalancedSupplier; DefaultNettyRpcClientProxy(String serviceName, String requestMappingName, Class interfaceClass, NettyServerInfo nettyServerInfo, Supplier loadBalancedSupplier) { this.serviceName = serviceName; this.interfaceClass = interfaceClass; this.nettyServerInfo = nettyServerInfo; this.loadBalancedSupplier = loadBalancedSupplier; this.requestMappingName = Strings.isEmpty(requestMappingName) ? getRequestMappingName(interfaceClass) : requestMappingName; this.version = RpcServerInstance.getVersion(interfaceClass, this.nettyServerInfo.getNrpc().getClientDefaultVersion()); this.rpcInstanceKey = RpcClient.getClientInstanceKey(interfaceClass, this.requestMappingName, version); this.timeout = this.nettyServerInfo.getNrpc().getClientServerResponseTimeoutMills(); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); int parameterCount = method.getParameterCount(); if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); } if ("toString".equals(methodName) && parameterCount == 0) { return this.toString(); } if ("hashCode".equals(methodName) && parameterCount == 0) { return this.hashCode(); } if ("equals".equals(methodName) && parameterCount == 1) { return this.equals(args[0]); } NettyRpcFilterChain filterChain = FILTER_CHAIN_THREAD_LOCAL.get(); DefaultNettyRpcRequest request = REQUEST_THREAD_LOCAL.get(); request.args = args; request.method = method; request.proxy = proxy; request.timeout = this.timeout; request.clientProxy = this; try { InetSocketAddress address = chooseAddress(request); request.remoteAddress = address; RpcClient rpcClient = getClient(address); request.rpcClient = rpcClient; RpcClient.Sender sender = rpcClient.getRpcInstance(rpcInstanceKey); if (sender == null) { sender = rpcClient.newRpcInstance(interfaceClass, timeout, version, requestMappingName, annotationMethodToParameterNamesFunction, annotationMethodToMethodNameFunction, nettyServerInfo.getNrpc().isClientMethodOverwriteCheck()); } request.sender = sender; filterChain.nettyRpcFilterList = getNettyRpcFilterList(); filterChain.doFilter(request); return request.getResponse(); } finally { request.recycle(); filterChain.recycle(); } } public List getNettyRpcFilterList() { List nettyRpcFilterList = nettyServerInfo.getApplication().getBeanForType(NettyRpcFilter.class); nettyRpcFilterList.sort(AnnotationAwareOrderComparator.INSTANCE); return nettyRpcFilterList; } public int getTimeout() { return timeout; } public void setTimeout(int timeout) { if (timeout > 0) { this.timeout = timeout; } } public AnnotationMethodToMethodNameFunction getAnnotationMethodToMethodNameFunction() { return annotationMethodToMethodNameFunction; } public AnnotationMethodToParameterNamesFunction getAnnotationMethodToParameterNamesFunction() { return annotationMethodToParameterNamesFunction; } public String getRequestMappingName(Class objectType) { String requestMappingName = RpcServerChannelHandler.getRequestMappingName(objectType); if (Strings.isNotEmpty(requestMappingName)) { return requestMappingName; } RequestMapping requestMapping = Reflections.findAnnotation(objectType, RequestMapping.class); if (requestMapping != null) { requestMappingName = requestMapping.name(); String[] values = requestMapping.value(); String[] paths = requestMapping.path(); if (Strings.isEmpty(requestMappingName) && values.length > 0) { requestMappingName = values[0]; } if (Strings.isEmpty(requestMappingName) && paths.length > 0) { requestMappingName = paths[0]; } if (Strings.isNotEmpty(requestMappingName)) { return requestMappingName; } } requestMappingName = RpcServerChannelHandler.generateRequestMappingName(objectType); return requestMappingName; } /** * Get the RPC client (from the current thread, if not, create it automatically). * * @param address InetSocketAddress * @return RpcClient */ public RpcClient getClient(InetSocketAddress address) { RpcClient rpcClient = CLIENT_MAP.get(address); if (rpcClient == null) { synchronized (CLIENT_MAP) { rpcClient = CLIENT_MAP.get(address); if (rpcClient == null) { NettyServerNRpcInfo nrpc = nettyServerInfo.getNrpc(); rpcClient = new RpcClient(address); rpcClient.getAopList().addAll(nettyServerInfo.getApplication().getBeanForType(RpcClientAop.class)); rpcClient.setIoThreadCount(nrpc.getClientIoThreads()); rpcClient.setIoRatio(nrpc.getClientIoRatio()); rpcClient.setConnectTimeout(nrpc.getClientConnectionTimeoutMills()); rpcClient.setIdleTimeMs(nrpc.getClientHeartIntervalMills()); rpcClient.setReconnectScheduledIntervalMs(nrpc.getClientReconnectScheduledIntervalMills()); rpcClient.setEnableRpcHeartLog(nrpc.isClientHeartLogEnabled()); rpcClient.setEnableReconnectScheduledTask(nrpc.isClientReconnectScheduledEnabled()); CLIENT_MAP.put(address, rpcClient); } } } return rpcClient; } public InetSocketAddress chooseAddress(NettyRpcRequest request) { InetSocketAddress address; try { address = loadBalancedSupplier.get().chooseAddress(request); } catch (Exception e) { throw new RpcConnectException("Rpc Failed to select client address. cause [" + e.getLocalizedMessage() + "]", e); } if (address == null) { throw new NullPointerException("Rpc Failed to select client address. cause [return address is null]"); } return address; } public String getRequestMappingName() { return requestMappingName; } public String getVersion() { return version; } public Class getInterfaceClass() { return interfaceClass; } public String getRpcInstanceKey() { return rpcInstanceKey; } public String getServiceName() { return serviceName; } public void setServiceName(String serviceName) { this.serviceName = serviceName; } public NettyServerInfo getProperties() { return nettyServerInfo; } public Supplier getLoadBalancedSupplier() { return loadBalancedSupplier; } public void setLoadBalancedSupplier(Supplier loadBalancedSupplier) { this.loadBalancedSupplier = loadBalancedSupplier; } @Override public String toString() { return "NettyRpcClientProxy{" + "serviceName='" + serviceName + '\'' + ", requestMappingName='" + requestMappingName + '\'' + ", interfaceClass=" + interfaceClass + ", version='" + version + '\'' + ", timeout=" + timeout + '}'; } public static NettyRpcRequest getRequest() { return REQUEST_THREAD_LOCAL.get(); } public static NettyRpcFilter.FilterChain getFilterChain() { return FILTER_CHAIN_THREAD_LOCAL.get(); } public static Map getClientMap() { return CLIENT_MAP; } private static class NettyRpcFilterChain implements NettyRpcFilter.FilterChain, Recyclable { private List nettyRpcFilterList; private int count = 0; @Override public void doFilter(NettyRpcFullRequest request) throws Throwable { if (count < nettyRpcFilterList.size()) { nettyRpcFilterList.get(count++).doFilter(request, this); } } @Override public List getNettyRpcFilterList() { return Collections.unmodifiableList(nettyRpcFilterList); } @Override public void recycle() { count = 0; nettyRpcFilterList = null; } } /** * Default nett request (parameter [args array] can be modified). */ private static class DefaultNettyRpcRequest implements NettyRpcFullRequest, Recyclable { private AtomicBoolean responseGetFlag = new AtomicBoolean(false); private Method method; private Object[] args; private DefaultNettyRpcClientProxy clientProxy; private int timeout; private Object proxy; private RpcClient rpcClient; private InetSocketAddress remoteAddress; private RpcClient.Sender sender; private volatile Object response; private volatile Throwable throwable; private volatile boolean doneFlag; @Override public String getRpcInstanceKey() { return clientProxy.rpcInstanceKey; } @Override public NettyRpcClientProxy getClientProxy() { return clientProxy; } @Override public Supplier getLoadBalancedSupplier() { return clientProxy.loadBalancedSupplier; } @Override public Object getProxy() { return proxy; } @Override public Method getMethod() { return method; } @Override public Object[] getArgs() { return args; } @Override public String getServiceName() { return clientProxy.serviceName; } @Override public String getRequestMappingName() { return clientProxy.requestMappingName; } @Override public String getVersion() { return clientProxy.version; } @Override public int getTimeout() { return timeout; } @Override public void setTimeout(int timeout) { this.timeout = timeout; } @Override public NettyServerInfo getNettyServerInfo() { return clientProxy.nettyServerInfo; } @Override public ApplicationXContainer getApplication() { return clientProxy.nettyServerInfo.getApplication(); } @Override public Map getClientMap() { return CLIENT_MAP; } @Override public Class getInterfaceClass() { return clientProxy.interfaceClass; } @Override public RpcClient getRpcClient() { return rpcClient; } @Override public RpcClient.Sender getSender() { return sender; } @Override public RpcMethod getRpcMethod() { if (sender == null) { return null; } String rpcMethodName = RpcMethod.getMethodDescriptorName(method); return sender.getRpcMethodMap().get(rpcMethodName); } @Override public Map> getRpcMethodMap() { if (sender == null) { return null; } return sender.getRpcMethodMap(); } @Override public InetSocketAddress getRemoteAddress() { return remoteAddress; } @Override public Object getResponse() throws Throwable { if (sender == null) { return null; } if (responseGetFlag.compareAndSet(false, true)) { sender.setTimeout(timeout); try { response = sender.invoke(getProxy(), getMethod(), getArgs()); } catch (Throwable t) { throwable = t; throw t; } finally { doneFlag = true; } } else if (doneFlag) { if (throwable != null) { throw throwable; } } else { throw new ConcurrentModificationException("other thread call getting response!"); } return response; } @Override public void recycle() { args = null; method = null; clientProxy = null; proxy = null; remoteAddress = null; rpcClient = null; sender = null; response = null; throwable = null; doneFlag = false; responseGetFlag.set(false); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy