• 7.1 服务暴露前的准备-ServiceBean的装配


    dubbo的服务暴露以第一章 第一个dubbo项目中的dubbo-demo-provider来讲述。

    列出dubbo-demo-provider的xml配置:

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     3        xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
     4        xmlns="http://www.springframework.org/schema/beans"
     5        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
     6        http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
     7 
     8     <!-- 提供方应用信息,用于计算依赖关系 -->
     9     <dubbo:application name="demo-provider"/>
    10 
    11     <!-- 使用zookeeper注册中心,并使用curator客户端 -->
    12     <dubbo:registry protocol="zookeeper" address="10.211.55.5:2181" client="curator"/>
    13 
    14     <!-- 用dubbo协议在20880端口暴露服务 -->
    15     <dubbo:protocol name="dubbo" port="20880"/>
    16 
    17     <!-- 和本地bean一样实现服务 -->
    18     <bean id="demoService" class="com.alibaba.dubbo.demo.provider.DemoServiceImpl"/>
    19     <!--<bean id="demo2Service" class="com.alibaba.dubbo.demo.provider.Demo2ServiceImpl"/>-->
    20 
    21     <!-- 声明需要暴露的服务接口 -->
    22     <dubbo:service interface="com.alibaba.dubbo.demo.DemoService" ref="demoService"/>
    23     <!--<dubbo:service interface="com.alibaba.dubbo.demo.Demo2Service" ref="demo2Service"/>-->
    24 </beans>

    服务暴露是由com.alibaba.dubbo.config.spring.ServiceBean这个类来实现的,这个类是spring通过解析<dubbo:service>节点创建的单例Bean,每一个<dubbo:service>都会创建一个ServiceBean。先看一下ServiceBean的继承类图:

    看一下ServiceBean的源码:

      1 package com.alibaba.dubbo.config.spring;
      2 
      3 import com.alibaba.dubbo.config.ApplicationConfig;
      4 import com.alibaba.dubbo.config.ModuleConfig;
      5 import com.alibaba.dubbo.config.MonitorConfig;
      6 import com.alibaba.dubbo.config.ProtocolConfig;
      7 import com.alibaba.dubbo.config.ProviderConfig;
      8 import com.alibaba.dubbo.config.RegistryConfig;
      9 import com.alibaba.dubbo.config.ServiceConfig;
     10 import com.alibaba.dubbo.config.annotation.Service;
     11 import com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory;
     12 
     13 import org.springframework.beans.factory.BeanFactoryUtils;
     14 import org.springframework.beans.factory.BeanNameAware;
     15 import org.springframework.beans.factory.DisposableBean;
     16 import org.springframework.beans.factory.InitializingBean;
     17 import org.springframework.context.ApplicationContext;
     18 import org.springframework.context.ApplicationContextAware;
     19 import org.springframework.context.ApplicationEvent;
     20 import org.springframework.context.ApplicationListener;
     21 import org.springframework.context.event.ContextRefreshedEvent;
     22 import org.springframework.context.support.AbstractApplicationContext;
     23 
     24 import java.lang.reflect.Method;
     25 import java.util.ArrayList;
     26 import java.util.List;
     27 import java.util.Map;
     28 
     29 /**
     30  * ServiceFactoryBean
     31  */
     32 public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener, BeanNameAware {
     33     private static final long serialVersionUID = 213195494150089726L;
     34 
     35     private static transient ApplicationContext SPRING_CONTEXT;
     36 
     37     private transient ApplicationContext applicationContext;
     38 
     39     private transient String beanName;
     40 
     41     private transient boolean supportedApplicationListener;
     42 
     43     public ServiceBean() {
     44         super();
     45     }
     46 
     47     public ServiceBean(Service service) {
     48         super(service);
     49     }
     50 
     51     public static ApplicationContext getSpringContext() {
     52         return SPRING_CONTEXT;
     53     }
     54 
     55     /**
     56      * ApplicationContextAware接口的方法
     57      * Set the ApplicationContext that this object runs in.
     58      * Invoked after population of normal bean properties but before an init callback such
     59      * as {@link org.springframework.beans.factory.InitializingBean#afterPropertiesSet()}
     60      * or a custom init-method.
     61      *
     62      * 流程:
     63      * 1 将applicationContext设置到SpringExtensionFactory中,用于后续从SpringExtensionFactory中获取Bean
     64      * 2 获取方法addApplicationListener(ApplicationListener<?> listener),之后将当前类(因为当前类监听了ContextRefreshedEvent事件)加入spring的监听器列表
     65      */
     66     @Override
     67     public void setApplicationContext(ApplicationContext applicationContext) {
     68         this.applicationContext = applicationContext;
     69         SpringExtensionFactory.addApplicationContext(applicationContext);
     70         if (applicationContext != null) {
     71             SPRING_CONTEXT = applicationContext;
     72             try {
     73                 /**  */
     74                 Method method = applicationContext.getClass().getMethod("addApplicationListener", new Class<?>[]{ApplicationListener.class}); // 兼容Spring2.0.1
     75                 method.invoke(applicationContext, new Object[]{this});
     76                 supportedApplicationListener = true;
     77             } catch (Throwable t) {
     78                 if (applicationContext instanceof AbstractApplicationContext) {
     79                     try {
     80                         Method method = AbstractApplicationContext.class.getDeclaredMethod("addListener", new Class<?>[]{ApplicationListener.class}); // 兼容Spring2.0.1
     81                         if (!method.isAccessible()) {
     82                             method.setAccessible(true);
     83                         }
     84                         method.invoke(applicationContext, new Object[]{this});
     85                         supportedApplicationListener = true;
     86                     } catch (Throwable t2) {
     87                     }
     88                 }
     89             }
     90         }
     91     }
     92 
     93     /**
     94      * BeanNameAware接口的方法
     95      * Set the name of the bean in the bean factory that created this bean.
     96      * Invoked after population of normal bean properties but before an
     97      * init callback such as {@link InitializingBean#afterPropertiesSet()}
     98      * or a custom init-method.
     99      */
    100     @Override
    101     public void setBeanName(String name) {
    102         this.beanName = name;
    103     }
    104 
    105     /**
    106      * ApplicationListener接口的方法
    107      * delay没有设置或者是-1 && 服务没有暴露 && 服务没有反注册,则进行服务暴露
    108      */
    109     @Override
    110     public void onApplicationEvent(ApplicationEvent event) {
    111         if (ContextRefreshedEvent.class.getName().equals(event.getClass().getName())) {
    112             if (isDelay() && !isExported() && !isUnexported()) {
    113                 if (logger.isInfoEnabled()) {
    114                     logger.info("The service ready on spring started. service: " + getInterface());
    115                 }
    116                 export();
    117             }
    118         }
    119     }
    120 
    121     private boolean isDelay() {
    122         Integer delay = getDelay();
    123         ProviderConfig provider = getProvider();
    124         if (delay == null && provider != null) {
    125             delay = provider.getDelay();
    126         }
    127         return supportedApplicationListener && (delay == null || delay.intValue() == -1);
    128     }
    129 
    130     /**
    131      * InitializingBean接口的方法:
    132      * This method allows the bean instance to perform initialization only
    133      * possible when all bean properties have been set
    134      *
    135      * 流程:
    136      * 1 检查ServiceBean的ProviderConfig provider,如果为空,从applicationContext获取ProviderConfig类型的bean(这里查找的过程其实就是看有没有配置<dubbo:provider>),如果获取到了,进行设置
    137      * 2 后续会参照1分别进行
    138      *   -- ApplicationConfig application
    139      *   -- ModuleConfig module
    140      *   -- List<RegistryConfig> registries
    141      *   -- MonitorConfig monitor
    142      *   -- List<ProtocolConfig> protocols
    143      *   -- String path:服务名称
    144      * 3 判断延迟的事件是否大于0,如果是,执行export(),进行服务暴露,如果不是,结束(这种情况下服务暴露,会发生在发布上下文刷新事件的时候)
    145      */
    146     @Override
    147     @SuppressWarnings({"unchecked", "deprecation"})
    148     public void afterPropertiesSet() throws Exception {
    149         if (getProvider() == null) {
    150             Map<String, ProviderConfig> providerConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProviderConfig.class, false, false);
    151             if (providerConfigMap != null && providerConfigMap.size() > 0) {
    152                 Map<String, ProtocolConfig> protocolConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProtocolConfig.class, false, false);
    153                 if ((protocolConfigMap == null || protocolConfigMap.size() == 0)
    154                         && providerConfigMap.size() > 1) { // 兼容旧版本
    155                     List<ProviderConfig> providerConfigs = new ArrayList<ProviderConfig>();
    156                     for (ProviderConfig config : providerConfigMap.values()) {
    157                         if (config.isDefault() != null && config.isDefault().booleanValue()) {
    158                             providerConfigs.add(config);
    159                         }
    160                     }
    161                     if (providerConfigs.size() > 0) {
    162                         setProviders(providerConfigs);
    163                     }
    164                 } else {
    165                     ProviderConfig providerConfig = null;
    166                     for (ProviderConfig config : providerConfigMap.values()) {
    167                         if (config.isDefault() == null || config.isDefault().booleanValue()) {
    168                             if (providerConfig != null) {
    169                                 throw new IllegalStateException("Duplicate provider configs: " + providerConfig + " and " + config);
    170                             }
    171                             providerConfig = config;
    172                         }
    173                     }
    174                     if (providerConfig != null) {
    175                         setProvider(providerConfig);
    176                     }
    177                 }
    178             }
    179         }
    180         if (getApplication() == null
    181                 && (getProvider() == null || getProvider().getApplication() == null)) {
    182             Map<String, ApplicationConfig> applicationConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ApplicationConfig.class, false, false);
    183             if (applicationConfigMap != null && applicationConfigMap.size() > 0) {
    184                 ApplicationConfig applicationConfig = null;
    185                 for (ApplicationConfig config : applicationConfigMap.values()) {
    186                     if (config.isDefault() == null || config.isDefault().booleanValue()) {
    187                         if (applicationConfig != null) {
    188                             throw new IllegalStateException("Duplicate application configs: " + applicationConfig + " and " + config);
    189                         }
    190                         applicationConfig = config;
    191                     }
    192                 }
    193                 if (applicationConfig != null) {
    194                     setApplication(applicationConfig);
    195                 }
    196             }
    197         }
    198         if (getModule() == null
    199                 && (getProvider() == null || getProvider().getModule() == null)) {
    200             Map<String, ModuleConfig> moduleConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ModuleConfig.class, false, false);
    201             if (moduleConfigMap != null && moduleConfigMap.size() > 0) {
    202                 ModuleConfig moduleConfig = null;
    203                 for (ModuleConfig config : moduleConfigMap.values()) {
    204                     if (config.isDefault() == null || config.isDefault().booleanValue()) {
    205                         if (moduleConfig != null) {
    206                             throw new IllegalStateException("Duplicate module configs: " + moduleConfig + " and " + config);
    207                         }
    208                         moduleConfig = config;
    209                     }
    210                 }
    211                 if (moduleConfig != null) {
    212                     setModule(moduleConfig);
    213                 }
    214             }
    215         }
    216         if ((getRegistries() == null || getRegistries().size() == 0)
    217                 && (getProvider() == null || getProvider().getRegistries() == null || getProvider().getRegistries().size() == 0)
    218                 && (getApplication() == null || getApplication().getRegistries() == null || getApplication().getRegistries().size() == 0)) {
    219             Map<String, RegistryConfig> registryConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, RegistryConfig.class, false, false);
    220             if (registryConfigMap != null && registryConfigMap.size() > 0) {
    221                 List<RegistryConfig> registryConfigs = new ArrayList<RegistryConfig>();
    222                 for (RegistryConfig config : registryConfigMap.values()) {
    223                     if (config.isDefault() == null || config.isDefault().booleanValue()) {
    224                         registryConfigs.add(config);
    225                     }
    226                 }
    227                 if (registryConfigs != null && registryConfigs.size() > 0) {
    228                     super.setRegistries(registryConfigs);
    229                 }
    230             }
    231         }
    232         if (getMonitor() == null
    233                 && (getProvider() == null || getProvider().getMonitor() == null)
    234                 && (getApplication() == null || getApplication().getMonitor() == null)) {
    235             Map<String, MonitorConfig> monitorConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, MonitorConfig.class, false, false);
    236             if (monitorConfigMap != null && monitorConfigMap.size() > 0) {
    237                 MonitorConfig monitorConfig = null;
    238                 for (MonitorConfig config : monitorConfigMap.values()) {
    239                     if (config.isDefault() == null || config.isDefault().booleanValue()) {
    240                         if (monitorConfig != null) {
    241                             throw new IllegalStateException("Duplicate monitor configs: " + monitorConfig + " and " + config);
    242                         }
    243                         monitorConfig = config;
    244                     }
    245                 }
    246                 if (monitorConfig != null) {
    247                     setMonitor(monitorConfig);
    248                 }
    249             }
    250         }
    251         if ((getProtocols() == null || getProtocols().size() == 0)
    252                 && (getProvider() == null || getProvider().getProtocols() == null || getProvider().getProtocols().size() == 0)) {
    253             Map<String, ProtocolConfig> protocolConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProtocolConfig.class, false, false);
    254             if (protocolConfigMap != null && protocolConfigMap.size() > 0) {
    255                 List<ProtocolConfig> protocolConfigs = new ArrayList<ProtocolConfig>();
    256                 for (ProtocolConfig config : protocolConfigMap.values()) {
    257                     if (config.isDefault() == null || config.isDefault().booleanValue()) {
    258                         protocolConfigs.add(config);
    259                     }
    260                 }
    261                 if (protocolConfigs != null && protocolConfigs.size() > 0) {
    262                     super.setProtocols(protocolConfigs);
    263                 }
    264             }
    265         }
    266         if (getPath() == null || getPath().length() == 0) {
    267             if (beanName != null && beanName.length() > 0
    268                     && getInterface() != null && getInterface().length() > 0
    269                     && beanName.startsWith(getInterface())) {
    270                 setPath(beanName);
    271             }
    272         }
    273         if (!isDelay()) {//设置的延迟时间大于0
    274             export();
    275         }
    276     }
    277 
    278     /**
    279      * DisposableBean接口的方法
    280      */
    281     @Override
    282     public void destroy() throws Exception {
    283         unexport();
    284     }
    285 }

    这里最重要的两个方法:afterPropertiesSet()和onApplicationEvent(ApplicationEvent event)。

    一 设置属性与服务暴露

    当所有的Bean的属性被设置好之后,执行afterPropertiesSet()。该方法的流程:

    1 设置属性

    检查ServiceBean的某个属性(这里的属性包含如下6个)是否为空,如果为空,从applicationContext获取相应类型的bean,如果获取到了,则进行相应的设置。

    • ProviderConfig provider:其实就是看有没有配置<dubbo:provider>
    • ApplicationConfig application:其实就是看有没有配置<dubbo:application>
    • ModuleConfig module:其实就是看有没有配置<dubbo:module>
    • List<RegistryConfig> registries:其实就是看有没有配置<dubbo:registry>
    • MonitorConfig monitor:其实就是看有没有配置<dubbo:monitor>
    • List<ProtocolConfig> protocols:其实就是看有没有配置<dubbo:protocol>
    • String path:服务名称

    2 是否暴露服务

    之后判断延迟的时间是否大于0,如果是,执行export(),进行服务暴露,如果不是,结束(这种情况下服务暴露会发生在容器发布上下文刷新事件的时候)。在这里,我们并没有指定delay,所以delay==null,服务暴露会发生在容器发布上下文刷新事件的时候。

    当afterPropertiesSet()结束之后,来看一下此时的ServiceBean实例,实例的私有属性如下:(没有值的暂时不说)

     1 id = com.alibaba.dubbo.demo.DemoService
     2 applicationContext = ClassPathXmlApplicationContext实例
     3 beanName = com.alibaba.dubbo.demo.DemoService
     4 interfaceName = com.alibaba.dubbo.demo.DemoService
     5 supportedApplicationListener = true
     6 ref = DemoServiceImpl实例
     7 path = com.alibaba.dubbo.demo.DemoService
     8 
     9 application:
    10 -- id = demo-provider
    11 -- name = demo-provider
    12 
    13 registries = [
    14     RegistryConfig:
    15     -- id = com.alibaba.dubbo.config.RegistryConfig
    16     -- protocol = zookeeper
    17     -- address = 10.211.55.5:2181
    18     -- client = curator
    19 ]
    20 
    21 protocols = [ 
    22     ProtocolConfig: 
    23     -- id = dubbo
    24     -- name = dubbo
    25     -- port = 20880    
    26 ]

    实际上在创建ServiceBean实例的时候,也会初始化其父类ServiceConfig的静态属性:

    1     private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
    2     private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();

    其中protocol的实例是:Protocol$Adaptive实例,Protocol$Adaptive类的代码在5.2 dubbo-compiler源码解析已经列出。

    下边来看一下第二句代码的源码。首先,看一下ProxyFactory的定义:

     1 package com.alibaba.dubbo.rpc;
     2 
     3 import com.alibaba.dubbo.common.Constants;
     4 import com.alibaba.dubbo.common.URL;
     5 import com.alibaba.dubbo.common.extension.Adaptive;
     6 import com.alibaba.dubbo.common.extension.SPI;
     7 
     8 /**
     9  * ProxyFactory. (API/SPI, Singleton, ThreadSafe)
    10  */
    11 @SPI("javassist")
    12 public interface ProxyFactory {
    13     /**
    14      * create proxy.
    15      */
    16     @Adaptive({Constants.PROXY_KEY})
    17     <T> T getProxy(Invoker<T> invoker) throws RpcException;
    18 
    19     /**
    20      * create invoker.
    21      */
    22     @Adaptive({Constants.PROXY_KEY})
    23     <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;
    24 }

    ExtensionLoader.getExtensionLoader(ProxyFactory.class)的实现结果还是:

    ExtensionLoader<com.alibaba.dubbo.rpc.ProxyFactory> loader,最终的loader包含如下属性:

    • Class<?> type = interface com.alibaba.dubbo.rpc.ProxyFactory
    • ExtensionFactory objectFactory = AdaptiveExtensionFactory(适配类)
      • factories = [SpringExtensionFactory实例, SpiExtensionFactory实例]

    之后,执行getAdaptiveExtension()。

    来看一下:META-INF/dubbo/internal/com.alibaba.dubbo.rpc.ProxyFactory的内容:

    1 stub=com.alibaba.dubbo.rpc.proxy.wrapper.StubProxyFactoryWrapper
    2 jdk=com.alibaba.dubbo.rpc.proxy.jdk.JdkProxyFactory
    3 javassist=com.alibaba.dubbo.rpc.proxy.javassist.JavassistProxyFactory

    从ProxyFactory的@SPI("javassist"),默认选用的实现是com.alibaba.dubbo.rpc.proxy.javassist.JavassistProxyFactory。com.alibaba.dubbo.rpc.proxy.wrapper.StubProxyFactoryWrapper是一个wrapper类,但是wrapper类只在getExtension("xxx")中会实现aop,而在getAdaptiveExtension()不会进行aop包裹。

    这里的三个实现类没有一个类上带有@Adaptive注解,所以会动态创建类。动态生成的类ProxyFactory$Adaptive代码如下:

     1 package com.alibaba.dubbo.rpc;
     2 import com.alibaba.dubbo.common.extension.ExtensionLoader;
     3 
     4 public class ProxyFactory$Adaptive implements com.alibaba.dubbo.rpc.ProxyFactory {
     5     public com.alibaba.dubbo.rpc.Invoker getInvoker(java.lang.Object arg0, java.lang.Class arg1, com.alibaba.dubbo.common.URL arg2) throws com.alibaba.dubbo.rpc.RpcException {
     6         if (arg2 == null) 
     7             throw new IllegalArgumentException("url == null");
     8         com.alibaba.dubbo.common.URL url = arg2;
     9         String extName = url.getParameter("proxy", "javassist");
    10         if(extName == null) 
    11             throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.ProxyFactory) name from url(" + url.toString() + ") use keys([proxy])");
    12         com.alibaba.dubbo.rpc.ProxyFactory extension = (com.alibaba.dubbo.rpc.ProxyFactory)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.ProxyFactory.class).getExtension(extName);
    13         return extension.getInvoker(arg0, arg1, arg2);
    14     }
    15     
    16     public java.lang.Object getProxy(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.RpcException {
    17         if (arg0 == null) 
    18             throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null");
    19         if (arg0.getUrl() == null) 
    20             throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");com.alibaba.dubbo.common.URL url = arg0.getUrl();
    21         String extName = url.getParameter("proxy", "javassist");
    22         if(extName == null) 
    23             throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.ProxyFactory) name from url(" + url.toString() + ") use keys([proxy])");
    24         com.alibaba.dubbo.rpc.ProxyFactory extension = (com.alibaba.dubbo.rpc.ProxyFactory)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.ProxyFactory.class).getExtension(extName);
    25         return extension.getProxy(arg0);
    26     }
    27 }

    所以ServiceConfig中的静态属性proxyFactory为ProxyFactory$Adaptive实例。

    至此,一个ServiceBean实例完成了。

    二 在上下文刷新时进行初始化

     1     /**
     2      * ApplicationListener接口的方法
     3      * delay没有设置或者是-1 && 服务没有暴露 && 服务没有反注册,则进行服务暴露
     4      */
     5     @Override
     6     public void onApplicationEvent(ApplicationEvent event) {
     7         if (ContextRefreshedEvent.class.getName().equals(event.getClass().getName())) {
     8             if (isDelay() && !isExported() && !isUnexported()) {
     9                 if (logger.isInfoEnabled()) {
    10                     logger.info("The service ready on spring started. service: " + getInterface());
    11                 }
    12                 export();
    13             }
    14         }
    15     }

    一切准备好之后,就在这里开始进行服务暴露!export()!!!

  • 相关阅读:
    TensorFlowMNIST数据集逻辑回归处理
    TensorFlow多元线性回归实现
    TensorFlow简单线性回归
    mysql ON DUPLICATE KEY UPDATE
    20200908 morning diary
    LambdaUtil
    数据库SQL自我书写册
    getMyFriendsListFromWeChat()
    MySQL8.*的JSON语法知多少
    Exception in thread "main" java.lang.IllegalArgumentException: Cannot deserialize instance of `java.lang.String` out of START_ARRAY token at [Source: UNKNOWN; line: -1, c
  • 原文地址:https://www.cnblogs.com/java-zhao/p/7620355.html
Copyright © 2020-2023  润新知