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

勿忘初心2018-11-18 11:58

此文已由作者赵计刚薪授权网易云社区发布。

欢迎访问网易云社区,了解更多网易技术产品运营经验。


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"/>-->
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()!!!


免费体验云安全(易盾)内容安全、验证码等服务

更多网易技术、产品、运营经验分享请点击