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