SOFA RPC源码解析之Rest服务(2)-服务引用

版权声明: https://blog.csdn.net/beyondself_77/article/details/80862607

1.SOFA RPC源码解析

1.1Rest服务

1.1.1 服务引用

        以SOFABoot自带的RPC案例sofaboot-sample-with-rpc为例,详细描述SOFABoot服务发布原理。

        在此提前说明,源码分析主要分析主流程,以及本人认为比较重要的一些内容,对于其它部分,大家可以基于本文档,自行研读。

        RPC案例的SpringXML配置文件内容如下:

1.  <?xml version="1.0"encoding="UTF-8"?>
2.  <beansxmlns="http://www.springframework.org/schema/beans"
3.         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4.         xmlns:sofa="http://sofastack.io/schema/sofaboot"
5.         xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd
6.              http://sofastack.io/schema/sofaboot  http://sofastack.io/schema/sofaboot.xsd"
7.         default-autowire="byName">
8.   
9.      <beanid="personServiceImpl"class="com.alipay.sofa.boot.examples.demo.rpc.bean.PersonServiceImpl"/>
10.     
11.     <sofa:serviceref="personServiceImpl"interface="com.alipay.sofa.boot.examples.demo.rpc.bean.PersonService">       
12.         <sofa:binding.rest/>
13.     </sofa:service>   
14.  
15.      <sofa:referenceid="personReferenceRest" interface="com.alipay.sofa.boot.examples.demo.rpc.bean.PersonService"jvm-first="false">
16.          <sofa:binding.rest>
17.              <sofa:global-attrstimeout="300000" address-wait-time="2000"/>
18.              <sofa:routetarget-url="127.0.0.1:8341"/>
19.              <sofa:methodname="sayName" timeout="300000"/>
20.          </sofa:binding.rest>
21.      </sofa:reference>  
22.  
23.     <bean id="personFilter"class="com.alipay.sofa.boot.examples.demo.rpc.bean.PersonServiceFilter"/>
24.  
25. </beans>

        在SpringXML配置文件中:

        1.   通过XML元素bean定义PersonService接口实现类PersonServiceImpl;

        2.   通过XML元素sofa:reference引用restful格式的PersonService接口服务;

        启动本应用,启动流程在《启动原理》中已经详细描述,在此不再详述,直接到从SpringXML配置文件加载Bean定义开始分析。

        一、   注册ReferenceFactoryBean类对应的Bean定义

        调用AnnotationConfigEmbeddedWebApplicationContext(AbstractApplicationContext).refresh())方法刷新Spring应用上下文过程,通过invokeBeanFactoryPostProcessors(beanFactory)方法调用beanFactory中所有实现了BeanFactoryPostProcessor接口的类。

        当调用到ConfigurationClassPostProcessor类processConfigBeanDefinitions方法时,在循环处理@Configuration配置类过程中,调用ConfigurationClassBeanDefinitionReader类loadBeanDefinitions(configClasses)方法,处理解析完成的@Configuration配置类。此时,其中有一步是调用ConfigurationClassBeanDefinitionReader类loadBeanDefinitionsFromImportedResources(configClass.getImportedResources())方法,加载@ImportResource注解里面配置的SpringXML配置文件中定义的Bean。在这个方法中,使用XMLBeanDefinitionReader加载SpringXML配置文件中定义的Bean。

        接下来就是SpringXML配置文件中各种标签的解析过程。

扫描二维码关注公众号,回复: 3682169 查看本文章

        对于XML标签bean,由于是最基本的SpringXML标签,大家都应用比较熟悉了,在此不再详述。

        对于XML标签sofa:reference,其处理过程如下:

        XMLBeanDefinitionReader类调用DefaultBeanDefinitionDocumentReader类registerBeanDefinitions方法注册Bean定义;

        DefaultBeanDefinitionDocumentReader类调用BeanDefinitionParserDelegate类parseCustomElement方法解析自定义的XML元素。

        在此,对于XML标签sofa:service,根据命名空间sofa对应的值http://sofastack.io/schema/sofaboot,在spring.handlers(此文件位于infra-sofa-boot-starter.jar)文件中,查找到XML标签的处理类SofaBootNamespaceHandler:

1.  http\://sofastack.io/schema/sofaboot=com.alipay.sofa.infra.config.spring.namespace.handler.SofaBootNamespaceHandler

        在SofaBootNamespaceHandler类中,调用findParserForElement方法,查找指定XML元素的解析类,此处service对应的BeanDefinitionParser解析类为com.alipay.sofa.runtime.spring.parser.ReferenceDefinitionParser。

        使用ReferenceDefinitionParser类把SpringXML配置文件中sofa:reference标签定义的服务转换为ReferenceFactoryBean,并注册到Spring应用上下文中。

        二、   创建ReferenceFactoryBean类的实例

        调用AnnotationConfigEmbeddedWebApplicationContext(AbstractApplicationContext).refresh())方法刷新Spring应用上下文。

        当通过onRefresh() 方法调用createEmbeddedServletContainer方法,在调用DefaultListableBeanFactory类doGetBeanNamesForType(ResolvableType type, booleanincludeNonSingletons, boolean allowEagerInit)方法,获取类型为org.springframework.boot.context.embedded.EmbeddedServletContainerFactory的Bean名字时,会遍历beanFactory中所有beanDefinitionNames,判断每个beanName所代表的Bean定义RootBeanDefinition中beanClass是否与EmbeddedServletContainerFactory类型相匹配。当调用org.springframework.beans.factory.support.AbstractBeanFactory.isTypeMatch方法判断名为personReferenceRest的BeanDefinition对应的实例与EmbeddedServletContainerFactory是否类型匹配。由于XML标签sofa:reference被解析为ReferenceFactoryBean类,该类实现了FactoryBean接口,表明其为工厂Bean,所以为了查看此工厂Bean创建的实例的具体类型,必须实例化此工厂Bean,即ReferenceFactoryBean。至此,又会调用AbstractBeanFactory的getObject方法,获取此ReferenceFactoryBean创建的具体实例。

        当实例化ReferenceFactoryBean时,由于ReferenceFactoryBean实现了Initializing接口,所以在调用ReferenceFactoryBean类的初始化方法时,会调用ReferenceFactoryBean类的afterPropertiesSet方法,进行实例的初始化操作。

        到现在为止,开始Rest服务引用流程:

        1.  根据XML标签sofa:reference所包含的子标签sofa:binding.*(一个或多个,此处是sofa:binding.rest),解析出引用服务的类型,此处是restful风格的服务。

        2.  创建Reference接口的实现ReferenceImpl,其中,引用的服务接口类型为com.alipay.sofa.boot.examples.demo.rpc.bean.PersonService,接口模式为spring(表明此引用服务来自于SpringXML配置文件),jvmFirst为true(表示优先使用JVM服务,即在同一个JVM内部服务之间的调用方式)。

        3.  把解析出的binding(此处为RestBinding)增加到reference实例的属性bindings集合中。

        4.  调用ReferenceRegisterHelper类registerReference方法:

1.  public static ObjectregisterReference(Reference reference,
2.                                             BindingAdapterFactorybindingAdapterFactory,
3.                                             SofaRuntimeProperties sofaRuntimeProperties,
4.                                             SofaRuntimeContextsofaRuntimeContext) {
5.          Binding binding = (Binding)reference.getBindings().toArray()[0];
6.   
7.          if(!binding.getBindingType().equals(JvmBinding.JVM_BINDING_TYPE)
8.              &&!sofaRuntimeProperties.isDisableJvmFirst() && reference.isJvmFirst()) {
9.              reference.addBinding(new JvmBinding());
10.         }
11.  
12.         ComponentManager componentManager= sofaRuntimeContext.getComponentManager();
13.         ReferenceComponent referenceComponent =new ReferenceComponent(reference,
14.             new DefaultImplementation(),bindingAdapterFactory, sofaRuntimeProperties,
15.             sofaRuntimeContext);
16.  
17.         if(componentManager.isRegistered(referenceComponent.getName())) {
18.             returncomponentManager.getComponentInfo(referenceComponent.getName())
19.                 .getImplementation().getTarget();
20.         }
21.  
22.         ComponentInfo componentInfo =componentManager.registerAndGet(referenceComponent);
23.         returncomponentInfo.getImplementation().getTarget();
24.  
25.     }

        注册Reference组件的主要步骤:

  • 获取ReferenceImpl实例的属性bindings集合中第一个binding;(此处为RestBinding类型)
  • 此binding不是JvmBinding类型,但属性disableJvmFirst为false(表明全局开启jvmFirst),属性jvmFirst为false,即不优先使用JVM服务,不用增加JvmBinding到reference实例的属性bindings集合中;
  • 从sofaRuntimeContext实例中获取组件管理器实例componentManager;
  • 创建ReferenceComponent实例;
  • 判断组件管理器componentManager中是否存在指定名字的组件,例如:名称为reference:com.alipay.sofa.boot.examples.demo.rpc.bean.PersonService:#-1745597079,如果有,则直接从组件管理器获取组件,并返回组件的实现的代理。如果没有,则在组件管理器中注册刚才创建的ReferenceComponent实例。
1.  private ComponentInfodoRegister(ComponentInfo ci) {
2.          ComponentName name = ci.getName();
3.          if (isRegistered(name)) {
4.              SofaLogger.error("Componentwas already registered: {0}", name);
5.              return getComponentInfo(name);
6.          }
7.   
8.          try {
9.              ci.register();
10.         } catch (Throwable e) {
11.             SofaLogger.error(e, "Failed toregister component: {0}", ci.getName());
12.             return null;
13.         }
14.  
15.         SofaLogger.info("Registeringcomponent: {0}", ci.getName());
16.  
17.         try {
18.             ComponentInfo old = registry.putIfAbsent(ci.getName(), ci);
19.             if (old != null) {
20.                 return old;
21.             }
22.             if (ci.resolve()) {
23.                 typeRegistry(ci);
24.                 ci.activate();
25.             }
26.         } catch (Throwable e) {
27.              ……
28.         }
29.  
30.         return ci;
31.     }

        在组件管理器中注册组件的主要过程如下:

  • 调用组件ComponentInfo类的register方法,更新组件状态为registered。
  • 把组件置入组件管理器的registry中(ConcurrentMap<ComponentName, ComponentInfo>)。
  • 调用组件ComponentInfo类的resolve方法,更新组件状态为resolved。
  • 把组件置入组件管理器的resolvedRegistry中(ConcurrentMap<ComponentType, Map<ComponentName,ComponentInfo>>)。
  • 调用组件ComponentInfo类的activate方法,激活组件,并更新组件状态为activated。
1.  public void activate() throwsServiceRuntimeException {
2.          if (reference.hasBinding()) {
3.              Binding candidate = null;
4.              Set<Binding> bindings =reference.getBindings();
5.              if (bindings.size() == 1) {
6.                  candidate = bindings.iterator().next();
7.              } else if (bindings.size() > 1){
8.                  Object backupProxy = null;
9.                  for (Binding binding :bindings) {
10.                     if(JvmBinding.JVM_BINDING_TYPE.getType().equals(binding.getName())) {
11.                         candidate = binding;
12.                     } else {
13.                         backupProxy = createProxy(reference, binding);
14.                     }
15.                 }
16.                 if (candidate != null) {
17.                     ((JvmBinding) candidate).setBackupProxy(backupProxy);
18.                 }
19.             }
20.  
21.             Object proxy = null;
22.             if (candidate != null) {
23.                 proxy = createProxy(reference, candidate);
24.             }
25.  
26.             this.implementation = newDefaultImplementation();
27.             implementation.setTarget(proxy);
28.         }
29.  
30.         super.activate();
31.         latch.countDown();
32.     }

        在ComponentInfo类activate方法中,主要处理逻辑如下:

  • 获取ReferenceImpl中所有Binding。

        此处需要注意的是,在rpc.xsd文件中,规定XML标签sofa-reference只能有0个或1个Binding子元素。其可选子元素:binding.jvm、binding.bolt、binding.rest、binding.dubbo。

        如果设置多个Binding子元素,则在实例化时抛异常。

        如果不设置Binding子元素,则默认为JvmBinding。

        这个隐含的规则从这部分代码中无法体现,但影响其下面的处理逻辑。

        由此可知,Binding的个数只能为1或2。

        当Binding的个数当为1时,则只能是JvmBinding或其他类型Binding之一。

        当Binding的个数当为2时,则只能是JvmBinding和其他类型Binding之一。

        在下述三种情况下,ReferenceImpl中所有Binding的个数为1:

        ★ 当未设置Binding子元素,而采用默认的JvmBinding;

        ★ 设置Binding子元素为JvmBinding;

        ★ 设置一个其他类型的Binding,但disableJvmFirst为false,并且jvmFirst为true。

        在下述情况下,ReferenceImpl中所有Binding的个数为2:

        ★ 设置一个其他类型的Binding,但disableJvmFirst为true,或jvmFirst为false。

  • 如果Binding个数为1,其处理逻辑为:

        ★ 设置candidate(候选Binding)为当前Binding;

  • 如果Binding个数为2,其处理逻辑为:

        ★ 如果Binding类型为jvm,则设置candidate为JvmBinding。

        ★ 如果Binding类型为其它类型的Binding,如RestBinding,则调用createProxy(reference,binding)方法,根据Binding类型创建代理对象。

        ★ 设置JvmBinding的备选代理对象(backupProxy)为刚才创建的其它类型Binding的代理对象。

  • 如果candidate不为null,则调用createProxy(reference,candidate)方法,为候选Binding(candidate)创建代理对象proxy。否则,proxy为null。
  • 创建DefaultImplementation实例,并设置ReferenceComponent实例target属性为刚才为candidate创建的代理对象proxy。

        上述逻辑稍微有点复杂,简单来说就是:

  • 在优先使用JVM服务的前提下,如果配置了一个其它类型的服务,如Rest服务,则把它作为JVM服务的备选服务。当JVM服务不可用时,使用备选服务。如果没有配置其它类型服务,则JVM服务没有备选服务,当JVM服务不可用时,则服务不可用,调用失败。
  • 在不优先使用JVM服务的前提下,则只能使用配置的其它类型的服务,如Rest服务。

        在此案例中,配置了RestBinding,但设置不优先使用JvmBinding,所以只有1个Binding。所以,candidate为RestBinding,为RestBinding创建代理对象。

        注意,如果我们配置了RestBinding,并且设置优先使用JvmBinding,则默认增加了JvmBinding,所以一共有2个Binding。此时,会先为RestBinding创建代理对象,然后设置candidate为JvmBinding,并设置JvmBinding的backupProxy为刚创建的RestBinding的代理对象。最后,在为JvmBinding创建代理对象。对于为JvmBinding创建代理对象的过程,请参考《JVM服务-服务引用》,在此不详述。

        在此,我们主要关注一下通过createProxy方法为RestBinding创建代理对象的过程。

        为RestBinding创建代理对象的具体过程如下:

1.  private Object createProxy(Referencereference, Binding binding) {
2.          BindingAdapter<Binding>bindingAdapter = bindingAdapterFactory.getBindingAdapter(binding
3.              .getBindingType());
4.          ……
5.          Object proxy;
6.          try {
7.              proxy = bindingAdapter.inBinding(reference,binding, sofaRuntimeContext);
8.          } finally {
9.              ……
10.         return proxy;
11.     }

        根据Binding类型,通过BindingAdapterFactoryImpl类getBindingAdapter方法,获取指定Binding类型的Binding适配器,此处是RestBindingAdapter。

        调用RestBindingAdapter类inBinding方法创建代理对象:

1.  public Object inBinding(Object contract,RpcBinding binding, SofaRuntimeContext sofaRuntimeContext) {
2.          ConsumerConfig consumerConfig =SpringBridge.getConsumerConfigHelper().getConsumerConfig((Contract) contract,
3.              binding);
4.          SpringBridge.getConsumerConfigContainer().addConsumerConfig(binding,consumerConfig);
5.   
6.          try {
7.              Objectresult = consumerConfig.refer();
8.              binding.setConsumerConfig(consumerConfig);
9.              return result;
10.         } catch (Exception e) {
11.             throw newServiceRuntimeException(LogCodes.getLog(LogCodes.ERROR_PROXY_CONSUME_FAIL), e);
12.         }
13.     }

        通过工具类SpringBridge获取服务消费者配置工具类ConsumerConfigHelper,然后调用ConsumerConfigHelper类getConsumerConfig方法,根据接口类型和Binding类型,获取服务消费者配置类ConsumerConfig,并增加到ConsumerConfigContainer中。

        调用服务消费者配置类ConsumerConfig的refer方法,开始指定Binding类型的服务引用流程,此处为RestBinding类型的服务引用流程。

1.      public T refer() {
2.          if (consumerBootstrap == null) {
3.              consumerBootstrap =Bootstraps.from(this);
4.          }
5.          return consumerBootstrap.refer();
6.      }

        通过Bootstraps类,利用ExtensionLoader扩展机制,获取名字为ConsumerConfig实例中bootstrap属性(此处为rest)指定的ConsumerBootstrap接口实现,此处为com.alipay.sofa.rpc.bootstrap.rest.RestConsumerBootstrap。

        调用RestConsumerBootstrap类refer方法,开始真正的Rest服务引用流程:

1.  public T refer() {
2.          if (proxyIns != null) {
3.              return proxyIns;
4.          }
5.          synchronized (this) {
6.              if (proxyIns != null) {
7.                  return proxyIns;
8.              }
9.              String key = consumerConfig.buildKey();
10.             String appName =consumerConfig.getAppName();
11.             // 检查参数
12.             checkParameters();
13.             // 提前检查接口类
14.             if (LOGGER.isInfoEnabled(appName)){
15.                 LOGGER.infoWithApp(appName,"Refer consumer config : {} with bean id {}", key,consumerConfig.getId());
16.             }
17.  
18.             // 注意同一interface,同一tags,同一protocol情况
19.             AtomicInteger cnt =REFERRED_KEYS.get(key); // 计数器
20.             if (cnt == null) { // 没有发布过
21.                 cnt =CommonUtils.putToConcurrentMap(REFERRED_KEYS, key, new AtomicInteger(0));
22.             }
23.             int c = cnt.incrementAndGet();
24.             int maxProxyCount =consumerConfig.getRepeatedReferLimit();
25.             if (maxProxyCount > 0) {
26.                 if (c > maxProxyCount) {
27.                     cnt.decrementAndGet();
28.                     // 超过最大数量,直接抛出异常
29.                     throw newSofaRpcRuntimeException("Duplicate consumer config with key " + key
30.                         + " has beenreferred more than " + maxProxyCount + " times!"
31.                         + " Maybe it'swrong config, please check it."
32.                         + " Ignore this ifyou did that on purpose!");
33.                 } else if (c > 1) {
34.                     if(LOGGER.isInfoEnabled(appName)) {
35.                         LOGGER.infoWithApp(appName,"Duplicate consumer config with key {} has been referred!"
36.                             + " Maybe it'swrong config, please check it."
37.                             + " Ignorethis if you did that on purpose!", key);
38.                     }
39.                 }
40.             }
41.  
42.             try {
43.                 // build cluster
44.                 cluster =ClusterFactory.getCluster(this);
45.                 // build listeners
46.                 consumerConfig.setConfigListener(buildConfigListener(this));
47.                 consumerConfig.setProviderInfoListener(buildProviderInfoListener(this));
48.                 // init cluster
49.                 cluster.init();
50.                 // 构造Invoker对象(执行链)
51.                 proxyInvoker =buildClientProxyInvoker(this);
52.                 // 创建代理类
53.                 proxyIns = (T)ProxyFactory.buildProxy(consumerConfig.getProxy(),consumerConfig.getProxyClass(),
54.                     proxyInvoker);
55.             } catch (Exception e) {
56.                 if (cluster != null) {
57.                     cluster.destroy();
58.                     cluster = null;
59.                 }
60.                 consumerConfig.setConfigListener(null);
61.                 consumerConfig.setProviderInfoListener(null);
62.                 cnt.decrementAndGet(); // 发布失败不计数
63.                 if (e instanceofSofaRpcRuntimeException) {
64.                     throw(SofaRpcRuntimeException) e;
65.                 } else {
66.                     throw newSofaRpcRuntimeException("Build consumer proxy error!", e);
67.                 }
68.             }
69.             if (consumerConfig.getOnAvailable()!= null && cluster != null) {
70.                 cluster.checkStateChange(false);// 状态变化通知监听器
71.             }
72.             RpcRuntimeContext.cacheConsumerConfig(this);
73.             return proxyIns;
74.         }
75.     }

        在refer方法中,其主要处理过程如下:

        (一)    如果proxyIns不为null,则直接返回proxyIns。否则,继续。

        (二)    在synchronized同步代码块中执行引用服务的过程,避免多线程并发引用服务的问题;

        (三)    构建服务消费者配置类key:格式:protocol + "://" +interfaceId + ":" + uniqueId;例如:rest://com.alipay.sofa.boot.examples.demo.rpc.bean.PersonService:

        (四)    检查参数,这是一个扩展点,通过在子类重写此方法,实现参数和属性的个性化处理。此处什么也不做。

        (五)    判断该服务的引用数量(即创建代理的数量)是否超出最大引用数量repeatedReferLimit的设置,如果超出最大数量,则直接抛出异常。否则,继续。

        (六)    通过ClusterFactory类getCluster方法获取Cluster实例。在getCluster方法中,通过RPC扩展机制获取Cluster接口扩展实现,此处别名为failover,所以获取到com.alipay.sofa.rpc.client.FailoverCluster类的实例。

        (七)    设置consumerConfig实例配置监听器为Consumer配置发生变化监听器ConsumerAttributeListener;

        (八)    设置consumerConfig实例服务提供者信息监听器为ClusterProviderInfoListener;

        (九)    调用Cluster的init方法,初始化Cluster实例:

1.  public synchronized void init() {
2.          if (initialized) { // 已初始化
3.              return;
4.          }
5.          // 构造Router
6.          routerChain =RouterChain.buildConsumerChain(consumerBootstrap);
7.          // 负载均衡策略考虑是否可动态替换?
8.          loadBalancer =LoadBalancerFactory.getLoadBalancer(consumerBootstrap);
9.          // 地址管理器
10.         addressHolder =AddressHolderFactory.getAddressHolder(consumerBootstrap);
11.         // 连接管理器
12.         connectionHolder =ConnectionHolderFactory.getConnectionHolder(consumerBootstrap);
13.         // 构造Filter,最底层是调用过滤器
14.         this.filterChain =FilterChain.buildConsumerChain(this.consumerConfig,
15.             newConsumerInvoker(consumerBootstrap));
16.  
17.         if (consumerConfig.isLazy()) { // 延迟连接
18.             if(LOGGER.isInfoEnabled(consumerConfig.getAppName())) {
19.                 LOGGER.infoWithApp(consumerConfig.getAppName(),"Connection will be initialized when first invoke.");
20.             }
21.         }
22.  
23.         // 启动重连线程
24.         connectionHolder.init();
25.         try {
26.             // 得到服务端列表
27.             List<ProviderGroup> all = consumerBootstrap.subscribe();
28.             if (CommonUtils.isNotEmpty(all)) {
29.                 // 初始化服务端连接(建立长连接)
30.                 updateAllProviders(all);
31.             }
32.         } catch (SofaRpcRuntimeException e) {
33.             throw e;
34.         } catch (Throwable e) {
35.             throw newSofaRpcRuntimeException("Init provider's transport error!", e);
36.         }
37.  
38.         // 启动成功
39.         initialized = true;
40.  
41.         // 如果check=true表示强依赖
42.         if (consumerConfig.isCheck() &&!isAvailable()) {
43.             throw newSofaRpcRuntimeException("The consumer is depend on alive provider " +
44.                 "and there is no aliveprovider, you can ignore it " +
45.                 "byConsumerConfig.setCheck(boolean) (default is false)");
46.         }
47.     }

        在init方法中,其主要处理过程如下:

        1)   构造Router链:解析用户通过别名的方式注入的router、解析自动加载的router,然后按order从小到大排序,最后根据解析完的router,创建RouterChain实例;

        2)   负载均衡策略:利用RPC扩展机制获取LoadBalancer接口扩展实现。此处采用默认的com.alipay.sofa.rpc.client.lb.RandomLoadBalancer;

        3)   地址管理器:利用RPC扩展机制获取AddressHolder接口扩展实现。此处别名为singleGroup,所以获取到com.alipay.sofa.rpc.client.SingleGroupAddressHolder类的实例;

        4)   连接管理器:利用RPC扩展机制获取ConnectionHolder接口扩展实现。此处别名为all,所以获取到com.alipay.sofa.rpc.client.AllConnectConnectionHolder类的实例;

        5)   构造服务调用端的执行链FilterChain,构建过程如下:

