赞
踩
本文仅仅包含Spring整合Dubbo部分,代码流程中涉及很多Spring的扩展机制,如果对于Spring的一些扩展机制不熟悉的小伙伴,可以先了解Spring中的源码,再阅读本文,否则会出现很多莫名其妙的接口和方法。
此处之外,文本仅涉及整合部分,不涉及服务调用、引入与导出部分。
先来一张总体的流程图:
如果Spring项目需要和Spring进行整合,在引入对应的maven依赖后,需要使用@EnableDubbo注解,用来开启对应的Dubbo组件。这个和众多分布式组件类似,都是使用一个注解引入对应的组件。
scanBasePackages 表示扫描路径,可以类比ComponentScan注解的配置项进行理解。即扫描哪些路径下的实体类,完成dubbo服务的提供。
在EnableDubbo注解里面又引入了两个注解,处理properties配置文件需要使用到@EnableDubboConfig注解,第二个注解与@Service和@Referencer注解有关,这在下一届进行讲解
@EnableDubboConfig
@DubboComponentScan
public @interface EnableDubbo {}
@EnableDubboConfig注解,又以同样的方式引入了DubboConfigConfigurationRegistrar类
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Import(DubboConfigConfigurationRegistrar.class)
public @interface EnableDubboConfig {
// multiple默认值为true
boolean multiple() default true;
}
此类实现了ImportBeanDefinitionRegistrar接口,熟悉Spring的小伙伴都知道这是Spring的一个扩展接口,用来将所有的Java类注册为BeanDefinition,再用于后期的实例化单例Bean步骤
对应的Spring中的源码位置如下图,这是一个十分重要的点,很多微服务组件都是通过实现这个接口进行BeanDefinition的注册。其对应Spring中refresh方法里面的invokeBeanFactoryPostProcessors方法(如果你对refresh方法都一点没听过,那就直接忽略这里)
registerBeans方法内部大致逻辑为注册DubboConfigConfiguration这个注解,所以压力又来到了DubboConfigConfiguration这个注解内部。想跟源码的可以跟进去,内部就是调用register方法完成注册
public class DubboConfigConfigurationRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { AnnotationAttributes attributes = AnnotationAttributes.fromMap( importingClassMetadata.getAnnotationAttributes(EnableDubboConfig.class.getName())); boolean multiple = attributes.getBoolean("multiple"); //true // Single Config Bindings registerBeans(registry, DubboConfigConfiguration.Single.class); // 默认为true if (multiple) { // Since 2.6.6 https://github.com/apache/dubbo/issues/3193 registerBeans(registry, DubboConfigConfiguration.Multiple.class); } } }
第二步在调用registerBeans方法的时候,会根据multiple参数的情况传入不同的参数,用于multiple默认值为true,所以这里使用的是下面的这个配置项。
该类你可以简单理解为如果我们要对dubbo服务进行配置,那么对应的配置项有哪些。prefix对应的值和dubbo服务配置项的前两位是相同的。
点进@EnableDubboConfigBindings注解,我们会发现其内部还是以同样的方式@Import一个类
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(DubboConfigBindingsRegistrar.class)
public @interface EnableDubboConfigBindings {
/**
* The value of {@link EnableDubboConfigBindings}
*
* @return non-null
*/
EnableDubboConfigBinding[] value();
}
接下来就开始我们正常的代码逻辑了
大致流程:
- 获取到所有EnableDubboConfigBindings注解的信息,返回转换成一个数组集合
- 拿到每一个注解中全部配置值(含prefix和type)
- 依次遍历每一个注解上的配置项
registerBeanDefinitions方法内部对element配置项进行解析,然后传入对应的prefix和type的值,再调用registerDubboConfigBeans方法
该方法目的为,将我们的dubbo配置项,解析为一个一个的BeanDefinition,并且注册到Spring容器中,未来这些BeanDefinition都会变成一个一个的Bean对象,用来赋值给使用了dubbo中@Service注解的对应的Bean的属性。
该方法大致步骤为:
- 首先根据传进来的prefix去我们的所有配置项中找到对应的配置key-value(对应的加载配置文件的步骤由spring进行处理)
- 再调用resolveMultipleBeanNames方法,根据第一个.出现的位置,判断获取beanName
- 根据前面获取到的beanName,注解配置项中的type创建对应的BeanDefinition对象
- 再调用registerDubboConfigBindingBeanPostProcessor方法,给Spring中每一个Bean在实例化过程中进行一个拦截处理(BeanPostProcessor涉及Spring中Bean的声明周期概念),在添加DubboConfigBindingBeanPostProcessor.class处理器的时候,还会为每一个处理器添加对应的初始化参数,用于后期过滤属于dubbo配置文件中的Bean。对应的代码如下图
- 最后再注册一个类型为NamePropertyDefaultValueDubboConfigBeanCustomizer名字为namePropertyDefaultValueDubboConfigBeanCustomizer的BeanDefinition到Spring容器中
private void registerDubboConfigBeans(String prefix, Class<? extends AbstractConfig> configClass, boolean multiple, BeanDefinitionRegistry registry) { // 从properties文件中根据前缀拿对应的配置项,比如根据dubbo.application前缀, // 就可以拿到: // (dubbo.application.name)name=dubbo-demo-provider-application // (dubbo.application.logger)logger=log4j Map<String, Object> properties = getSubProperties(environment.getPropertySources(), prefix); // 如果没有相关的配置项,则不需要注册BeanDefinition if (CollectionUtils.isEmpty(properties)) { if (log.isDebugEnabled()) { log.debug("There is no property for binding to dubbo config class [" + configClass.getName() + "] within prefix [" + prefix + "]"); } return; } // 根据配置项生成beanNames,为什么会有多个? // 普通情况一个dubbo.application前缀对应一个ApplicationConfig类型的Bean // 特殊情况下,比如dubbo.protocols对应了: // dubbo.protocols.p1.name=dubbo // dubbo.protocols.p1.port=20880 // dubbo.protocols.p1.host=0.0.0.0 // dubbo.protocols.p2.name=http // dubbo.protocols.p2.port=8082 // dubbo.protocols.p2.host=0.0.0.0 // 那么就需要对应两个ProtocolConfig类型的Bean,那么就需要两个beanName:p1和p2 // 这里就是multiple为true或false的区别,名字的区别,根据multiple用来判断是否从配置项中获取beanName // 如果multiple为false,则看有没有配置id属性,如果没有配置则自动生成一个beanName. Set<String> beanNames = multiple ? resolveMultipleBeanNames(properties) : Collections.singleton(resolveSingleBeanName(properties, configClass, registry)); for (String beanName : beanNames) { // 为每个beanName,注册一个空的BeanDefinition registerDubboConfigBean(beanName, configClass, registry); // 为每个bean注册一个DubboConfigBindingBeanPostProcessor的Bean后置处理器 registerDubboConfigBindingBeanPostProcessor(prefix, beanName, multiple, registry); } // 注册一个NamePropertyDefaultValueDubboConfigBeanCustomizer的bean // 用来把某个XxConfig所对应的beanName设置到name属性中去 registerDubboConfigBeanCustomizers(registry); }
该节大致流程为:
至此,我们已经完成了对Dubbo的配置文件中内容的解析,我们根据指定的规则(@DubboConfigConfiguration注解上的配置信息),完成了配置相关BeanDefinition的注册。该BeanDefiniton实例化为Bean后作用于被Dubbo中@Service注解修饰的每一个服务。
接下来就是处理所有的服务。我们在调用这个注解时传入的scanBasePackages就是为DubboComponentScan这个注解做准备的。
注解内部还是和前面一样的方式引入了DubboComponentScanRegistrar注解,在该类内部就完成了@Service和@Reference注解的处理,本节暂时只说明@Service注解,即调用registerServiceAnnotationBeanPostProcessor方法。该方法内部只完成一件事情,那就是注册ServiceAnnotationBeanPostProcessor这个处理器。
@Inherited
@Documented
@EnableDubboConfig
@DubboComponentScan
public @interface EnableDubbo {
@AliasFor(annotation = DubboComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
...
}
该类实现了BeanDefinitionRegistryPostProcessor接口,表示BeanFactory的后置处理器,用于向Spring容器添加BeanDefinition。最终在Spring启动后,会调用该类的postProcessBeanDefinitionRegistry方法,完成BeanDefinition的注册
在该方法内部,会调用registerServiceBeans方法,完成注册
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
Set<String> resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);
if (!CollectionUtils.isEmpty(resolvedPackagesToScan)) {
// 扫描包,进行Bean注册
registerServiceBeans(resolvedPackagesToScan, registry);
} else {
if (logger.isWarnEnabled()) {
logger.warn("packagesToScan is empty , ServiceBean registry will be ignored!");
}
}
}
由于我们使用Dubbo中的@Service注解进行服务的暴露,那么我们原本的Spring中的@Service注解的效果就没有了,所以Dubbo中的@Service需要具备将添加了Dubbo中@Service注解的类,注册到Spring容器中。在此基础上,再扩展完成Dubbo自己想要的功能
下列代码逻辑大致为:
- 获取到scanBasePackages配置的扫描路径
- 添加需要扫描的注解类型(Dubbo中的Service注解)
- 由于对应的扫描路径可以配置多个,所以遍历每一个扫描路径
- 调用scanner.scan方法,完成Spring中BeanDefinition的注册
- 再调用findServiceBeanDefinitionHolders获取到scan方法注册了哪些BeanDefintion
- 最后遍历通过scan扫描到的BeanDefinition,再调用registerServiceBean方法,完成Dubbo的额外逻辑
private void registerServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) { DubboClassPathBeanDefinitionScanner scanner = new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader); BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry); scanner.setBeanNameGenerator(beanNameGenerator); // 扫描被Service注解标注的类 scanner.addIncludeFilter(new AnnotationTypeFilter(Service.class)); /** * Add the compatibility for legacy Dubbo's @Service * * The issue : https://github.com/apache/dubbo/issues/4330 * @since 2.7.3 */ scanner.addIncludeFilter(new AnnotationTypeFilter(com.alibaba.dubbo.config.annotation.Service.class)); for (String packageToScan : packagesToScan) { // Registers @Service Bean first // 扫描Dubbo自定义的@Service注解 scanner.scan(packageToScan); // 查找被@Service注解的类的BeanDefinition(无论这个类有没有被@ComponentScan注解标注了) // Finds all BeanDefinitionHolders of @Service whether @ComponentScan scans or not. Set<BeanDefinitionHolder> beanDefinitionHolders = findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator); if (!CollectionUtils.isEmpty(beanDefinitionHolders)) { // 扫描到BeanDefinition开始处理它 for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) { registerServiceBean(beanDefinitionHolder, registry, scanner); } if (logger.isInfoEnabled()) { logger.info(beanDefinitionHolders.size() + " annotated Dubbo's @Service Components { " + beanDefinitionHolders + " } were scanned under package[" + packageToScan + "]"); } } else { if (logger.isWarnEnabled()) { logger.warn("No Spring Bean annotating Dubbo's @Service was found under package[" + packageToScan + "]"); } } } }
该方法主要作用为完成Dubbo中对于每一个@Service注解修饰的服务的处理。
该方法逻辑大致为:
- 获取到具体类上的@Service注解
- 解析获取到每一个@Service注解上的配置信息
- 根据对应的配置信息,创建出一个ServiceBean的对象(后文会对赋值情况进行解释)
- 根据创建出来的ServiceBean对象的接口名字、group分组名字、version版本名字创建出该对象在Spring容器中对应的beanName
- 调用registerBeanDefinition方法,将上面创建出来的BeanDefinition添加到Spring容器中
private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry, DubboClassPathBeanDefinitionScanner scanner) { // 服务实现类 Class<?> beanClass = resolveClass(beanDefinitionHolder); // 1、@Service注解 Annotation service = findServiceAnnotation(beanClass); //2、 @Service注解上的信息 AnnotationAttributes serviceAnnotationAttributes = getAnnotationAttributes(service, false, false); // 服务实现类对应的接口 Class<?> interfaceClass = resolveServiceInterfaceClass(serviceAnnotationAttributes, beanClass); // 服务实现类对应的bean的名字,比如:demoServiceImpl String annotatedServiceBeanName = beanDefinitionHolder.getBeanName(); // 3、生成一个ServiceBean AbstractBeanDefinition serviceBeanDefinition = buildServiceBeanDefinition(service, serviceAnnotationAttributes, interfaceClass, annotatedServiceBeanName); // ServiceBean Bean name String beanName = generateServiceBeanName(serviceAnnotationAttributes, interfaceClass); if (scanner.checkCandidate(beanName, serviceBeanDefinition)) { // check duplicated candidate bean // 把ServiceBean注册进去,对应的beanName为ServiceBean:org.apache.dubbo.demo.DemoService registry.registerBeanDefinition(beanName, serviceBeanDefinition); if (logger.isInfoEnabled()) { logger.info("The BeanDefinition[" + serviceBeanDefinition + "] of ServiceBean has been registered with name : " + beanName); } } else { if (logger.isWarnEnabled()) { logger.warn("The Duplicated BeanDefinition[" + serviceBeanDefinition + "] of ServiceBean[ bean name : " + beanName + "] was be found , Did @DubboComponentScan scan to same package in many times?"); } } }
该方法作用为,将Service注解上配置的信息,以及properties配置文件中的配置项,赋值给这个ServiceBean对象,即进行属性的赋值
该方法很长,但是作用却清晰明了:
- 创建一个忽略的赋值参数列表(忽略的都是需要赋值BeanDefinition对象的,而非简单的字符串)
- 获取到@Service注解上的信息,调用addPropertyValues方法,对创建出现的ServiceBean进行除了忽略的参数列表的其他属性进行赋值
- 对于忽略的参数列表,一个一个的单独处理。首先根据对应的String字符串找到对应的BeanDefinition,再将对应的BeanDefinition赋值给对应的属性
- 这里有一个很重要的属性ref,该属性对应的值为annotatedServiceBeanName,通过代码就可以得到这个值为被@Service注解修饰的服务类。调用addPropertyReference方法就会根据annotatedServiceBeanName这个名字找到Spring容器中对应的BeanDefinition,然后完成ref参数的赋值
private AbstractBeanDefinition buildServiceBeanDefinition(Annotation serviceAnnotation, AnnotationAttributes serviceAnnotationAttributes, Class<?> interfaceClass, String annotatedServiceBeanName) { // 生成一个ServiceBean对应的BeanDefinition BeanDefinitionBuilder builder = rootBeanDefinition(ServiceBean.class); AbstractBeanDefinition beanDefinition = builder.getBeanDefinition(); MutablePropertyValues propertyValues = beanDefinition.getPropertyValues(); String[] ignoreAttributeNames = of("provider", "monitor", "application", "module", "registry", "protocol", "interface", "interfaceName", "parameters"); // 把serviceAnnotation中的参数值赋值给ServiceBean的属性 propertyValues.addPropertyValues(new AnnotationPropertyValuesAdapter(serviceAnnotation, environment, ignoreAttributeNames)); // References "ref" property to annotated-@Service Bean // ref属性赋值为另外一个bean, 对应的就是被@Service注解的服务实现类对应的bean addPropertyReference(builder, "ref", annotatedServiceBeanName); // Set interface builder.addPropertyValue("interface", interfaceClass.getName()); // Convert parameters into map builder.addPropertyValue("parameters", convertParameters(serviceAnnotationAttributes.getStringArray("parameters"))); // 配置了methods属性,则给ServiceBean对应的methods属性赋值 // Add methods parameters List<MethodConfig> methodConfigs = convertMethodConfigs(serviceAnnotationAttributes.get("methods")); if (!methodConfigs.isEmpty()) { builder.addPropertyValue("methods", methodConfigs); } /** * Add {@link org.apache.dubbo.config.ProviderConfig} Bean reference */ String providerConfigBeanName = serviceAnnotationAttributes.getString("provider"); if (StringUtils.hasText(providerConfigBeanName)) { addPropertyReference(builder, "provider", providerConfigBeanName); } /** * Add {@link org.apache.dubbo.config.MonitorConfig} Bean reference */ String monitorConfigBeanName = serviceAnnotationAttributes.getString("monitor"); if (StringUtils.hasText(monitorConfigBeanName)) { addPropertyReference(builder, "monitor", monitorConfigBeanName); } /** * Add {@link org.apache.dubbo.config.ApplicationConfig} Bean reference */ String applicationConfigBeanName = serviceAnnotationAttributes.getString("application"); if (StringUtils.hasText(applicationConfigBeanName)) { addPropertyReference(builder, "application", applicationConfigBeanName); } /** * Add {@link org.apache.dubbo.config.ModuleConfig} Bean reference */ String moduleConfigBeanName = serviceAnnotationAttributes.getString("module"); if (StringUtils.hasText(moduleConfigBeanName)) { addPropertyReference(builder, "module", moduleConfigBeanName); } /** * Add {@link org.apache.dubbo.config.RegistryConfig} Bean reference * 获取注解上配置的注册中心的beanName */ String[] registryConfigBeanNames = serviceAnnotationAttributes.getStringArray("registry"); List<RuntimeBeanReference> registryRuntimeBeanReferences = toRuntimeBeanReferences(registryConfigBeanNames); if (!registryRuntimeBeanReferences.isEmpty()) { builder.addPropertyValue("registries", registryRuntimeBeanReferences); } /** * Add {@link org.apache.dubbo.config.ProtocolConfig} Bean reference */ String[] protocolConfigBeanNames = serviceAnnotationAttributes.getStringArray("protocol"); List<RuntimeBeanReference> protocolRuntimeBeanReferences = toRuntimeBeanReferences(protocolConfigBeanNames); if (!protocolRuntimeBeanReferences.isEmpty()) { builder.addPropertyValue("protocols", protocolRuntimeBeanReferences); } return builder.getBeanDefinition(); }
该节大致流程为:
至此,对于@Service注解暴露对应的服务相关的解析流程已经完成
该方法仅完成一件事情,那就是注册ReferenceAnnotationBeanPostProcessor这个Bean。这个类的名字太长,你可能看着比较陌生。那我再给你说另一个类AutowiredAnnotationBeanPostProcessor,有没有发现这两个类有一点像?AutowiredAnnotationBeanPostProcessor这个类是Spring中对类中添加了@Autwired方法后进行属性注入的类,同理,我们的ReferenceAnnotationBeanPostProcessor就是为添加了@Reference注解的属性进行属性填充。
private void registerReferenceAnnotationBeanPostProcessor(BeanDefinitionRegistry registry) {
// Register @Reference Annotation Bean Processor
// 注册一个ReferenceAnnotationBeanPostProcessor做为bean,ReferenceAnnotationBeanPostProcessor是一个BeanPostProcessor
BeanRegistrar.registerInfrastructureBean(registry,
ReferenceAnnotationBeanPostProcessor.BEAN_NAME, ReferenceAnnotationBeanPostProcessor.class);
}
类比Spring的@Autwired注解,在实例化所有的单例Bean的时候,我们就会调用populateBean进行属性填充,在populateBean方法内部会调用postProcessPropertyValues方法,完成属性的填充。postProcessPropertyValues方法就会跳转到对应的AutwiredAnnotationBeanPostProcessor。同理我们就以ReferenceAnnotationBeanPostProcessor的postProcessPropertyValues为起点
@Override public PropertyValues postProcessPropertyValues( PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException { // 寻找需要注入的属性(被@Reference标注的Field) InjectionMetadata metadata = findInjectionMetadata(beanName, bean.getClass(), pvs); try { metadata.inject(bean, beanName, pvs); } catch (BeanCreationException ex) { throw ex; } catch (Throwable ex) { throw new BeanCreationException(beanName, "Injection of @" + getAnnotationType().getSimpleName() + " dependencies is failed", ex); } return pvs; }
在Spring中,这个基本的属性注入的方法第一步首先要找到注入点,即哪些位置需要进行属性注入。类比到这里就是找到哪些位置含有@Reference注解,继而能够完成@Reference属性的填充
private InjectionMetadata findInjectionMetadata(String beanName, Class<?> clazz, PropertyValues pvs) { // Fall back to class name as cache key, for backwards compatibility with custom callers. String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName()); // Quick check on the concurrent map first, with minimal locking. AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey); if (InjectionMetadata.needsRefresh(metadata, clazz)) { synchronized (this.injectionMetadataCache) { metadata = this.injectionMetadataCache.get(cacheKey); if (InjectionMetadata.needsRefresh(metadata, clazz)) { if (metadata != null) { metadata.clear(pvs); } try { metadata = buildAnnotatedMetadata(clazz); this.injectionMetadataCache.put(cacheKey, metadata); } catch (NoClassDefFoundError err) { throw new IllegalStateException("Failed to introspect object class [" + clazz.getName() + "] for annotation metadata: could not find class that it depends on", err); } } } } return metadata; }
传入指定的类,调用buildAnnotatedMetadata方法,分别在属性、方法上找到对应的注入点
private AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata buildAnnotatedMetadata(final Class<?> beanClass) {
// 哪些Filed上有@Reference注解
Collection<AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement> fieldElements = findFieldAnnotationMetadata(beanClass);
// 哪些方法上有@Reference注解
Collection<AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement> methodElements = findAnnotatedMethodMetadata(beanClass);
// 返回的是Dubbo定义的AnnotatedInjectionMetadata,接下来就会使用这个类去进行属性注入
return new AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata(beanClass, fieldElements, methodElements);
}
调用inject完成对应注入点的注入(含有成员变量和方法两类)
找到注入点以后,就会调用该方法完成注入点的赋值。
大致流程步骤为:
- 得到当前所引入服务对应的ServiceBean的beanName
- 据@Reference注解的所有信息+属性接口类型得到一个referenceBeanName
- 根据@Reference注解配置的信息生成一个ReferenceBean对象,并且放入referenceBeanCache缓存Map中(key(@Reference这个注解的配置转换成字符串)-value(根据配置信息创建一个ReferenceBean对象))
- 把referenceBean添加到Spring容器中去
- 获取到对应的代理对象
@Override protected Object doGetInjectedBean(AnnotationAttributes attributes, Object bean, String beanName, Class<?> injectedType, InjectionMetadata.InjectedElement injectedElement) throws Exception { /** * The name of bean that annotated Dubbo's {@link Service @Service} in local Spring {@link ApplicationContext} */ // 按ServiceBean的beanName生成规则来生成referencedBeanName, 规则为ServiceBean:interfaceClassName:version:group String referencedBeanName = buildReferencedBeanName(attributes, injectedType); /** * The name of bean that is declared by {@link Reference @Reference} annotation injection */ // @Reference(methods=[Lorg.apache.dubbo.config.annotation.Method;@39b43d60) org.apache.dubbo.demo.DemoService // 根据@Reference注解的信息生成referenceBeanName String referenceBeanName = getReferenceBeanName(attributes, injectedType); // 生成一个ReferenceBean对象 ReferenceBean referenceBean = buildReferenceBeanIfAbsent(referenceBeanName, attributes, injectedType); // 把referenceBean添加到Spring容器中去 registerReferenceBean(referencedBeanName, referenceBean, attributes, injectedType); cacheInjectedReferenceBean(referenceBean, injectedElement); // 创建一个代理对象,Service中的属性被注入的就是这个代理对象 // 内部会调用referenceBean.get(); return getOrCreateProxy(referencedBeanName, referenceBeanName, referenceBean, injectedType); }
该方法对应上图的第4步,把referenceBean添加到Spring容器中去。@Reference引用的是一个服务,这个服务对应的就是被@Service注解修饰的类,@Reference注解修饰的属性或者方法需要使用到被@Service注解修饰到的服务。那么我们这里需要明白两种场景,第一种是对应的服务存在于我们的本地,另一种是对应的服务不在我们本地。如果不存在就表示对应的服务存在于远程
该方法的大致步骤为:
- 根据 @Resource注解获取到对应的字符串(同上面的第2步)
- 判断Spring容器中是否含有对应的
- 如果当前Spring容器存在,表示在本地存在。那么就获取ServiceBean对象里面的ref属性,即前面有说到过的@Service标注的类的服务,然后获取到对应的服务注册到容器中
- 如果不存在,就表示未来这个服务是需要远程获取,这里就将封装好的ReferenceBean对象注册到容器中
- ReferenceBean类继承自FactoryBean类,到时候调用对应的getObject方法,就可以获取到对应的代理对象
private void registerReferenceBean(String referencedBeanName, ReferenceBean referenceBean, AnnotationAttributes attributes, Class<?> interfaceClass) { ConfigurableListableBeanFactory beanFactory = getBeanFactory(); // 就是referenceBeanName(ServiceBean对应的beanName) String beanName = getReferenceBeanName(attributes, interfaceClass); // 当前Spring容器中是否存在referencedBeanName if (existsServiceBean(referencedBeanName)) { // If @Service bean is local one /** * Get the @Service's BeanDefinition from {@link BeanFactory} * Refer to {@link ServiceAnnotationBeanPostProcessor#buildServiceBeanDefinition} */ AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) beanFactory.getBeanDefinition(referencedBeanName); RuntimeBeanReference runtimeBeanReference = (RuntimeBeanReference) beanDefinition.getPropertyValues().get("ref"); // ServiceBean --- ref // The name of bean annotated @Service String serviceBeanName = runtimeBeanReference.getBeanName(); // DemoServiceImpl对应的beanName // register Alias rather than a new bean name, in order to reduce duplicated beans // DemoServiceImpl多了一个别名,比如 demoServiceImpl和 beanFactory.registerAlias(serviceBeanName, beanName); } else { // Remote @Service Bean if (!beanFactory.containsBean(beanName)) { beanFactory.registerSingleton(beanName, referenceBean); } } }
该节大致流程为:
一句话,如果对应的服务存在于本地,就使用@Service注解配置到的服务类进行属性填充;如果对应的服务不存在本地,就使用ReferenceBean(继承了FactoryBean类)类配置到的对应的属性上。至此,Dubbo中的@Reference注解(类比@Autwired注解作用)完成对应服务对象的填充步骤已经完成。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。