Dubbo系列(十二)Dubbo之改造Dubbo,使其能够兼容Spring 4注解配置

转载请注明出处:http://blog.csdn.net/l1028386804/article/details/70040928

Dubbo本身就是基于spring环境的,但是Dubbo当年Spring才2.版本。 而现如今Spring 已经发展到4.3.,今年(2017)应该会发布Spring 5。
而随着Spring Boot的大热,Java-Base方式配置Spring也变得越来越流行。
Dubbo + Boot的开发模式,也是较为常见的组合方式。
但是,当使用Dubbo在高版本Spring环境中使用注解方式配置时,会因为一些代码版本的原因导致整合出现问题。

1. Dubbo原生的注解配置

Dubbo本身就是基于Spring的,而且原生就提供注解配置:
服务提供方配置:

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <!-- 扫描注解包路径,多个包用逗号分隔,不填pacakge表示扫描当前ApplicationContext中所有的类 -->  
  2. <dubbo:annotation package="com.foo.bar.service" />  
服务提供方注解:
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. import com.alibaba.dubbo.config.annotation.Service;  
  2.   
  3. @Service(version="1.0.0")  
  4. public class FooServiceImpl implements FooService {  
  5.     // ......  
  6. }  

服务消费方注解:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. import com.alibaba.dubbo.config.annotation.Reference;  
  2. import org.springframework.stereotype.Component;  
  3.   
  4. @Component  
  5. public class BarAction {  
  6.   
  7.     @Reference(version="1.0.0")  
  8.     private FooService fooService;  
  9.   
  10. }  