1.  public static FilterChainbuildConsumerChain(ConsumerConfig<?> consumerConfig, FilterInvokerlastFilter) {
2.   
3.          /*
4.          * 例如自动装载扩展 A(a),B(b),C(c)  filter=[-a,d]  filterRef=[new E, new Exclude(b)]
5.          * 逻辑如下:
6.          * 1.解析config.getFilterRef(),记录E-b
7.          * 2.解析config.getFilter()字符串,记录 d -a,-b
8.          * 3.再解析自动装载扩展,a,b被排除了,所以拿到c,d
9.          * 4.c d进行排序
10.         * 5.拿到CD实现类
11.         * 6.加上自定义,返回CDE
12.         */
13.         // 用户通过自己new实例的方式注入的filter,优先级高
14.         List<Filter> customFilters =consumerConfig.getFilterRef() == null ?
15.             new ArrayList<Filter>() : newCopyOnWriteArrayList<Filter>(consumerConfig.getFilterRef());
16.         // 先解析是否有特殊处理
17.         HashSet<String> excludes =parseExcludeFilter(customFilters);
18.  
19.         // 准备数据:用户通过别名的方式注入的filter,需要解析
20.         List<ExtensionClass<Filter>>extensionFilters = new ArrayList<ExtensionClass<Filter>>();
21.         List<String> filterAliases =consumerConfig.getFilter(); //
22.         if(CommonUtils.isNotEmpty(filterAliases)) {
23.             for (String filterAlias :filterAliases) {
24.                 if (startsWithExcludePrefix(filterAlias)){ // 排除用的特殊字符
25.                     excludes.add(filterAlias.substring(1));
26.                 } else {
27.                     ExtensionClass<Filter>filter = EXTENSION_LOADER.getExtensionClass(filterAlias);
28.                     if (filter != null) {
29.                         extensionFilters.add(filter);
30.                     }
31.                 }
32.             }
33.         }
34.         // 解析自动加载的过滤器
35.         if (!excludes.contains(StringUtils.ALL)&& !excludes.contains(StringUtils.DEFAULT)) { // 配了-*-default表示不加载内置
36.             for (Map.Entry<String,ExtensionClass<Filter>> entry : CONSUMER_AUTO_ACTIVES.entrySet()) {
37.                 if(!excludes.contains(entry.getKey())) {
38.                     extensionFilters.add(entry.getValue());
39.                 }
40.             }
41.         }
42.         excludes = null; // 不需要了
43.         // order从小到大排序
44.         if (extensionFilters.size() > 1) {
45.             Collections.sort(extensionFilters,new OrderedComparator<ExtensionClass<Filter>>());
46.         }
47.         List<Filter> actualFilters = newArrayList<Filter>();
48.         for (ExtensionClass<Filter>extensionFilter : extensionFilters) {
49.             actualFilters.add(extensionFilter.getExtInstance());
50.         }
51.         // 加入自定义的过滤器
52.         actualFilters.addAll(customFilters);
53.         return new FilterChain(actualFilters,lastFilter, consumerConfig);
54.     }

        注意,最底层是服务消费者调用过滤器ConsumerInvoker,是执行真正的服务调用过程,使用client发送数据给server,具体调用过程在后面详细说明;

        6)   启动重连线程:根据配置参数,启动ScheduledThreadPoolExecutor线程池,默认每隔10秒进行重连操作。

        7)   获取服务提供者列表:如果配置了直连属性directUrl不为空,则直接返回;如果为空,则依次从多个服务注册中心订阅服务提供者列表,并返回订阅结果,例如:

1.  [ProviderGroup{name='_DEFAULT',providerInfos=[rest://192.168.1.101:8341?serialization=hessian2&source=local,rest://192.168.1.4:8341?serialization=hessian2&source=local,rest://192.168.1.3:8341?serialization=hessian2&source=local]}]
        8)   更新服务端列表,初始化服务端连接:
1.  public voidupdateAllProviders(List<ProviderGroup> providerGroups) {
2.          List<ProviderGroup>oldProviderGroups = newArrayList<ProviderGroup>(addressHolder.getProviderGroups());
3.          int count = 0;
4.          if (providerGroups != null) {
5.              for (ProviderGroup providerGroup :providerGroups) {
6.                  checkProviderInfo(providerGroup);
7.                  count += providerGroup.size();
8.              }
9.          }
10.         if (count == 0) {
11.             Collection<ProviderInfo>currentProviderList = currentProviderList();
12.             addressHolder.updateAllProviders(providerGroups);
13.             if(CommonUtils.isNotEmpty(currentProviderList)) {
14.                 if(LOGGER.isWarnEnabled(consumerConfig.getAppName())) {
15.                     LOGGER.warnWithApp(consumerConfig.getAppName(),"Provider list is emptied, may be all " +
16.                         "providers hasbeen closed, or this consumer has been add to blacklist");
17.                     closeTransports();
18.                 }
19.             }
20.         } else {
21.             addressHolder.updateAllProviders(providerGroups);
22.             connectionHolder.updateAllProviders(providerGroups);
23.         }
24.         if(EventBus.isEnable(ProviderInfoUpdateAllEvent.class)) {
25.             ProviderInfoUpdateAllEvent event =new ProviderInfoUpdateAllEvent(consumerConfig, oldProviderGroups,
26.                 providerGroups);
27.             EventBus.post(event);
28.         }
29.     }

        检查各个服务提供端组中每个服务提供端信息,如协议是否匹配、序列化方式等。然后,更新addressHolder实例的服务提供者信息和更新connectionHolder实例的服务提供者信息。

        至此, Cluster实例初始化完毕。

        (十)    构造Invoker对象(执行链):proxyInvoker具体实现类为DefaultClientProxyInvoker;

        (十一) 为proxyInvoker创建代理对象:调用ProxyFactory类buildProxy方法:

1.  public static <T> TbuildProxy(String proxyType, Class<T> clazz, Invoker proxyInvoker) throwsException {
2.          try {
3.              ExtensionClass<Proxy> ext =ExtensionLoaderFactory.getExtensionLoader(Proxy.class)
4.                  .getExtensionClass(proxyType);
5.              if (ext == null) {
6.                  throwExceptionUtils.buildRuntime("consumer.proxy", proxyType,
7.                      "Unsupported proxy ofclient!");
8.              }
9.              Proxy proxy = ext.getExtInstance();
10.             return proxy.getProxy(clazz,proxyInvoker);
11.         } catch (SofaRpcRuntimeException e) {
12.             throw e;
13.         }catch (Throwable e) {
14.             throw newSofaRpcRuntimeException(e.getMessage(), e);
15.         }
16.     }

        利用RPC扩展机制获取Proxy接口扩展实现。此处别名为jdk,所以获取到com.alipay.sofa.rpc.proxy.jdk.JDKProxy类的实例。

        调用JDKProxy类getProxy方法,为clazz指定的接口(例如:com.alipay.sofa.boot.examples.demo.rpc.bean.PersonService)创建代理实例:

1.      public <T> T getProxy(Class<T>interfaceClass, Invoker proxyInvoker) {
2.          InvocationHandler handler = newJDKInvocationHandler(interfaceClass, proxyInvoker);
3.          ClassLoader classLoader =ClassLoaderUtils.getCurrentClassLoader();
4.          T result = (T)java.lang.reflect.Proxy.newProxyInstance(classLoader,
5.              new Class[] { interfaceClass },handler);
6.          return result;
7.      }

        创建JDK代理处理器JDKInvocationHandler,该类实现了JDK动态代理java.lang.reflect.InvocationHandler接口。

1.      public JDKInvocationHandler(ClassproxyClass, Invoker proxyInvoker) {
2.          this.proxyClass = proxyClass;
3.          this.proxyInvoker = proxyInvoker;
4.      }

        通过java.lang.reflect.Proxy类newProxyInstance方法,为指定的接口(如: com.alipay.sofa.boot.examples.demo.rpc.bean.PersonService)创建代理。

        此处可以看到,JDKProxy采用JDK动态代理机制。该JDK代理处理器拦截对proxyClass指定的接口(例如:com.alipay.sofa.boot.examples.demo.rpc.bean.PersonService)的方法调用,把方法调用封装成SOFA RPC请求SofaRequest,然后调用proxyInvoker的invoke方法,完成具体的服务调用。

        至此,proxyInvoker代理对象proxyIns创建完成,返回proxyIns。

        返回到引用组件的activate方法,通过createProxy创建后备代理对象backupProxy的流程完成。

1.  public void activate() throwsServiceRuntimeException {
2.          if (reference.hasBinding()) {
3.              Binding candidate = null;
4.              Set<Binding> bindings =reference.getBindings();
5.              if (bindings.size() == 1) {
6.                  candidate =bindings.iterator().next();
7.              } else if (bindings.size() > 1){
8.                  Object backupProxy = null;
9.                  for (Binding binding :bindings) {
10.                     if(JvmBinding.JVM_BINDING_TYPE.getType().equals(binding.getName())) {
11.                         candidate = binding;
12.                     } else {
13.                         backupProxy = createProxy(reference, binding);
14.                     }
15.                 }
16.                 if (candidate != null) {
17.                     ((JvmBinding)candidate).setBackupProxy(backupProxy);
18.                 }
19.             }
20.  
21.             Object proxy = null;
22.             if (candidate != null) {
23.                 proxy = createProxy(reference, candidate);
24.             }
25.  
26.             this.implementation = newDefaultImplementation();
27.             implementation.setTarget(proxy);
28.         }
29.  
30.         super.activate();
31.         latch.countDown();
32.     }

        接下来,创建DefaultImplementation实例,并设置ReferenceComponent实例target属性为刚才创建的candidate代理对象。

        设置ReferenceFactoryBean的proxy为刚才创建的代理对象。这样,当其它类引用某个服务的ReferenceFactoryBean类时,由于此类为工厂Bean,所以通过getObject方法获取的实际对象为代理对象。这样对生成的代理对象的方法调用都会委托到InvocationHandler.invoke()方法。

        至此,RestBinding类型的服务的代理对象创建完成。

猜你喜欢

转载自blog.csdn.net/beyondself_77/article/details/80862607