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初始化成功之後再進行,而且這樣作還會帶來必定的好處)