Spring Dubbo 是我本身写的一个基于spring-boot和dubbo,目的是使用Spring boot的风格来使用dubbo。(便可以了解Spring boot的启动过程又能够学习一下dubbo的框架)git
github: https://github.com/Athlizo/spring-dubbo-parentgithub
码云: https://git.oschina.net/null_584_3382/spring-dubbo-parentspring
有兴趣的朋友能够一块儿交流学习。app
Dubbo启动的时候,是可使用本身的Spring来启动dubbo服务,可是如今是须要把Dubbo启动SpringApplicationContest的逻辑放入到Spring Boot的启动逻辑中去。(主要是针对注解的方式)框架
按照调用的顺序来介绍spring-boot
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> { void initialize(C applicationContext); }
Spring Boot启动的时候,会扫描classpath下的META-INF.spring.factories, 其中有一个配置名为org.springframework.context.ApplicationContextInitializer,配置项为一些实现了ApplicationContextInitializer接口的类的全路径名,这些类就是Spring Boot在启动的时候首先会进行实例化。post
同ApplicationContextInitializer加载方式同样,META-INF.spring.factories中还有另一个配置项org.springframework.context.ApplicationListener,定义在SpringBoot启动的时候会初始化的ApplicationListener。严格来讲ApplicationListener在整个SpringApplicationContext启动的时候都会触发调用逻辑(经过各类不一样事件触发)学习
public interface BeanFactoryPostProcessor { void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException; }
从名字能够看出,这个接口的类主要是针对BeanFactory进行一些操做,和ApplicationContextInitializer实例化的方式不同,这个接口必须在BeanFactory中存在才会在启动中生效,所以,ApplicationContextInitializer中常作的事情就是加入一些BeanFactoryPostProcessor 。spa
public interface BeanPostProcessor { // 先于afterPropertiesSet() 和init-method Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException; Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException; }
若是BeanFactoryPostProcessor针对的是BeanFactory,那么BeanPostProcessor针对就是BeanFactory中的全部bean了。分别提供了Bean初始化以前和bean初始化以后的相关处理。和BeanFactoryPostProcessor同样,也须要在启动中注册到BeanFactory中才会生效,通常经过BeanFactoryPostProcessor 加入。.net
从上面的分析能够看出
注:这里的接入主要是对使用注解的方式。
关键类:com.alibaba.dubbo.config.spring.AnnotationBean 代码逻辑比较简单,这个类实现了BeanFactoryPostProcessor和BeanPostProcessor这2个接口,分别做用:
所以,SpringBoot接入dubbo的关键在于:在完成BeanFactoryPostProcessor调用以前,把AnnotationBean加入到BeanFactory中就能够了
这里不直接使用AnnotationBean,而是另外定义一个类,新类的名字为AnnotationBeanProcessor(为了贴代码方便),做用是同样的,只是修改里面的部分处理逻辑。
代码以下
public class DubboContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { public void initialize(ConfigurableApplicationContext applicationContext) { AnnotationBeanProcessor annotationBeanProcessor= new AnnotationBeanProcessor(${构造参数}); annotationBeanProcessor.setApplicationContext(applicationContext); applicationContext.addBeanFactoryPostProcessor(annotationBeanProcessor); } }
特色——简单暴力
在ApplicationContextInitializer中加入其它的一个BeanFactoryPostProcessor,而后在这个BeanFactoryPostProcessor加入AnnotationBeanProcessor
public class DubboContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { public void initialize(ConfigurableApplicationContext applicationContext) { DubboBeanDefinitionRegistryPostProcessor dubboBeanDefinitionRegistryPostProcessor = new DubboBeanDefinitionRegistryPostProcessor(); applicationContext.addBeanFactoryPostProcessor(dubboBeanDefinitionRegistryPostProcessor); } public class DubboBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor { public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); beanDefinition.setBeanClass(AnnotationBeanProcessor.class); beanDefinition.getConstructorArgumentValues() .addGenericArgumentValue(${构造参数}); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); registry.registerBeanDefinition("annotationBeanProcessor", beanDefinition); } } }
特色: 这样作虽然感受有点绕,可是好处就是能够在其它的一些关键的BeanDefinitionRegistryPostProcessor 后再执行,这样就可使用xxxAware接口,Spring会自动帮咱们注入。能够利用Spring提供的一些便利功能。 虽然利用ApplicationListener也能够作到,可是不推荐
@Import注解中加入ImportBeanDefinitionRegistrar的实现类,实现对bean definition 层面的开发。
public class AnnotationBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { private String BEAN_NAME = "annotationBeanProcessor"; public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { List<String> basePackages = getPackagesToScan(importingClassMetadata); if (!registry.containsBeanDefinition(BEAN_NAME)) { addPostProcessor(registry, basePackages); } } // register annotationBeanProcessor.class private void addPostProcessor(BeanDefinitionRegistry registry, List<String> basePackages) { GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); beanDefinition.setBeanClass(AnnotationBeanProcessor.class); beanDefinition.getConstructorArgumentValues() .addGenericArgumentValue(basePackages); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); registry.registerBeanDefinition(BEAN_NAME, beanDefinition); } //获取扫描的包路径 private List<String> getPackagesToScan(AnnotationMetadata metadata) { //EnableDubbo 是一个注解,用于开启扫描dubbo的bean,而且能够本身定义扫描basePackages AnnotationAttributes attributes = AnnotationAttributes.fromMap( metadata.getAnnotationAttributes(EnableDubbo.class.getName())); String[] basePackages = attributes.getStringArray("basePackages"); return Arrays.asList(basePackages); } }
其中还使用到了EnableDubbo.class ,其实这个是一个注解,里面定义了basePackages的属性。 特色:1 经过注解使Dubbo是否生效,还能够本身配置basePackages的扫描包路径,而不用写死在代码里。2. 很Spring Boot Style
而这2个流程的理想处理方式就是在BeanPostProcessor 中,由于上面这2个处理逻辑不是针对某个特殊的bean,而是针对全部的bean,只要有@Reference或者@Service,而且知足basepackage限制就行。
dubbo现有的逻辑是分别在全部bean初始化以前进行@Reference相关流程,而在全部bean初始化以后调用@Service处理流程。(这2个流程甚至在ApplicationContext初始化成功之后再进行,而且这样作还会带来必定的好处)