在 dubbo的Reference注解实现原理 中提到,@Reference
注解用于实现 RPC client 代理的自动注入,这是通过 ReferenceAnnotationBeanPostProcessor
来实现的。若要让其生效,还需要在这之前将其注册到 BeanFactory 中。
通常配置 spring 的方式有 XML 形式、java 注解形式,那么注册 ReferenceAnnotationBeanPostProcessor
的方式也分别有 XML 形式配置、java 注解形式配置。
整体流程 通常情况下,往 ApplicationContext
类型的容器中注册 BeanPostProcessor
的过程主要包括如下两个步骤:
往 BeanDefinitonRegistry
中注册 BeanPostProcessor
的 BeanDefinition
定义 从 BeanFactory
中获取 BeanPostProcessor
类型的 Bean
,将其注册到 BeanFactory
的后处理器中 其中第一步需要使用者自己处理,spring 会自动完成第二步操作。
注册 BeanDefinition 将 ReferenceAnnotationBeanPostProcessor
以 BeanDefintion
的形式注册到 BeanDefinitionRegistry
中。
XML 方式 使用方式 如下是一个使用 XML 方式的配置:
1 2 3 4 5 6 7 8 9 10 11 <beans xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo ="http://dubbo.apache.org/schema/dubbo" xmlns ="http://www.springframework.org/schema/beans" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd" > <dubbo:application name ="annotation-consumer" /> <dubbo:registry address ="127.0.0.1:4548" /> <dubbo:annotation package ="org.apache.dubbo.config.spring.annotation.consumer" /> </beans >
相关配置 其中我们需要关注的配置项是:
1 <dubbo:annotation package ="org.apache.dubbo.config.spring.annotation.consumer" />
它表示要开启注解的方式,这样就支持 @Reference
注解的自动注入。
它是如何生效的 上面的 XML 中使用的是自定义的 namespace http://dubbo.apache.org/schema/dubbo
,要对它进行解析处理,需要注册对应的 NamespaceHandler
Dubbo 在 class path 下的 META-INF 文件夹中新增了 handlers 配置文件 spring.handlers
,如下图所示
在该文件中配置了 namespace 对应的 NamespaceHandler
,文件内容如下(注意 :
需要进行转义):
1 http\://dubbo.apache.org/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
在解析 xml 时,spring 会通过 namespaceUri
查找对应的 NamespaceHandler
来解析 xml 元素。它的主要思路是:获取 namespaceUri
到 NamespaceHandler
的映射关系,然后根据 namespaceUri
找到对应的 NamespaceHandler
类名,进行初始化并返回,相关代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 public NamespaceHandler resolve (String namespaceUri) { Map<String, Object> handlerMappings = getHandlerMappings(); Object handlerOrClassName = handlerMappings.get(namespaceUri); if (handlerOrClassName == null ) { return null ; } else if (handlerOrClassName instanceof NamespaceHandler) { return (NamespaceHandler) handlerOrClassName; } else { String className = (String) handlerOrClassName; try { Class<?> handlerClass = ClassUtils.forName(className, this .classLoader); if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) { throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri + "] does not implement the [" + NamespaceHandler.class.getName() + "] interface" ); } NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass); namespaceHandler.init(); handlerMappings.put(namespaceUri, namespaceHandler); return namespaceHandler; } catch (ClassNotFoundException ex) { throw new FatalBeanException("Could not find NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "]" , ex); } catch (LinkageError err) { throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "]" , err); } } }
注意到它是通过 getHandlerMappings
获取的 namespaceUri
到 NamespaceHandler
的映射关系,第一次调用该方法时会从加载并解析 META-INF/spring.handlers
,将映射关系保存到 handlerMappings
中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers" ;public DefaultNamespaceHandlerResolver () { this (null , DEFAULT_HANDLER_MAPPINGS_LOCATION); } private Map<String, Object> getHandlerMappings () { Map<String, Object> handlerMappings = this .handlerMappings; if (handlerMappings == null ) { synchronized (this ) { handlerMappings = this .handlerMappings; if (handlerMappings == null ) { if (logger.isTraceEnabled()) { logger.trace("Loading NamespaceHandler mappings from [" + this .handlerMappingsLocation + "]" ); } try { Properties mappings = PropertiesLoaderUtils.loadAllProperties(this .handlerMappingsLocation, this .classLoader); if (logger.isTraceEnabled()) { logger.trace("Loaded NamespaceHandler mappings: " + mappings); } handlerMappings = new ConcurrentHashMap<>(mappings.size()); CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings); this .handlerMappings = handlerMappings; } catch (IOException ex) { throw new IllegalStateException( "Unable to load NamespaceHandler mappings from location [" + this .handlerMappingsLocation + "]" , ex); } } } } return handlerMappings; }
DubboNamespaceHandler的处理 接下来看下 DubboNamespaceHandler
是如何处理 xml 中的配置的。DubboNamespaceHandler
继承自 NamespaceHandlerSupport
,主要实现了 NamespaceHandler
接口的 init 方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public void init () { registerBeanDefinitionParser("application" , new DubboBeanDefinitionParser(ApplicationConfig.class, true )); registerBeanDefinitionParser("module" , new DubboBeanDefinitionParser(ModuleConfig.class, true )); registerBeanDefinitionParser("registry" , new DubboBeanDefinitionParser(RegistryConfig.class, true )); registerBeanDefinitionParser("config-center" , new DubboBeanDefinitionParser(ConfigCenterBean.class, true )); registerBeanDefinitionParser("metadata-report" , new DubboBeanDefinitionParser(MetadataReportConfig.class, true )); registerBeanDefinitionParser("monitor" , new DubboBeanDefinitionParser(MonitorConfig.class, true )); registerBeanDefinitionParser("metrics" , new DubboBeanDefinitionParser(MetricsConfig.class, true )); registerBeanDefinitionParser("provider" , new DubboBeanDefinitionParser(ProviderConfig.class, true )); registerBeanDefinitionParser("consumer" , new DubboBeanDefinitionParser(ConsumerConfig.class, true )); registerBeanDefinitionParser("protocol" , new DubboBeanDefinitionParser(ProtocolConfig.class, true )); registerBeanDefinitionParser("service" , new DubboBeanDefinitionParser(ServiceBean.class, true )); registerBeanDefinitionParser("reference" , new DubboBeanDefinitionParser(ReferenceBean.class, false )); registerBeanDefinitionParser("annotation" , new AnnotationBeanDefinitionParser()); }
在这里为每一个 XML 配置项注册了对应的 parser,其中 annotation 对应的 parser 为 AnnotationBeanDefinitionParser
。这样 spring 在遇到如下配置时,会将其解析工作交给 AnnotationBeanDefinitionParser
1 <dubbo:annotation package ="org.apache.dubbo.config.spring.annotation.consumer" />
AnnotationBeanDefinitionParser解析 如上所述,AnnotationBeanDefinitionParser
用于解析 XML 中的 annotation 配置。它的主要功能是:
解析 package 配置,注册到该配置项对应的 BeanDefinition
中 注册 ReferenceAnnotationBeanPostProcessor
1 2 3 4 5 6 7 8 9 10 protected void doParse (Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { String packageToScan = element.getAttribute("package" ); String[] packagesToScan = trimArrayElements(commaDelimitedListToStringArray(packageToScan)); builder.addConstructorArgValue(packagesToScan); builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); registerReferenceAnnotationBeanPostProcessor(parserContext.getRegistry()); }
ReferenceAnnotationBeanPostProcessor
的 BeanDefinition 注册实现
1 2 3 4 5 6 7 8 9 BeanRegistrar.registerInfrastructureBean(registry, ReferenceAnnotationBeanPostProcessor.BEAN_NAME, ReferenceAnnotationBeanPostProcessor.class); if (!beanDefinitionRegistry.containsBeanDefinition(beanName)) { RootBeanDefinition beanDefinition = new RootBeanDefinition(beanType); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); beanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinition); }
java 注解方式 这是通过 spring 的 ImportBeanDefinitionRegistrar
扩展实现的。dubbo 提供了一个 DubboComponentScanRegistrar
类,它实现了 ImportBeanDefinitionRegistrar
接口,在这里完成了 ReferenceAnnotationBeanPostProcessor
的注册
1 2 3 4 5 6 7 8 public void registerBeanDefinitions (AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { Set<String> packagesToScan = getPackagesToScan(importingClassMetadata); registerServiceAnnotationBeanPostProcessor(packagesToScan, registry); registerReferenceAnnotationBeanPostProcessor(registry); }
相关注册代码如下
1 2 3 4 5 private void registerReferenceAnnotationBeanPostProcessor (BeanDefinitionRegistry registry) { BeanRegistrar.registerInfrastructureBean(registry, ReferenceAnnotationBeanPostProcessor.BEAN_NAME, ReferenceAnnotationBeanPostProcessor.class); }
ImportBeanDefinitionRegistrar 是如何生效的 在 ApplicationContext
进行 refresh
时,处理 BeanFactory
的最后一步是BeanFactoryPostProcessor
。在这一步会对所有的 BeanDefinitionRegistryPostProcessor
进行回调。
在这里需要提到一个后处理器是 ConfigurationClassPostProcessor
,它负责处理所有的 Configuration
类,包括 ImportBeanDefinitionRegistrar
类的回调。
ConfigurationClassPostProcessor 的注册 与 xml 类型的 bean 通过 XmlBeanDefinitionReader
解析类似,annotation 类型的 bean 通过 AnnotatedBeanDefinitionReader
进行解析。AnnotatedBeanDefinitionReader
在构造时会注册一些配置处理器,其中一个就是 ConfigurationClassPostProcessor
1 2 3 4 5 if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)); }
ConfigurationClassPostProcessor 的处理 解析 ImportBeanDefinitionRegistrar 配置 上面提到 ConfigurationClassPostProcessor
实现了 BeanDefinitionRegistryPostProcessor
,它的 postProcessBeanDefinitionRegistry
方法如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public void postProcessBeanDefinitionRegistry (BeanDefinitionRegistry registry) { int registryId = System.identityHashCode(registry); if (this .registriesPostProcessed.contains(registryId)) { throw new IllegalStateException( "postProcessBeanDefinitionRegistry already called on this post-processor against " + registry); } if (this .factoriesPostProcessed.contains(registryId)) { throw new IllegalStateException( "postProcessBeanFactory already called on this post-processor against " + registry); } this .registriesPostProcessed.add(registryId); processConfigBeanDefinitions(registry); }
其中会调用 ConfigurationClassParser
解析配置类
1 2 3 4 5 6 7 8 9 10 ConfigurationClassParser parser = new ConfigurationClassParser( this .metadataReaderFactory, this .problemReporter, this .environment, this .resourceLoader, this .componentScanBeanNameGenerator, registry); Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates); Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size()); do { parser.parse(candidates); parser.validate();
ConfigurationClassParser 会解析配置类上的各种注解,包括 @ComponentScan
、@Import
等
1 2 processImports(configClass, sourceClass, getImports(sourceClass), true );
如果是 ImportBeanDefinitionRegistrar
的子类,则将其添加到 ConfigurationClass
中
1 2 3 4 5 6 7 8 9 10 11 if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) { Class<?> candidateClass = candidate.loadClass(); ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class); ParserStrategyUtils.invokeAwareMethods( registrar, this .environment, this .resourceLoader, this .registry); configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata()); }
注册和回调 ImportBeanDefinitionRegistrar 解析完 ImportBeanDefinitionRegistrar
配置到 ConfigurationClass
之后,接下来就需要从中读取配置并注册相关的 BeanDefintion
。这一步是交给 ConfigurationClassBeanDefinitionReader
来处理的
1 2 3 4 5 6 7 if (this .reader == null ) { this .reader = new ConfigurationClassBeanDefinitionReader( registry, this .sourceExtractor, this .resourceLoader, this .environment, this .importBeanNameGenerator, parser.getImportRegistry()); } this .reader.loadBeanDefinitions(configClasses);
它会从 ConfigurationClass
中取出前面解析到的 ImportBeanDefinitionRegistrar
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 private void loadBeanDefinitionsForConfigurationClass ( ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) { if (trackedConditionEvaluator.shouldSkip(configClass)) { String beanName = configClass.getBeanName(); if (StringUtils.hasLength(beanName) && this .registry.containsBeanDefinition(beanName)) { this .registry.removeBeanDefinition(beanName); } this .importRegistry.removeImportingClass(configClass.getMetadata().getClassName()); return ; } if (configClass.isImported()) { registerBeanDefinitionForImportedConfigurationClass(configClass); } for (BeanMethod beanMethod : configClass.getBeanMethods()) { loadBeanDefinitionsForBeanMethod(beanMethod); } loadBeanDefinitionsFromImportedResources(configClass.getImportedResources()); loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars()); }
回调其 registerBeanDefinitions
方法
1 2 3 4 private void loadBeanDefinitionsFromRegistrars (Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) { registrars.forEach((registrar, metadata) -> registrar.registerBeanDefinitions(metadata, this .registry)); }
注册 BeanPostProcessor 注册 BeanPostProcessor
是由 spring 自己处理的(指的是 ApplicationContext
类型的容器)。
在 ApplicationContext
进行 refresh
操作时,首先会对 BeanFactory
进行准备和一些处理工作,在这之后就会往 BeanFactory
中注册 BeanPostProcessor
。它的主要思路是:
从 BeanFactory
中获取 BeanPostProcessor
类型的 bean
调用 ConfigurableBeanFactory
的 addBeanPostProcessor
方法往容器中注册 BeanPostProcessor
具体代码可参考 registerBeanPostProcessors