Dubbo中@EnableDubbo注解原理
Posted 敲代码的小小酥
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dubbo中@EnableDubbo注解原理相关的知识,希望对你有一定的参考价值。
前言
前面解析过很多@EnableXXX注解开启某个功能的原理,其注解内部都是通过@Import注解,来引入一个类,通过这个类,将开启功能的核心类引入spring容器,并进行一系列初始化操作。@EnableDubbo注解也不例外,还是这个套路,下面看其详细实现。
@EnableDubbo原理解析
点进去,看其源码:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@EnableDubboConfig
@DubboComponentScan
public @interface EnableDubbo
/**
* Base packages to scan for annotated @Service classes.
* <p>
* Use @link #scanBasePackageClasses() for a type-safe alternative to String-based
* package names.
*
* @return the base packages to scan
* @see DubboComponentScan#basePackages()
*/
@AliasFor(annotation = DubboComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default ;
/**
* Type-safe alternative to @link #scanBasePackages() for specifying the packages to
* scan for annotated @Service classes. The package of each class specified will be
* scanned.
*
* @return classes from the base packages to scan
* @see DubboComponentScan#basePackageClasses
*/
@AliasFor(annotation = DubboComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default ;
/**
* It indicates whether @link AbstractConfig binding to multiple Spring Beans.
*
* @return the default value is <code>false</code>
* @see EnableDubboConfig#multiple()
*/
@AliasFor(annotation = EnableDubboConfig.class, attribute = "multiple")
boolean multipleConfig() default true;
核心是@EnableDubboConfig注解和@DubboComponentScan。先看@EnableDubboConfig注解源码:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Import(DubboConfigConfigurationRegistrar.class)
public @interface EnableDubboConfig
/**
* It indicates whether binding to multiple Spring Beans.
* <p>
* Please note that if @link #multiple() is <code>true</code> since 2.6.6, the multiple bean bindings will be
* enabled, works with single bean bindings, rather than they are mutually exclusive before.
*
* @return the default value is <code>true</code> since 2.6.6, the value is inverse earlier.
* @revised 2.5.9
*/
boolean multiple() default true;
找到了熟悉的@Import注解,那么就看Import进来的这个类:
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");
// Single Config Bindings
registerBeans(registry, DubboConfigConfiguration.Single.class);
if (multiple) // Since 2.6.6 https://github.com/apache/incubator-dubbo/issues/3193
registerBeans(registry, DubboConfigConfiguration.Multiple.class);
可以看出,是一个BeanDefinitionRegistrar,是可以将bean注册到spring容器的,那么它将什么注册进了spring容器呢?核心代码如下:
registerBeans(registry, DubboConfigConfiguration.Single.class);
看DubboConfigConfiguration源码:
public class DubboConfigConfiguration
/**
* Single Dubbo @link AbstractConfig Config Bean Binding
*/
@EnableDubboConfigBindings(
@EnableDubboConfigBinding(prefix = "dubbo.application", type = ApplicationConfig.class),
@EnableDubboConfigBinding(prefix = "dubbo.module", type = ModuleConfig.class),
@EnableDubboConfigBinding(prefix = "dubbo.registry", type = RegistryConfig.class),
@EnableDubboConfigBinding(prefix = "dubbo.protocol", type = ProtocolConfig.class),
@EnableDubboConfigBinding(prefix = "dubbo.monitor", type = MonitorConfig.class),
@EnableDubboConfigBinding(prefix = "dubbo.provider", type = ProviderConfig.class),
@EnableDubboConfigBinding(prefix = "dubbo.consumer", type = ConsumerConfig.class)
)
public static class Single
/**
* Multiple Dubbo @link AbstractConfig Config Bean Binding
*/
@EnableDubboConfigBindings(
@EnableDubboConfigBinding(prefix = "dubbo.applications", type = ApplicationConfig.class, multiple = true),
@EnableDubboConfigBinding(prefix = "dubbo.modules", type = ModuleConfig.class, multiple = true),
@EnableDubboConfigBinding(prefix = "dubbo.registries", type = RegistryConfig.class, multiple = true),
@EnableDubboConfigBinding(prefix = "dubbo.protocols", type = ProtocolConfig.class, multiple = true),
@EnableDubboConfigBinding(prefix = "dubbo.monitors", type = MonitorConfig.class, multiple = true),
@EnableDubboConfigBinding(prefix = "dubbo.providers", type = ProviderConfig.class, multiple = true),
@EnableDubboConfigBinding(prefix = "dubbo.consumers", type = ConsumerConfig.class, multiple = true)
)
public static class Multiple
可以看出,这里是将xml里的一些配置信息,绑定到了类里,加入到了Spring缓存。
下面再看另一个核心注解@DubboComponentScan源码:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(DubboComponentScanRegistrar.class)
public @interface DubboComponentScan
/**
* Alias for the @link #basePackages() attribute. Allows for more concise annotation
* declarations e.g.: @code @DubboComponentScan("org.my.pkg") instead of
* @code @DubboComponentScan(basePackages="org.my.pkg").
*
* @return the base packages to scan
*/
String[] value() default ;
/**
* Base packages to scan for annotated @Service classes. @link #value() is an
* alias for (and mutually exclusive with) this attribute.
* <p>
* Use @link #basePackageClasses() for a type-safe alternative to String-based
* package names.
*
* @return the base packages to scan
*/
String[] basePackages() default ;
/**
* Type-safe alternative to @link #basePackages() for specifying the packages to
* scan for annotated @Service classes. The package of each class specified will be
* scanned.
*
* @return classes from the base packages to scan
*/
Class<?>[] basePackageClasses() default ;
可以看到@Import进来了DubboComponentScanRegistrar类,看其源码:
public class DubboComponentScanRegistrar implements ImportBeanDefinitionRegistrar
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry)
Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
registerServiceAnnotationBeanPostProcessor(packagesToScan, registry);
registerReferenceAnnotationBeanPostProcessor(registry);
/**
* Registers @link ServiceAnnotationBeanPostProcessor
*
* @param packagesToScan packages to scan without resolving placeholders
* @param registry @link BeanDefinitionRegistry
* @since 2.5.8
*/
private void registerServiceAnnotationBeanPostProcessor(Set<String> packagesToScan, BeanDefinitionRegistry registry)
BeanDefinitionBuilder builder = rootBeanDefinition(ServiceAnnotationBeanPostProcessor.class);
builder.addConstructorArgValue(packagesToScan);
builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);
/**
* Registers @link ReferenceAnnotationBeanPostProcessor into @link BeanFactory
*
* @param registry @link BeanDefinitionRegistry
*/
private void registerReferenceAnnotationBeanPostProcessor(BeanDefinitionRegistry registry)
// Register @Reference Annotation Bean Processor
BeanRegistrar.registerInfrastructureBean(registry,
ReferenceAnnotationBeanPostProcessor.BEAN_NAME, ReferenceAnnotationBeanPostProcessor.class);
private Set<String> getPackagesToScan(AnnotationMetadata metadata)
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
metadata.getAnnotationAttributes(DubboComponentScan.class.getName()));
String[] basePackages = attributes.getStringArray("basePackages");
Class<?>[] basePackageClasses = attributes.getClassArray("basePackageClasses");
String[] value = attributes.getStringArray("value");
// Appends value array attributes
Set<String> packagesToScan = new LinkedHashSet<String>(Arrays.asList(value));
packagesToScan.addAll(Arrays.asList(basePackages));
for (Class<?> basePackageClass : basePackageClasses)
packagesToScan.add(ClassUtils.getPackageName(basePackageClass));
if (packagesToScan.isEmpty())
return Collections.singleton(ClassUtils.getPackageName(metadata.getClassName()));
return packagesToScan;
可以看到里面有registerServiceAnnotationBeanPostProcessor方法和registerReferenceAnnotationBeanPostProcessor方法。这里注册进来两个BeanPostProcessor,一个用于扫描@Service注解,一个用于扫描@Reference注解。
总结
@EnableDubbo做了两件事,一个是初始化Dubbo核心组件,加载Dubbo配置到内存。另一个是注册BeanPostProcessor,用来扫描@Service和@Reference注解。
以上是关于Dubbo中@EnableDubbo注解原理的主要内容,如果未能解决你的问题,请参考以下文章