服务消费方配置:
[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <!-- 扫描注解包路径,多个包用逗号分隔,不填pacakge表示扫描当前ApplicationContext中所有的类 -->  
  2. <dubbo:annotation package="com.foo.bar.action" />  

通过官方的例子,就可以看出Dubbo使用xml配置<dubbo:annotation /> 来开启注解配置,并提供 com.alibaba.dubbo.config.annotation.Service注解进行服务注册,提供com.alibaba.dubbo.config.annotation.Reference注解进行服务注入。

2.实现机制

可以看出,内部机制都是依托于<dubbo:annotation />标签。 通过源码分析,Dubbo对于Spring xml解析处理由com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler提供:
DubboNamespaceHandler.java

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package com.alibaba.dubbo.config.spring.schema;  
  2.   
  3. import org.springframework.beans.factory.xml.NamespaceHandlerSupport;  
  4.   
  5. import com.alibaba.dubbo.common.Version;  
  6. import com.alibaba.dubbo.config.ApplicationConfig;  
  7. import com.alibaba.dubbo.config.ConsumerConfig;  
  8. import com.alibaba.dubbo.config.ModuleConfig;  
  9. import com.alibaba.dubbo.config.MonitorConfig;  
  10. import com.alibaba.dubbo.config.ProtocolConfig;  
  11. import com.alibaba.dubbo.config.ProviderConfig;  
  12. import com.alibaba.dubbo.config.RegistryConfig;  
  13. import com.alibaba.dubbo.config.spring.AnnotationBean;  
  14. import com.alibaba.dubbo.config.spring.ReferenceBean;  
  15. import com.alibaba.dubbo.config.spring.ServiceBean;  
  16.   
  17. /** 
  18.  * DubboNamespaceHandler 
  19.  *  
  20.  * @author william.liangf 
  21.  * @export 
  22.  */  
  23. public class DubboNamespaceHandler extends NamespaceHandlerSupport {  
  24.   
  25.     static {  
  26.         Version.checkDuplicate(DubboNamespaceHandler.class);  
  27.     }  
  28.   
  29.     public void init() {  
  30.         registerBeanDefinitionParser("application"new DubboBeanDefinitionParser(ApplicationConfig.classtrue));  
  31.         registerBeanDefinitionParser("module"new DubboBeanDefinitionParser(ModuleConfig.classtrue));  
  32.         registerBeanDefinitionParser("registry"new DubboBeanDefinitionParser(RegistryConfig.classtrue));  
  33.         registerBeanDefinitionParser("monitor"new DubboBeanDefinitionParser(MonitorConfig.classtrue));  
  34.         registerBeanDefinitionParser("provider"new DubboBeanDefinitionParser(ProviderConfig.classtrue));  
  35.         registerBeanDefinitionParser("consumer"new DubboBeanDefinitionParser(ConsumerConfig.classtrue));  
  36.         registerBeanDefinitionParser("protocol"new DubboBeanDefinitionParser(ProtocolConfig.classtrue));  
  37.         registerBeanDefinitionParser("service"new DubboBeanDefinitionParser(ServiceBean.classtrue));  
  38.         registerBeanDefinitionParser("reference"new DubboBeanDefinitionParser(ReferenceBean.classfalse));  
  39.         registerBeanDefinitionParser("annotation"new DubboBeanDefinitionParser(AnnotationBean.classtrue));  
  40.     }  
  41.   
  42. }  
通过上面的代码可以很直观的发现,<dubbo:annotation />标签实际是由com.alibaba.dubbo.config.spring.schema.DubboBeanDefinitionParser解析:
DubboBeanDefinitionParser.java
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * AbstractBeanDefinitionParser 
  3.  *  
  4.  * @author william.liangf 
  5.  * @export 
  6.  */  
  7. public class DubboBeanDefinitionParser implements BeanDefinitionParser {  
  8.   
  9.     private static final Logger logger = LoggerFactory.getLogger(DubboBeanDefinitionParser.class);  
  10.   
  11.     private final Class<?> beanClass;  
  12.   
  13.     private final boolean required;  
  14.   
  15.     public DubboBeanDefinitionParser(Class<?> beanClass, boolean required) {  
  16.         this.beanClass = beanClass;  
  17.         this.required = required;  
  18.     }  
  19.   
  20.     public BeanDefinition parse(Element element, ParserContext parserContext) {  
  21.         return parse(element, parserContext, beanClass, required);  
  22.     }  
  23.   
  24.     @SuppressWarnings("unchecked")  
  25.     private static BeanDefinition parse(Element element, ParserContext parserContext, Class<?> beanClass, boolean required) {  
  26.         //略  
  27.     }  
可以看到这个类实现了Spring的org.springframework.beans.factory.xml.BeanDefinitionParser接口,从而完成Spring Bean的解析工作。
而registerBeanDefinitionParser("annotation", new DubboBeanDefinitionParser(AnnotationBean.class, true));就是将<dubbo:annotation />标签,解析成com.alibaba.dubbo.config.spring.AnnotationBean并注册到Spring中。

3.AnnotationBean分析

先来看看源码:
AnnotationBean.java

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package com.alibaba.dubbo.config.spring;  
  2.   
  3.   
  4.   
  5. /** 
  6.  * AnnotationBean 
  7.  *  
  8.  * @author william.liangf 
  9.  * @export 
  10.  */  
  11. public class AnnotationBean extends AbstractConfig implements DisposableBean, BeanFactoryPostProcessor, BeanPostProcessor, ApplicationContextAware {  
  12.   
  13.     private static final long serialVersionUID = -7582802454287589552L;  
  14.   
  15.     private static final Logger logger = LoggerFactory.getLogger(Logger.class);  
  16.   
  17.     private String annotationPackage;  
  18.   
  19.     private String[] annotationPackages;  
  20.   
  21.     private final Set<ServiceConfig<?>> serviceConfigs = new ConcurrentHashSet<ServiceConfig<?>>();  
  22.   
  23.     private final ConcurrentMap<String, ReferenceBean<?>> referenceConfigs = new ConcurrentHashMap<String, ReferenceBean<?>>();  
  24.   
  25.     public String getPackage() {  
  26.         return annotationPackage;  
  27.     }  
  28.   
  29.     public void setPackage(String annotationPackage) {  
  30.         this.annotationPackage = annotationPackage;  
  31.         this.annotationPackages = (annotationPackage == null || annotationPackage.length() == 0) ? null  
  32.                 : Constants.COMMA_SPLIT_PATTERN.split(annotationPackage);  
  33.     }  
  34.   
  35.     private ApplicationContext applicationContext;  
  36.   
  37.     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {  
  38.         this.applicationContext = applicationContext;  
  39.     }  
  40.   
  41.     public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)  
  42.             throws BeansException {  
  43.         if (annotationPackage == null || annotationPackage.length() == 0) {  
  44.             return;  
  45.         }  
  46.         if (beanFactory instanceof BeanDefinitionRegistry) {  
  47.             try {  
  48.                 // init scanner  
  49.                 Class<?> scannerClass = ReflectUtils.forName("org.springframework.context.annotation.ClassPathBeanDefinitionScanner");  
  50.                 Object scanner = scannerClass.getConstructor(new Class<?>[] {BeanDefinitionRegistry.classboolean.class}).newInstance(new Object[] {(BeanDefinitionRegistry) beanFactory, true});  
  51.                 // add filter  
  52.                 Class<?> filterClass = ReflectUtils.forName("org.springframework.core.type.filter.AnnotationTypeFilter");  
  53.                 Object filter = filterClass.getConstructor(Class.class).newInstance(Service.class);  
  54.                 Method addIncludeFilter = scannerClass.getMethod("addIncludeFilter", ReflectUtils.forName("org.springframework.core.type.filter.TypeFilter"));  
  55.                 addIncludeFilter.invoke(scanner, filter);  
  56.                 // scan packages  
  57.                 String[] packages = Constants.COMMA_SPLIT_PATTERN.split(annotationPackage);  
  58.                 Method scan = scannerClass.getMethod("scan"new Class<?>[]{String[].class});  
  59.                 scan.invoke(scanner, new Object[] {packages});  
  60.             } catch (Throwable e) {  
  61.                 // spring 2.0  
  62.             }  
  63.         }  
  64.     }  
  65.   
  66.     public void destroy() throws Exception {  
  67.         for (ServiceConfig<?> serviceConfig : serviceConfigs) {  
  68.             try {  
  69.                 serviceConfig.unexport();  
  70.             } catch (Throwable e) {  
  71.                 logger.error(e.getMessage(), e);  
  72.             }  
  73.         }  
  74.         for (ReferenceConfig<?> referenceConfig : referenceConfigs.values()) {  
  75.             try {  
  76.                 referenceConfig.destroy();  
  77.             } catch (Throwable e) {  
  78.                 logger.error(e.getMessage(), e);  
  79.             }  
  80.         }  
  81.     }  
  82.   
  83.     public Object postProcessAfterInitialization(Object bean, String beanName)  
  84.             throws BeansException {  
  85.         if (! isMatchPackage(bean)) {  
  86.             return bean;  
  87.         }  
  88.         Service service = bean.getClass().getAnnotation(Service.class);  
  89.         if (service != null) {  
  90.             ServiceBean<Object> serviceConfig = new ServiceBean<Object>(service);  
  91.             if (void.class.equals(service.interfaceClass())  
  92.                     && "".equals(service.interfaceName())) {  
  93.                 if (bean.getClass().getInterfaces().length > 0) {  
  94.                     serviceConfig.setInterface(bean.getClass().getInterfaces()[0]);  
  95.                 } else {  
  96.                     throw new IllegalStateException("Failed to export remote service class " + bean.getClass().getName() + ", cause: The @Service undefined interfaceClass or interfaceName, and the service class unimplemented any interfaces.");  
  97.                 }  
  98.             }  
  99.             if (applicationContext != null) {  
  100.                 serviceConfig.setApplicationContext(applicationContext);  
  101.                 if (service.registry() != null && service.registry().length > 0) {  
  102.                     List<RegistryConfig> registryConfigs = new ArrayList<RegistryConfig>();  
  103.                     for (String registryId : service.registry()) {  
  104.                         if (registryId != null && registryId.length() > 0) {  
  105.                             registryConfigs.add((RegistryConfig)applicationContext.getBean(registryId, RegistryConfig.class));  
  106.                         }  
  107.                     }  
  108.                     serviceConfig.setRegistries(registryConfigs);  
  109.                 }  
  110.                 if (service.provider() != null && service.provider().length() > 0) {  
  111.                     serviceConfig.setProvider((ProviderConfig)applicationContext.getBean(service.provider(),ProviderConfig.class));  
  112.                 }  
  113.                 if (service.monitor() != null && service.monitor().length() > 0) {  
  114.                     serviceConfig.setMonitor((MonitorConfig)applicationContext.getBean(service.monitor(), MonitorConfig.class));  
  115.                 }  
  116.                 if (service.application() != null && service.application().length() > 0) {  
  117.                     serviceConfig.setApplication((ApplicationConfig)applicationContext.getBean(service.application(), ApplicationConfig.class));  
  118.                 }  
  119.                 if (service.module() != null && service.module().length() > 0) {  
  120.                     serviceConfig.setModule((ModuleConfig)applicationContext.getBean(service.module(), ModuleConfig.class));  
  121.                 }  
  122.                 if (service.provider() != null && service.provider().length() > 0) {  
  123.                     serviceConfig.setProvider((ProviderConfig)applicationContext.getBean(service.provider(), ProviderConfig.class));  
  124.                 } else {  
  125.   
  126.                 }  
  127.                 if (service.protocol() != null && service.protocol().length > 0) {  
  128.                     List<ProtocolConfig> protocolConfigs = new ArrayList<ProtocolConfig>();  
  129.                     for (String protocolId : service.registry()) {  
  130.                         if (protocolId != null && protocolId.length() > 0) {  
  131.                             protocolConfigs.add((ProtocolConfig)applicationContext.getBean(protocolId, ProtocolConfig.class));  
  132.                         }  
  133.                     }  
  134.                     serviceConfig.setProtocols(protocolConfigs);  
  135.                 }  
  136.                 try {  
  137.                     serviceConfig.afterPropertiesSet();  
  138.                 } catch (RuntimeException e) {  
  139.                     throw (RuntimeException) e;  
  140.                 } catch (Exception e) {  
  141.                     throw new IllegalStateException(e.getMessage(), e);  
  142.                 }  
  143.             }  
  144.             serviceConfig.setRef(bean);  
  145.             serviceConfigs.add(serviceConfig);  
  146.             serviceConfig.export();  
  147.         }  
  148.         return bean;  
  149.     }  
  150.   
  151.     public Object postProcessBeforeInitialization(Object bean, String beanName)  
  152.             throws BeansException {  
  153.         if (! isMatchPackage(bean)) {  
  154.             return bean;  
  155.         }  
  156.         Method[] methods = bean.getClass().getMethods();  
  157.         for (Method method : methods) {  
  158.             String name = method.getName();  
  159.             if (name.length() > 3 && name.startsWith("set")  
  160.                     && method.getParameterTypes().length == 1  
  161.                     && Modifier.isPublic(method.getModifiers())  
  162.                     && ! Modifier.isStatic(method.getModifiers())) {  
  163.                 try {  
  164.                     Reference reference = method.getAnnotation(Reference.class);  
  165.                     if (reference != null) {  
  166.                         Object value = refer(reference, method.getParameterTypes()[0]);  
  167.                         if (value != null) {  
  168.                             method.invoke(bean, new Object[] {  });  
  169.                         }  
  170.                     }  
  171.                 } catch (Throwable e) {  
  172.                     logger.error("Failed to init remote service reference at method " + name + " in class " + bean.getClass().getName() + ", cause: " + e.getMessage(), e);  
  173.                 }  
  174.             }  
  175.         }  
  176.         Field[] fields = bean.getClass().getDeclaredFields();  
  177.         for (Field field : fields) {  
  178.             try {  
  179.                 if (! field.isAccessible()) {  
  180.                     field.setAccessible(true);  
  181.                 }  
  182.                 Reference reference = field.getAnnotation(Reference.class);  
  183.                 if (reference != null) {  
  184.                     Object value = refer(reference, field.getType());  
  185.                     if (value != null) {  
  186.                         field.set(bean, value);  
  187.                     }  
  188.                 }  
  189.             } catch (Throwable e) {  
  190.                 logger.error("Failed to init remote service reference at filed " + field.getName() + " in class " + bean.getClass().getName() + ", cause: " + e.getMessage(), e);  
  191.             }  
  192.         }  
  193.         return bean;  
  194.     }  
  195.   
  196.     private Object refer(Reference reference, Class<?> referenceClass) { //method.getParameterTypes()[0]  
  197.         String interfaceName;  
  198.         if (! "".equals(reference.interfaceName())) {  
  199.             interfaceName = reference.interfaceName();  
  200.         } else if (! void.class.equals(reference.interfaceClass())) {  
  201.             interfaceName = reference.interfaceClass().getName();  
  202.         } else if (referenceClass.isInterface()) {  
  203.             interfaceName = referenceClass.getName();  
  204.         } else {  
  205.             throw new IllegalStateException("The @Reference undefined interfaceClass or interfaceName, and the property type " + referenceClass.getName() + " is not a interface.");  
  206.         }  
  207.         String key = reference.group() + "/" + interfaceName + ":" + reference.version();  
  208.         ReferenceBean<?> referenceConfig = referenceConfigs.get(key);  
  209.         if (referenceConfig == null) {  
  210.             referenceConfig = new ReferenceBean<Object>(reference);  
  211.             if (void.class.equals(reference.interfaceClass())  
  212.                     && "".equals(reference.interfaceName())  
  213.                     && referenceClass.isInterface()) {  
  214.                 referenceConfig.setInterface(referenceClass);  
  215.             }  
  216.             if (applicationContext != null) {  
  217.                 referenceConfig.setApplicationContext(applicationContext);  
  218.                 if (reference.registry() != null && reference.registry().length > 0) {  
  219.                     List<RegistryConfig> registryConfigs = new ArrayList<RegistryConfig>();  
  220.                     for (String registryId : reference.registry()) {  
  221.                         if (registryId != null && registryId.length() > 0) {  
  222.                             registryConfigs.add((RegistryConfig)applicationContext.getBean(registryId, RegistryConfig.class));  
  223.                         }  
  224.                     }  
  225.                     referenceConfig.setRegistries(registryConfigs);  
  226.                 }  
  227.                 if (reference.consumer() != null && reference.consumer().length() > 0) {  
  228.                     referenceConfig.setConsumer((ConsumerConfig)applicationContext.getBean(reference.consumer(), ConsumerConfig.class));  
  229.                 }  
  230.                 if (reference.monitor() != null && reference.monitor().length() > 0) {  
  231.                     referenceConfig.setMonitor((MonitorConfig)applicationContext.getBean(reference.monitor(), MonitorConfig.class));  
  232.                 }  
  233.                 if (reference.application() != null && reference.application().length() > 0) {  
  234.                     referenceConfig.setApplication((ApplicationConfig)applicationContext.getBean(reference.application(), ApplicationConfig.class));  
  235.                 }  
  236.                 if (reference.module() != null && reference.module().length() > 0) {  
  237.                     referenceConfig.setModule((ModuleConfig)applicationContext.getBean(reference.module(), ModuleConfig.class));  
  238.                 }  
  239.                 if (reference.consumer() != null && reference.consumer().length() > 0) {  
  240.                     referenceConfig.setConsumer((ConsumerConfig)applicationContext.getBean(reference.consumer(), ConsumerConfig.class));  
  241.                 }  
  242.                 try {  
  243.                     referenceConfig.afterPropertiesSet();  
  244.                 } catch (RuntimeException e) {  
  245.                     throw (RuntimeException) e;  
  246.                 } catch (Exception e) {  
  247.                     throw new IllegalStateException(e.getMessage(), e);  
  248.                 }  
  249.             }  
  250.             referenceConfigs.putIfAbsent(key, referenceConfig);  
  251.             referenceConfig = referenceConfigs.get(key);  
  252.         }  
  253.         return referenceConfig.get();  
  254.     }  
  255.   
  256.     private boolean isMatchPackage(Object bean) {  
  257.         if (annotationPackages == null || annotationPackages.length == 0) {  
  258.             return true;  
  259.         }  
  260.         String beanClassName = bean.getClass().getName();  
  261.         for (String pkg : annotationPackages) {  
  262.             if (beanClassName.startsWith(pkg)) {  
  263.                 return true;  
  264.             }  
  265.         }  
  266.         return false;  
  267.     }  
  268.   
  269. }  
这个AnnotationBean实现了几个Spring生命周期接口,从而完成Dubbo整合Spring 的操作。
org.springframework.beans.factory.config.BeanFactoryPostProcessor
先来看看Spring文档中的介绍:
[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. BeanFactoryPostProcessor operates on the bean configuration metadata; that is, the Spring IoC container allows a BeanFactoryPostProcessor to read the configuration metadata and potentially change it before the container instantiates any beans other than BeanFactoryPostProcessors.  
  2. BeanFactoryPostProcessor可以用于在Spring IoC容器实例化Bean之前,对Spring Bean配置信息进行一些操作  
通过Spring文档,可以清楚这个接口的功能,那再来看看Dubbo的AnnotationBean是如何实现这个接口的:
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)  
  2.             throws BeansException {  
  3.     if (annotationPackage == null || annotationPackage.length() == 0) {  
  4.         return;  
  5.     }  
  6.     if (beanFactory instanceof BeanDefinitionRegistry) {  
  7.         try {  
  8.             // init scanner  
  9.             Class<?> scannerClass = ReflectUtils.forName("org.springframework.context.annotation.ClassPathBeanDefinitionScanner");  
  10.             Object scanner = scannerClass.getConstructor(new Class<?>[] {BeanDefinitionRegistry.classboolean.class}).newInstance(new Object[] {(BeanDefinitionRegistry) beanFactory, true});  
  11.             // add filter  
  12.             Class<?> filterClass = ReflectUtils.forName("org.springframework.core.type.filter.AnnotationTypeFilter");  
  13.             Object filter = filterClass.getConstructor(Class.class).newInstance(Service.class);  
  14.             Method addIncludeFilter = scannerClass.getMethod("addIncludeFilter", ReflectUtils.forName("org.springframework.core.type.filter.TypeFilter"));  
  15.             addIncludeFilter.invoke(scanner, filter);  
  16.             // scan packages  
  17.             String[] packages = Constants.COMMA_SPLIT_PATTERN.split(annotationPackage);  
  18.             Method scan = scannerClass.getMethod("scan"new Class<?>[]{String[].class});  
  19.             scan.invoke(scanner, new Object[] {packages});  
  20.         } catch (Throwable e) {  
  21.             // spring 2.0  
  22.         }  
  23.     }  
  24. }  
源码中已经标出了,Dubbo做了以下几件事:

  • 增加了一个class扫描器,用于处理Dubbo服务类的扫描
  • 增加过滤器,只扫描带有com.alibaba.dubbo.config.annotation.Service注解的class
  • 指定扫描的包,对应这<dubbo:annotation package="com.foo.bar.service" />标签中的package属性。

这个扫描器,就是将那些带有com.alibaba.dubbo.config.annotation.Service注解的class纳入Spring容器中,而这些Dubbo服务类上不需要单独加上Spring的注解,也不需要额外配置Spring Bean定义。
org.springframework.beans.factory.DisposableBean
再来看看这个接口,还是先看看Spring文档:

[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. Implementing the org.springframework.beans.factory.DisposableBean interface allows a bean to get a callback when the container containing it is destroyed. The DisposableBean interface specifies a single method:void destroy() throws Exception;  
这个接口实际上就是当Spring容器要销毁时的一个回调接口。
那再来看看Dubbo是如何实现的:
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public void destroy() throws Exception {  
  2.     for (ServiceConfig<?> serviceConfig : serviceConfigs) {  
  3.         try {  
  4.             serviceConfig.unexport();  
  5.         } catch (Throwable e) {  
  6.             logger.error(e.getMessage(), e);  
  7.         }  
  8.     }  
  9.     for (ReferenceConfig<?> referenceConfig : referenceConfigs.values()) {  
  10.         try {  
  11.             referenceConfig.destroy();  
  12.         } catch (Throwable e) {  
  13.             logger.error(e.getMessage(), e);  
  14.         }  
  15.     }  
  16. }  
也比较简单,实际上就是当Spring容器销毁时,对Dubbo服务进行反注册操作。
org.springframework.beans.factory.config.BeanPostProcessor
最后来看看这个接口,照例先看看Spring文档:
[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. The BeanPostProcessor interface defines callback methods that you can implement to provide your own (or override the container’s default) instantiation logic, dependency-resolution logic, and so forth. If you want to implement some custom logic after the Spring container finishes instantiating, configuring, and initializing a bean, you can plug in one or more BeanPostProcessor implementations.  
这个接口也是一个回调接口,只是回调时机不同,它发生在Spring容器初始化过程中,Bean实例化前后之时。也可以理解为Spring容器初始化完成后,Bean实例化前后但还没有给容器外使用前。
再来看看Dubbbo在这个时间点上做了什么:
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public Object postProcessBeforeInitialization(Object bean, String beanName)  
  2.             throws BeansException {  
  3.     if (! isMatchPackage(bean)) {  
  4.         return bean;  
  5.     }  
  6.     Method[] methods = bean.getClass().getMethods();  
  7.     for (Method method : methods) {  
  8.         String name = method.getName();  
  9.         if (name.length() > 3 && name.startsWith("set")  
  10.                 && method.getParameterTypes().length == 1  
  11.                 && Modifier.isPublic(method.getModifiers())  
  12.                 && ! Modifier.isStatic(method.getModifiers())) {  
  13.             try {  
  14.                 Reference reference = method.getAnnotation(Reference.class);  
  15.                 if (reference != null) {  
  16.                     Object value = refer(reference, method.getParameterTypes()[0]);  
  17.                     if (value != null) {  
  18.                         method.invoke(bean, new Object[] {  });  
  19.                     }  
  20.                 }  
  21.             } catch (Throwable e) {  
  22.                 logger.error("Failed to init remote service reference at method " + name + " in class " + bean.getClass().getName() + ", cause: " + e.getMessage(), e);  
  23.             }  
  24.         }  
  25.     }  
  26.     Field[] fields = bean.getClass().getDeclaredFields();  
  27.     for (Field field : fields) {  
  28.         try {  
  29.             if (! field.isAccessible()) {  
  30.                 field.setAccessible(true);  
  31.             }  
  32.             Reference reference = field.getAnnotation(Reference.class);  
  33.             if (reference != null) {  
  34.                 Object value = refer(reference, field.getType());  
  35.                 if (value != null) {  
  36.                     field.set(bean, value);  
  37.                 }  
  38.             }  
  39.         } catch (Throwable e) {  
  40.             logger.error("Failed to init remote service reference at filed " + field.getName() + " in class " + bean.getClass().getName() + ", cause: " + e.getMessage(), e);  
  41.         }  
  42.     }  
  43.     return bean;  
  44. }  
postProcessBeforeInitialization方法,顾名思义,发生Bean实例化之前。 通过源码就可以发现,主要用于处理Bean中的com.alibaba.dubbo.config.annotation.Reference注解,从而让Dubbo服务能够注入到Bean中。期间利用JAVA反射机制对Bean的方法和属性进行注入。
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public Object postProcessAfterInitialization(Object bean, String beanName)  
  2.             throws BeansException {  
  3.     if (! isMatchPackage(bean)) {  
  4.         return bean;  
  5.     }  
  6.     Service service = bean.getClass().getAnnotation(Service.class);  
  7.     if (service != null) {  
  8.         ServiceBean<Object> serviceConfig = new ServiceBean<Object>(service);  
  9.         if (void.class.equals(service.interfaceClass())  
  10.                 && "".equals(service.interfaceName())) {  
  11.             if (bean.getClass().getInterfaces().length > 0) {  
  12.                 serviceConfig.setInterface(bean.getClass().getInterfaces()[0]);  
  13.             } else {  
  14.                 throw new IllegalStateException("Failed to export remote service class " + bean.getClass().getName() + ", cause: The @Service undefined interfaceClass or interfaceName, and the service class unimplemented any interfaces.");  
  15.             }  
  16.         }  
  17.         if (applicationContext != null) {  
  18.             serviceConfig.setApplicationContext(applicationContext);  
  19.             if (service.registry() != null && service.registry().length > 0) {  
  20.                 List<RegistryConfig> registryConfigs = new ArrayList<RegistryConfig>();  
  21.                 for (String registryId : service.registry()) {  
  22.                     if (registryId != null && registryId.length() > 0) {  
  23.                         registryConfigs.add((RegistryConfig)applicationContext.getBean(registryId, RegistryConfig.class));  
  24.                     }  
  25.                 }  
  26.                 serviceConfig.setRegistries(registryConfigs);  
  27.             }  
  28.             if (service.provider() != null && service.provider().length() > 0) {  
  29.                 serviceConfig.setProvider((ProviderConfig)applicationContext.getBean(service.provider(),ProviderConfig.class));  
  30.             }  
  31.             if (service.monitor() != null && service.monitor().length() > 0) {  
  32.                 serviceConfig.setMonitor((MonitorConfig)applicationContext.getBean(service.monitor(), MonitorConfig.class));  
  33.             }  
  34.             if (service.application() != null && service.application().length() > 0) {  
  35.                 serviceConfig.setApplication((ApplicationConfig)applicationContext.getBean(service.application(), ApplicationConfig.class));  
  36.             }  
  37.             if (service.module() != null && service.module().length() > 0) {  
  38.                 serviceConfig.setModule((ModuleConfig)applicationContext.getBean(service.module(), ModuleConfig.class));  
  39.             }  
  40.             if (service.provider() != null && service.provider().length() > 0) {  
  41.                 serviceConfig.setProvider((ProviderConfig)applicationContext.getBean(service.provider(), ProviderConfig.class));  
  42.             } else {  
  43.   
  44.             }  
  45.             if (service.protocol() != null && service.protocol().length > 0) {  
  46.                 List<ProtocolConfig> protocolConfigs = new ArrayList<ProtocolConfig>();  
  47.                 for (String protocolId : service.registry()) {  
  48.                     if (protocolId != null && protocolId.length() > 0) {  
  49.                         protocolConfigs.add((ProtocolConfig)applicationContext.getBean(protocolId, ProtocolConfig.class));  
  50.                     }  
  51.                 }  
  52.                 serviceConfig.setProtocols(protocolConfigs);  
  53.             }  
  54.             try {  
  55.                 serviceConfig.afterPropertiesSet();  
  56.             } catch (RuntimeException e) {  
  57.                 throw (RuntimeException) e;  
  58.             } catch (Exception e) {  
  59.                 throw new IllegalStateException(e.getMessage(), e);  
  60.             }  
  61.         }  
  62.         serviceConfig.setRef(bean);  
  63.         serviceConfigs.add(serviceConfig);  
  64.         serviceConfig.export();  
  65.     }  
  66.     return bean;  
  67. }  
postProcessAfterInitialization方法,同样从名字就能看出,其发生在Bean实例化之后。 通过源码就能发现,其作用就是将带有com.alibaba.dubbo.config.annotation.Service注解的Bean自动注册到Dubbo的注册中心,完成服务注册动作。

4.问题分析

通过上面的分析,对于Dubbo注解方式整合到Spring已经比较清楚了。 而在使用高版本Spring时,上面的AnnotationBean会出现一些问题。
问题主要集中在:

  • Dubbo的注解Service有时不能进行服务注册
  • Dubbo的注解Reference有时不能注入服务

从代码分析问题主要集中在postProcessBeforeInitialization和postProcessAfterInitialization方法上。

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. Service service = bean.getClass().getAnnotation(Service.class);  
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. Method[] methods = bean.getClass().getMethods();  
方法中都是利用Java反射来处理Bean的Class。
众所周知,Spring有两大利器IOC和AOP。在早期AOP基本都是利用JAVA动态代理实现的,而随着字节码技术的发展,现在Spring已经基本以ASM为代表的字节码增强框架为基础实现AOP,以及一些Bean的代理。
有兴趣的小伙伴可以打开spring-core-x.x.x.jar,会发现spring已经内嵌了asm以及cglib (org.springframework.asm)(org.springframework.cglib)
而在Spring环境中大量出现经过Cglib增强的Class,这些Class不再是简单的基于接口的代理机制了,其内部大量使用委派方式,以及访问器模式。最常见的就是Spring的事物,对于使用了@Transactional的Bean,都是以这种方式来增加事物处理能力的。
那基于这种方式扩展的Class,再通过反射getClass得到的是经过cglib改写后的class。在这些class上getAnnotation以及getMethods都不再是预期中的结果了。
所以,这也也就导致了上面罗列的两个问题。

5. 解决方案

经过对问题的分析,可以发现,问题主要是集中在Dubbo获取Bean的class上。
在Spring中,提供了很多Utils类。其中org.springframework.aop.support.AopUtils就可以用来对Aop代理的类进行操作的API。
于是,我们可以利用这个类来完成Class的获取。

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. private Class<?> getBeanClass(Object bean) {  
  2.     Class<?> clazz = bean.getClass();  
  3.     if (AopUtils.isAopProxy(bean)) {  
  4.         clazz = AopUtils.getTargetClass(bean);  
  5.     }  
  6.     return clazz;  
  7. }  
这样获取Class就可以这样:
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. Class<?> clazz = getBeanClass(bean);  
  2. Service service = clazz.getAnnotation(Service.class);  
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. Class<?> clazz = getBeanClass(bean);  
修改后完整的代码:
AnnotationBean.java
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /* 
  2.  * Copyright 1999-2012 Alibaba Group. 
  3.  *   
  4.  * Licensed under the Apache License, Version 2.0 (the "License"); 
  5.  * you may not use this file except in compliance with the License. 
  6.  * You may obtain a copy of the License at 
  7.  *   
  8.  *      http://www.apache.org/licenses/LICENSE-2.0 
  9.  *   
  10.  * Unless required by applicable law or agreed to in writing, software 
  11.  * distributed under the License is distributed on an "AS IS" BASIS, 
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  13.  * See the License for the specific language governing permissions and 
  14.  * limitations under the License. 
  15.  */  
  16. package com.roc.dubbo.config.spring;  
  17.   
  18. import java.lang.reflect.Field;  
  19. import java.lang.reflect.Method;  
  20. import java.lang.reflect.Modifier;  
  21. import java.util.ArrayList;  
  22. import java.util.List;  
  23. import java.util.Set;  
  24. import java.util.concurrent.ConcurrentHashMap;  
  25. import java.util.concurrent.ConcurrentMap;  
  26.   
  27. import org.springframework.aop.support.AopUtils;  
  28. import org.springframework.beans.BeansException;  
  29. import org.springframework.beans.factory.DisposableBean;  
  30. import org.springframework.beans.factory.config.BeanFactoryPostProcessor;  
  31. import org.springframework.beans.factory.config.BeanPostProcessor;  
  32. import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;  
  33. import org.springframework.beans.factory.support.BeanDefinitionRegistry;  
  34. import org.springframework.context.ApplicationContext;  
  35. import org.springframework.context.ApplicationContextAware;  
  36.   
  37. import com.alibaba.dubbo.common.Constants;  
  38. import com.alibaba.dubbo.common.logger.Logger;  
  39. import com.alibaba.dubbo.common.logger.LoggerFactory;  
  40. import com.alibaba.dubbo.common.utils.ConcurrentHashSet;  
  41. import com.alibaba.dubbo.common.utils.ReflectUtils;  
  42. import com.alibaba.dubbo.config.AbstractConfig;  
  43. import com.alibaba.dubbo.config.ApplicationConfig;  
  44. import com.alibaba.dubbo.config.ConsumerConfig;  
  45. import com.alibaba.dubbo.config.ModuleConfig;  
  46. import com.alibaba.dubbo.config.MonitorConfig;  
  47. import com.alibaba.dubbo.config.ProtocolConfig;  
  48. import com.alibaba.dubbo.config.ProviderConfig;  
  49. import com.alibaba.dubbo.config.ReferenceConfig;  
  50. import com.alibaba.dubbo.config.RegistryConfig;  
  51. import com.alibaba.dubbo.config.ServiceConfig;  
  52. import com.alibaba.dubbo.config.annotation.Reference;  
  53. import com.alibaba.dubbo.config.annotation.Service;  
  54. import com.alibaba.dubbo.config.spring.ReferenceBean;  
  55. import com.alibaba.dubbo.config.spring.ServiceBean;  
  56.   
  57. /** 
  58.  * AnnotationBean 
  59.  *  
  60.  * @author william.liangf 
  61.  * @export 
  62.  *  
  63.  *         >>>修复@com.alibaba.dubbo.config.annotation.Service 
  64.  *         与Spring @Transactional 冲突 
  65.  */  
  66. public class AnnotationBean extends AbstractConfig  
  67.         implements DisposableBean, BeanFactoryPostProcessor, BeanPostProcessor, ApplicationContextAware {  
  68.   
  69.     private static final long serialVersionUID = -7582802454287589552L;  
  70.   
  71.     private static final Logger logger = LoggerFactory.getLogger(Logger.class);  
  72.   
  73.     private String annotationPackage;  
  74.   
  75.     private String[] annotationPackages;  
  76.   
  77.     private final Set<ServiceConfig<?>> serviceConfigs = new ConcurrentHashSet<ServiceConfig<?>>();  
  78.   
  79.     private final ConcurrentMap<String, ReferenceBean<?>> referenceConfigs = new ConcurrentHashMap<String, ReferenceBean<?>>();  
  80.   
  81.     public String getPackage() {  
  82.         return annotationPackage;  
  83.     }  
  84.   
  85.     public void setPackage(String annotationPackage) {  
  86.         this.annotationPackage = annotationPackage;  
  87.         this.annotationPackages = (annotationPackage == null || annotationPackage.length() == 0) ? null  
  88.                 : Constants.COMMA_SPLIT_PATTERN.split(annotationPackage);  
  89.     }  
  90.   
  91.     private ApplicationContext applicationContext;  
  92.   
  93.     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {  
  94.         this.applicationContext = applicationContext;  
  95.     }  
  96.   
  97.     public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {  
  98.         if (annotationPackage == null || annotationPackage.length() == 0) {  
  99.             logger.debug("未定义注解扫描包");  
  100.             return;  
  101.         }  
  102.         logger.info("扫描:" + annotationPackage);  
  103.         if (beanFactory instanceof BeanDefinitionRegistry) {  
  104.             try {  
  105.                 // init scanner  
  106.                 Class<?> scannerClass = ReflectUtils  
  107.                         .forName("org.springframework.context.annotation.ClassPathBeanDefinitionScanner");  
  108.                 Object scanner = scannerClass  
  109.                         .getConstructor(new Class<?>[] { BeanDefinitionRegistry.classboolean.class })  
  110.                         .newInstance(new Object[] { (BeanDefinitionRegistry) beanFactory, true });  
  111.                 // add filter  
  112.                 Class<?> filterClass = ReflectUtils  
  113.                         .forName("org.springframework.core.type.filter.AnnotationTypeFilter");  
  114.                 Object filter = filterClass.getConstructor(Class.class).newInstance(Service.class);  
  115.                 Method addIncludeFilter = scannerClass.getMethod("addIncludeFilter",  
  116.                         ReflectUtils.forName("org.springframework.core.type.filter.TypeFilter"));  
  117.                 addIncludeFilter.invoke(scanner, filter);  
  118.                 // scan packages  
  119.                 String[] packages = Constants.COMMA_SPLIT_PATTERN.split(annotationPackage);  
  120.                 Method scan = scannerClass.getMethod("scan"new Class<?>[] { String[].class });  
  121.                 scan.invoke(scanner, new Object[] { packages });  
  122.             } catch (Throwable e) {  
  123.                 // spring 2.0  
  124.             }  
  125.         }  
  126.     }  
  127.   
  128.     public void destroy() throws Exception {  
  129.         for (ServiceConfig<?> serviceConfig : serviceConfigs) {  
  130.             try {  
  131.                 serviceConfig.unexport();  
  132.             } catch (Throwable e) {  
  133.                 logger.error(e.getMessage(), e);  
  134.             }  
  135.         }  
  136.         for (ReferenceConfig<?> referenceConfig : referenceConfigs.values()) {  
  137.             try {  
  138.                 referenceConfig.destroy();  
  139.             } catch (Throwable e) {  
  140.                 logger.error(e.getMessage(), e);  
  141.             }  
  142.         }  
  143.     }  
  144.   
  145.     public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {  
  146.         if (!isMatchPackage(bean)) {  
  147.             return bean;  
  148.         }  
  149.         Class<?> clazz = getBeanClass(bean);  
  150.         Service service = clazz.getAnnotation(Service.class);  
  151.         // >>>>>>>>>>>>>>>>>>  
  152.         if (service != null) {  
  153.             ServiceBean<Object> serviceConfig = new ServiceBean<Object>(service);  
  154.             if (void.class.equals(service.interfaceClass()) && "".equals(service.interfaceName())) {  
  155.                 if (bean.getClass().getInterfaces().length > 0) {  
  156.                     serviceConfig.setInterface(bean.getClass().getInterfaces()[0]);  
  157.                 } else {  
  158.                     throw new IllegalStateException("Failed to export remote service class " + bean.getClass().getName()  
  159.                             + ", cause: The @Service undefined interfaceClass or interfaceName, and the service class unimplemented any interfaces.");  
  160.                 }  
  161.             }  
  162.             if (applicationContext != null) {  
  163.                 serviceConfig.setApplicationContext(applicationContext);  
  164.                 if (service.registry() != null && service.registry().length > 0) {  
  165.                     List<RegistryConfig> registryConfigs = new ArrayList<RegistryConfig>();  
  166.                     for (String registryId : service.registry()) {  
  167.                         if (registryId != null && registryId.length() > 0) {  
  168.                             registryConfigs  
  169.                                     .add((RegistryConfig) applicationContext.getBean(registryId, RegistryConfig.class));  
  170.                         }  
  171.                     }  
  172.                     serviceConfig.setRegistries(registryConfigs);  
  173.                 }  
  174.                 if (service.provider() != null && service.provider().length() > 0) {  
  175.                     serviceConfig.setProvider(  
  176.                             (ProviderConfig) applicationContext.getBean(service.provider(), ProviderConfig.class));  
  177.                 }  
  178.                 if (service.monitor() != null && service.monitor().length() > 0) {  
  179.                     serviceConfig.setMonitor(  
  180.                             (MonitorConfig) applicationContext.getBean(service.monitor(), MonitorConfig.class));  
  181.                 }  
  182.                 if (service.application() != null && service.application().length() > 0) {  
  183.                     serviceConfig.setApplication((ApplicationConfig) applicationContext.getBean(service.application(),  
  184.                             ApplicationConfig.class));  
  185.                 }  
  186.                 if (service.module() != null && service.module().length() > 0) {  
  187.                     serviceConfig  
  188.                             .setModule((ModuleConfig) applicationContext.getBean(service.module(), ModuleConfig.class));  
  189.                 }  
  190.                 if (service.provider() != null && service.provider().length() > 0) {  
  191.                     serviceConfig.setProvider(  
  192.                             (ProviderConfig) applicationContext.getBean(service.provider(), ProviderConfig.class));  
  193.                 } else {  
  194.   
  195.                 }  
  196.                 if (service.protocol() != null && service.protocol().length > 0) {  
  197.                     List<ProtocolConfig> protocolConfigs = new ArrayList<ProtocolConfig>();  
  198.                     for (String protocolId : service.registry()) {  
  199.                         if (protocolId != null && protocolId.length() > 0) {  
  200.                             protocolConfigs  
  201.                                     .add((ProtocolConfig) applicationContext.getBean(protocolId, ProtocolConfig.class));  
  202.                         }  
  203.                     }  
  204.                     serviceConfig.setProtocols(protocolConfigs);  
  205.                 }  
  206.                 try {  
  207.                     serviceConfig.afterPropertiesSet();  
  208.                 } catch (RuntimeException e) {  
  209.                     throw (RuntimeException) e;  
  210.                 } catch (Exception e) {  
  211.                     throw new IllegalStateException(e.getMessage(), e);  
  212.                 }  
  213.             }  
  214.             serviceConfig.setRef(bean);  
  215.             serviceConfigs.add(serviceConfig);  
  216.             serviceConfig.export();  
  217.         }  
  218.         return bean;  
  219.     }  
  220.   
  221.     public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {  
  222.         // logger.debug("扫描bean:"+bean);  
  223.         // System.out.println("扫描bean:"+bean);  
  224.         if (!isMatchPackage(bean)) {  
  225.             return bean;  
  226.         }  
  227.         // >>>>>>>>>>>>>>>>>>>>>>>>  
  228.         Class<?> clazz = getBeanClass(bean);  
  229.         // >>>>>>>>>>>>>>>>>>>>>>>>  
  230.         Method[] methods = clazz.getMethods();  
  231.         for (Method method : methods) {  
  232.             String name = method.getName();  
  233.             if (name.length() > 3 && name.startsWith("set") && method.getParameterTypes().length == 1  
  234.                     && Modifier.isPublic(method.getModifiers()) && !Modifier.isStatic(method.getModifiers())) {  
  235.                 try {  
  236.                     Reference reference = method.getAnnotation(Reference.class);  
  237.                     if (reference != null) {  
  238.                         Object value = refer(reference, method.getParameterTypes()[0]);  
  239.                         if (value != null) {  
  240.                             method.invoke(bean, new Object[] {});  
  241.                         }  
  242.                     }  
  243.                 } catch (Throwable e) {  
  244.                     logger.error("Failed to init remote service reference at method " + name + " in class "  
  245.                             + bean.getClass().getName() + ", cause: " + e.getMessage(), e);  
  246.                 }  
  247.             }  
  248.         }  
  249.         // >>>>>>>>>>>>>>>>>>>>>>>>  
  250.         Field[] fields = clazz.getDeclaredFields();  
  251.         for (Field field : fields) {  
  252.             try {  
  253.                 if (!field.isAccessible()) {  
  254.                     field.setAccessible(true);  
  255.                 }  
  256.                 Reference reference = field.getAnnotation(Reference.class);  
  257.                 if (reference != null) {  
  258.                     Object value = refer(reference, field.getType());  
  259.                     if (value != null) {  
  260.                         field.set(bean, value);  
  261.                     }  
  262.                 }  
  263.             } catch (Throwable e) {  
  264.                 logger.error("Failed to init remote service reference at filed " + field.getName() + " in class "  
  265.                         + bean.getClass().getName() + ", cause: " + e.getMessage(), e);  
  266.             }  
  267.         }  
  268.         return bean;  
  269.     }  
  270.   
  271.     private Object refer(Reference reference, Class<?> referenceClass) { // method.getParameterTypes()[0]  
  272.         String interfaceName;  
  273.         if (!"".equals(reference.interfaceName())) {  
  274.             interfaceName = reference.interfaceName();  
  275.         } else if (!void.class.equals(reference.interfaceClass())) {  
  276.             interfaceName = reference.interfaceClass().getName();  
  277.         } else if (referenceClass.isInterface()) {  
  278.             interfaceName = referenceClass.getName();  
  279.         } else {  
  280.             throw new IllegalStateException(  
  281.                     "The @Reference undefined interfaceClass or interfaceName, and the property type "  
  282.                             + referenceClass.getName() + " is not a interface.");  
  283.         }  
  284.         String key = reference.group() + "/" + interfaceName + ":" + reference.version();  
  285.         ReferenceBean<?> referenceConfig = referenceConfigs.get(key);  
  286.         if (referenceConfig == null) {  
  287.             referenceConfig = new ReferenceBean<Object>(reference);  
  288.             if (void.class.equals(reference.interfaceClass()) && "".equals(reference.interfaceName())  
  289.                     && referenceClass.isInterface()) {  
  290.                 referenceConfig.setInterface(referenceClass);  
  291.             }  
  292.             if (applicationContext != null) {  
  293.                 referenceConfig.setApplicationContext(applicationContext);  
  294.                 if (reference.registry() != null && reference.registry().length > 0) {  
  295.                     List<RegistryConfig> registryConfigs = new ArrayList<RegistryConfig>();  
  296.                     for (String registryId : reference.registry()) {  
  297.                         if (registryId != null && registryId.length() > 0) {  
  298.                             registryConfigs  
  299.                                     .add((RegistryConfig) applicationContext.getBean(registryId, RegistryConfig.class));  
  300.                         }  
  301.                     }  
  302.                     referenceConfig.setRegistries(registryConfigs);  
  303.                 }  
  304.                 if (reference.consumer() != null && reference.consumer().length() > 0) {  
  305.                     referenceConfig.setConsumer(  
  306.                             (ConsumerConfig) applicationContext.getBean(reference.consumer(), ConsumerConfig.class));  
  307.                 }  
  308.                 if (reference.monitor() != null && reference.monitor().length() > 0) {  
  309.                     referenceConfig.setMonitor(  
  310.                             (MonitorConfig) applicationContext.getBean(reference.monitor(), MonitorConfig.class));  
  311.                 }  
  312.                 if (reference.application() != null && reference.application().length() > 0) {  
  313.                     referenceConfig.setApplication((ApplicationConfig) applicationContext  
  314.                             .getBean(reference.application(), ApplicationConfig.class));  
  315.                 }  
  316.                 if (reference.module() != null && reference.module().length() > 0) {  
  317.                     referenceConfig.setModule(  
  318.                             (ModuleConfig) applicationContext.getBean(reference.module(), ModuleConfig.class));  
  319.                 }  
  320.                 if (reference.consumer() != null && reference.consumer().length() > 0) {  
  321.                     referenceConfig.setConsumer(  
  322.                             (ConsumerConfig) applicationContext.getBean(reference.consumer(), ConsumerConfig.class));  
  323.                 }  
  324.                 try {  
  325.                     referenceConfig.afterPropertiesSet();  
  326.                 } catch (RuntimeException e) {  
  327.                     throw (RuntimeException) e;  
  328.                 } catch (Exception e) {  
  329.                     throw new IllegalStateException(e.getMessage(), e);  
  330.                 }  
  331.             }  
  332.             referenceConfigs.putIfAbsent(key, referenceConfig);  
  333.             referenceConfig = referenceConfigs.get(key);  
  334.         }  
  335.         return referenceConfig.get();  
  336.     }  
  337.   
  338.     private boolean isMatchPackage(Object bean) {  
  339.         if (annotationPackages == null || annotationPackages.length == 0) {  
  340.             return true;  
  341.         }  
  342.         Class<?> clazz = getBeanClass(bean);  
  343.         String beanClassName = clazz.getName();  
  344.         for (String pkg : annotationPackages) {  
  345.             if (beanClassName.startsWith(pkg)) {  
  346.                 return true;  
  347.             }  
  348.         }  
  349.         return false;  
  350.     }  
  351.   
  352.     private Class<?> getBeanClass(Object bean) {  
  353.         Class<?> clazz = bean.getClass();  
  354.         if (AopUtils.isAopProxy(bean)) {  
  355.             clazz = AopUtils.getTargetClass(bean);  
  356.         }  
  357.         return clazz;  
  358.     }  
  359.   
  360. }  

6. 整合

同样,我不太赞同自己修改Dubbo源码,然后打包。侵入性太强。 通过前面几节的分析发现,其实只要AnnotationBean能够注册到Spring环境就行。而AnnotationBean无所谓放在哪个jar中。
所以,完全可以把修改后的AnnotationBean打入到自己写的jar中,然后注入Spring环境,以外挂的方式完成修改。
下面示例代码展示了,在Spring Boot中以外挂方式整合:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package com.roc.dubbo.boot.configuration;  
  2.   
  3. import org.apache.logging.log4j.LogManager;  
  4. import org.apache.logging.log4j.Logger;  
  5. import com.roc.dubbo.config.spring.AnnotationBean;  
  6. import org.springframework.boot.autoconfigure.AutoConfigureAfter;  
  7. import org.springframework.context.annotation.Bean;  
  8. import org.springframework.context.annotation.Configuration;  
  9. import org.springframework.context.annotation.Import;  
  10.   
  11. /** 
  12.  * @author liuyazhuang 
  13.  * @date 2017-04-11 00:25:27 
  14.  * @description 
  15.  */  
  16. @Configuration  
  17. @Import(DubboBasicConfiguration.class)  
  18. @AutoConfigureAfter(DubboBasicConfiguration.class)  
  19. public class DubboConfiguration {  
  20.   
  21.     private final Logger logger = LogManager.getLogger(getClass());  
  22.   
  23.     @Bean  
  24.     // @DependsOn("dubboConfiguration")  
  25.     public AnnotationBean dubboAnnotationBean() {  
  26.         AnnotationBean annotationBean = new AnnotationBean();  
  27.         // annotationBean.setApplicationContext(applicationContext);  
  28.         // annotationBean.setPackage(dubboProperties.getAnnotationPackage());  
  29.         // annotationBean.setPackage("com.roc.pay");  
  30.         logger.info("加入自定义" + annotationBean);  
  31.         return annotationBean;  
  32.     }  
  33.   
  34. }  
----------------------------------------------------------------------------------------------------

使用Dubbo时,因为要与4.x版本的spring,所以,我们需要做如下修改。

一,与4.x版本的Spring共存

首先需要排除掉dubbo自带的2.5的Spring,所以我使用下面这个配置,前面都是正常的引用Spring 4.1.6.RELEASE。

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <dependency>  
  2.     <groupId>com.alibaba</groupId>  
  3.     <artifactId>dubbo</artifactId>  
  4.     <version>2.5.3</version>  
  5.     <exclusions>  
  6.         <exclusion>  
  7.             <groupId>org.springframework</groupId>  
  8.             <artifactId>spring</artifactId>  
  9.         </exclusion>  
  10.         <exclusion>  
  11.             <artifactId>netty</artifactId>  
  12.             <groupId>org.jboss.netty</groupId>  
  13.         </exclusion>  
  14.     </exclusions>  
  15. </dependency>  
  16. <dependency>  
  17.     <groupId>org.apache.zookeeper</groupId>  
  18.     <artifactId>zookeeper</artifactId>  
  19.     <version>3.4.6</version>  
  20. </dependency>  
  21. <dependency>  
  22.     <groupId>com.github.sgroschupf</groupId>  
  23.     <artifactId>zkclient</artifactId>  
  24.     <version>0.1</version>  
  25. </dependency>  

二,打包成本地APP

需要使用Shade这个插件来打包,POM配置如下,其中最关键是那两个transformer,保证将spring.handlers和spring.schemas文件能合并起来,否则执行时会报找不到dubbo:application错误,或者说无法处理dubbo:application错,都是因为在缺省的打包模式下,META-INF目录下同名文件是只取第一个,而不会多个合并起来,导致找不到dubbo.xsd以及对应的handler类:

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <plugin>  
  2.     <groupId>org.apache.maven.plugins</groupId>  
  3.     <artifactId>maven-shade-plugin</artifactId>  
  4.     <version>2.4.2</version>  
  5.     <configuration>  
  6.         <transformers>  
  7.             <transformer  
  8.                 implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">  
  9.                 <manifestEntries>  
  10.                     <Main-Class>cn.chinaunicom.woplus.analysis.MongoStatisticServer.App</Main-Class>  
  11.                     <X-Compile-Source-JDK>1.7</X-Compile-Source-JDK>  
  12.                     <X-Compile-Target-JDK>1.7</X-Compile-Target-JDK>  
  13.                 </manifestEntries>  
  14.             </transformer>  
  15.             <transformer  
  16.                 implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">  
  17.                 <resource>META-INF/spring.schemas</resource>  
  18.             </transformer>  
  19.             <transformer  
  20.                 implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">  
  21.                 <resource>META-INF/spring.handlers</resource>  
  22.             </transformer>  
  23.         </transformers>  
  24.     </configuration>  
  25.     <executions>  
  26.         <execution>  
  27.             <phase>package</phase>  
  28.             <goals>  
  29.                 <goal>shade</goal>  
  30.             </goals>  
  31.         </execution>  
  32.     </executions>  
  33. </plugin>  

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值