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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM