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