通過之前系列文章我們已對Dubbo已有了1個整體的印象,接下來我們從其他角度來進1步了解它.Dubbo通過Spring的加載而啟動,本文分析了通過注解方式加載的進程.
1.Schema擴大
通過注解加載dubbo,需要在spring的配置文件中添加:
<dubbo:annotationpackage="com.package.to.be.scanned" />
dubbo:annotation是dubbo基于spring的schema擴大。
dubbo的schema描寫文件在dubbo-config-spring模塊下。我們可以看到在其中定義的xml描寫信息。
Spring會默許加載spring.handlers和spring.schemas,從而感知schema描寫文檔。從中我們可以看到schema的處理器:com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler
DubboNamespaceHandler繼承了NamespaceHandlerSupport。因此不需要實現所有的解析工作,只要將自定義schema中的元素解析器注冊進來就能夠。
public void init() {
registerBeanDefinitionParser("application", newDubboBeanDefinitionParser(ApplicationConfig.class, true));
registerBeanDefinitionParser("module", newDubboBeanDefinitionParser(ModuleConfig.class, true));
registerBeanDefinitionParser("registry", newDubboBeanDefinitionParser(RegistryConfig.class, true));
registerBeanDefinitionParser("monitor", newDubboBeanDefinitionParser(MonitorConfig.class, true));
registerBeanDefinitionParser("provider", newDubboBeanDefinitionParser(ProviderConfig.class, true));
registerBeanDefinitionParser("consumer", newDubboBeanDefinitionParser(ConsumerConfig.class, true));
registerBeanDefinitionParser("protocol", newDubboBeanDefinitionParser(ProtocolConfig.class, true));
registerBeanDefinitionParser("service", newDubboBeanDefinitionParser(ServiceBean.class, true));
registerBeanDefinitionParser("reference", newDubboBeanDefinitionParser(ReferenceBean.class, false));
registerBeanDefinitionParser("annotation", newDubboBeanDefinitionParser(AnnotationBean.class, true));
}
在代碼中我們可以看到被注冊的annotation解析器:DubboBeanDefinitionParser。Parser中的privatestaticBeanDefinition parse()方法實現了解析,并返回解析后生成bean的定義。接下來我們就看1下dubbodubbo:annotation的加載進程。
2. Dubbo 自定義元素加載
Spring啟動后,加載配置文件信息,得到dubbo的schema元素定義信息:<dubbo:annotation package="com.package.to.be.scanned" />
根據DubboNamespaceHandler中注冊的信息,spring找到解析類并調用解析方法:DubboBeanDefinitionParser.Parse()。
第1步,初始化RootBeanDefinition
第2步,獲得beanid
第3步,將xml中配置的信息放到beandefinition的PropertyValues中。
最后返回AnnotationBean的BeanDefinition。
至此,annotation對應的bean定義解析終了,spring知曉了AnnotationBean的存在。
3. AnnotationBean運行
AnnotationBean實現了很多spring的特殊bean接口:DisposableBean,BeanFactoryPostProcessor,BeanPostProcessor,ApplicationContextAware。這保證AnnotationBean能夠在spring加載的各個時期實現自己的功能。
注解掃描的功能在beanfactory初始化完成調用接口BeanFactoryPostProcessor.postProcessBeanFactory中實現。
實現代碼:
public voidpostProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {
if (annotationPackage == null ||annotationPackage.length() == 0) {
return;
}
if (beanFactory instanceofBeanDefinitionRegistry) {
try {
// init scanner
Class<?> scannerClass =ReflectUtils.forName("org.springframework.context.annotation.ClassPathBeanDefinitionScanner");
Object scanner =scannerClass.getConstructor(new Class<?>[] {BeanDefinitionRegistry.class,boolean.class}).newInstance(new Object[] {(BeanDefinitionRegistry) beanFactory,true});
// add filter
Class<?> filterClass =ReflectUtils.forName("org.springframework.core.type.filter.AnnotationTypeFilter");
Object filter =filterClass.getConstructor(Class.class).newInstance(Service.class);
Method addIncludeFilter =scannerClass.getMethod("addIncludeFilter",ReflectUtils.forName("org.springframework.core.type.filter.TypeFilter"));
addIncludeFilter.invoke(scanner, filter);
// scan packages
String[] packages =Constants.COMMA_SPLIT_PATTERN.split(annotationPackage);
Method scan =scannerClass.getMethod("scan", newClass<?>[]{String[].class});
scan.invoke(scanner, newObject[] {packages});
} catch (Throwable e) {
// spring 2.0
}
}
}
AnnotationBean的參數annotationPackage,就是在beandefinition創建時,從xml中讀取到spring中。源碼通過ClassPathBeanDefinitionScanner.doScan掃描annotationPackage下所有的文件。配置成bean的類會定義成BeanDefinition,注冊到spring。