通过之前系列文章我们已经对Dubbo已经有了一个整体的印象,接下来我们从其他角度来进一步了解它.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的定义。接下来我们就看一下dubbodubbo:annotation的加载过程。
2. Dubbo 自定义元素加载
Spring启动后,加载配置文件信息,得到dubbo的schema元素定义信息:<dubbo:annotation package="com.package.to.be.scanned" />
根据DubboNamespaceHandler中注册的信息,spring找到解析类并调用解析方法:DubboBeanDefinitionParser.Parse()。
第一步,初始化RootBeanDefinition
第二步,获取beanid
第三步,将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。