Pigeon源码跟踪之客户端获取服务

在具体调用ServiceFactory.getService时,实际会调用serviceProxy.getProxy(invokerConfig),进一步调用AbstractServiceProxy#getProxy方法,这个方法的实现逻辑大致如下:

1 检查interface,url,protocol等参数合法性,如果url没有设置,默认使用接口全限定名,如果protocol不为空,且等于default,则修改成@DEFAULT@,同时更新url加上这个协议前缀
2 双重加锁检查invokeConfig对应的服务是否以存在,不存在先尝试启动调用方启动类InvokerBootStrap
3 先根据配置的序列方式获取相应的序列化类,再根据invokerConfig创建动态代理:ServiceInvocationProxy
4 如果配置中的负载均衡配置存在,注册服务到负载均衡管理器中
5 注册区域策略服务
6 ClientManager.getInstance().registerClients(invokerConfig)注册客户端到注册中心(默认为zk)
7 缓存服务

 本文分析下第6条

public static void init() {
        registerBizProcessFilter(new GenericImplFilter());
        if (!isInitialized) {
            registerBizProcessFilter(new InvokerDataFilter());
            if (Constants.MONITOR_ENABLE) {
                registerBizProcessFilter(new RemoteCallMonitorInvokeFilter());
            }

            registerBizProcessFilter(new DegradationFilter());
            registerBizProcessFilter(new FlowControlPigeonClientFilter());
            registerBizProcessFilter(new ClusterInvokeFilter());
            registerBizProcessFilter(new GatewayInvokeFilter());
            registerBizProcessFilter(new ContextPrepareInvokeFilter());
            registerBizProcessFilter(new RemoteCallInvokeFilter());
            bizInvocationHandler = createInvocationHandler(bizProcessFilters);
            isInitialized = true;
        }

    }

  先看客户端的动态代理过程

  com.dianping.pigeon.remoting.invoker.proxy.AbstractServiceProxy

public <T> T getProxy(InvokerConfig<T> invokerConfig) {
        if (invokerConfig.getServiceInterface() == null) {
            throw new IllegalArgumentException("service interface is required");
        } else {
            if (StringUtils.isBlank(invokerConfig.getUrl())) {
                invokerConfig.setUrl(ServiceFactory.getServiceUrl(invokerConfig));
            }

            String protocolPrefix;
            if (!StringUtils.isBlank(invokerConfig.getProtocol()) && !invokerConfig.getProtocol().equalsIgnoreCase("default")) {
                protocolPrefix = "@" + invokerConfig.getProtocol().toUpperCase() + "@";
                if (!invokerConfig.getUrl().startsWith(protocolPrefix)) {
                    invokerConfig.setUrl(protocolPrefix + invokerConfig.getUrl());
                }
            }

            protocolPrefix = null;
            Object service = services.get(invokerConfig);
            if (service == null) {
                try {
                    InvokerBootStrap.startup();
                    service = SerializerFactory.getSerializer(invokerConfig.getSerialize()).proxyRequest(invokerConfig);
                    if (StringUtils.isNotBlank(invokerConfig.getLoadbalance())) {
                        LoadBalanceManager.register(invokerConfig.getUrl(), invokerConfig.getGroup(), invokerConfig.getLoadbalance());
                    }

  

public abstract class DefaultAbstractSerializer implements Serializer {
    public DefaultAbstractSerializer() {
    }

    public Object proxyRequest(InvokerConfig<?> invokerConfig) throws SerializationException {
        return Proxy.newProxyInstance(ClassUtils.getCurrentClassLoader(invokerConfig.getClassLoader()), new Class[]{invokerConfig.getServiceInterface()}, new ServiceInvocationProxy(invokerConfig, InvokerProcessHandlerFactory.selectInvocationHandler(invokerConfig)));
    }
public class ServiceInvocationProxy implements InvocationHandler
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
        Class<?>[] parameterTypes = method.getParameterTypes();
        if (method.getDeclaringClass() == Object.class) {
            return method.invoke(this.handler, args);
        } else if ("toString".equals(methodName) && parameterTypes.length == 0) {
            return this.handler.toString();
        } else if ("hashCode".equals(methodName) && parameterTypes.length == 0) {
            return this.handler.hashCode();
        } else {
            return "equals".equals(methodName) && parameterTypes.length == 1 ? this.handler.equals(args[0]) : this.extractResult(this.handler.handle(new DefaultInvokerContext(this.invokerConfig, methodName, parameterTypes, args)), method.getReturnType());
        }
    }
DefaultInvokerContext 这个就好玩了
public class DefaultInvokerContext extends AbstractInvocationContext implements InvokerContext {
    private InvokerConfig<?> invokerConfig;
    private String methodName;
    private Class<?>[] parameterTypes;
    private Object[] arguments;
    private Client client;//tcp客户端
    private boolean isDegraded = false;

  注意这里的client可是null的,那么什么时候变成的具体值呢?

  ClusterInvokeFilter()

public class ClusterInvokeFilter extends InvocationInvokeFilter {
    private static final Logger logger = LoggerLoader.getLogger(ClusterInvokeFilter.class);
    private Monitor monitor = MonitorLoader.getMonitor();

    public ClusterInvokeFilter() {
    }

    public InvocationResponse invoke(ServiceInvocationHandler handler, InvokerContext invocationContext) throws Throwable {
        invocationContext.getTimeline().add(new TimePoint(TimePhase.CL));
        InvokerConfig<?> invokerConfig = invocationContext.getInvokerConfig();
        Cluster cluster = ClusterFactory.selectCluster(invokerConfig.getCluster());
        if (cluster == null) {
            throw new IllegalArgumentException("Unsupported cluster type:" + cluster);
        } else {
            try {
                return cluster.invoke(handler, invocationContext);

  FailfastCluster 

public InvocationResponse invoke(ServiceInvocationHandler handler, InvokerContext invocationContext) throws Throwable {
        InvokerConfig<?> invokerConfig = invocationContext.getInvokerConfig();
        InvocationRequest request = InvokerUtils.createRemoteCallRequest(invocationContext, invokerConfig);
        boolean timeoutRetry = invokerConfig.isTimeoutRetry();
        if (!timeoutRetry) {
            Client remoteClient = this.clientManager.getClient(invokerConfig, request, (List)null);
            invocationContext.setClient(remoteClient);

            try {
                return handler.handle(invocationContext);

  每个客户端都会缓存到一个服务端的连接,调用的时候根据负载均衡策略等选择一条连接进行通讯

posted on 2021-03-09 15:55  MaXianZhe  阅读(80)  评论(0编辑  收藏  举报

导航