# Dubbo源码解析:基于注解配置原理解析

# 使用注解开发一个Dubbo应用
# 客户端
@Component("demoServiceComponent")
public class DemoServiceComponent implements DemoService {
@Reference
private DemoService demoService;
@Override
public String sayHello(String name) {
return demoService.sayHello(name);
}
}
dubbo-consumer.properties
dubbo.application.name=dubbo-demo-annotation-consumer
dubbo.registry.address=zookeeper://myhost:2181
public class Application {
/**
* In order to make sure multicast registry works, need to specify '-Djava.net.preferIPv4Stack=true' before
* launch the application
*/
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConsumerConfiguration.class);
context.start();
DemoService service = context.getBean("demoServiceComponent", DemoServiceComponent.class);
String hello = service.sayHello("world");
System.out.println("result :" + hello);
}
@Configuration
@EnableDubbo(scanBasePackages = "org.apache.dubbo.demo.consumer.comp")
@PropertySource("classpath:/spring/dubbo-consumer.properties")
@ComponentScan(value = {"org.apache.dubbo.demo.consumer.comp"})
static class ConsumerConfiguration {
}
}
@Configuration:表明这是一个配置类 @EnableDubbo:最主要的一个注解,后面详细分析 @PropertySourc:指定配置文件地址 @ComponentScan:配置包扫描,将类注入容器
# 服务端
@Service
public class DemoServiceImpl implements DemoService {
private static final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class);
@Override
public String sayHello(String name) {
logger.info("Hello " + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress());
return "Hello " + name + ", response from provider: " + RpcContext.getContext().getLocalAddress();
}
}
dubbo-provider.properties
dubbo.application.name=dubbo-demo-annotation-provider
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
public class Application {
/**
* In order to make sure multicast registry works, need to specify '-Djava.net.preferIPv4Stack=true' before
* launch the application
*/
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProviderConfiguration.class);
context.start();
System.in.read();
}
@Configuration
@EnableDubbo(scanBasePackages = "org.apache.dubbo.demo.provider")
@PropertySource("classpath:/spring/dubbo-provider.properties")
static class ProviderConfiguration {
@Bean
public RegistryConfig registryConfig() {
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setAddress("zookeeper://myhost:2181");
return registryConfig;
}
}
}
# @EnableDubbo解密
从前面的例子中我们可以发现,起主要作用的注解是@EnableDubbo,接着我们就详细分析一这个注解的作用
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@EnableDubboConfig
@DubboComponentScan
public @interface EnableDubbo {
@AliasFor(annotation = DubboComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
@AliasFor(annotation = DubboComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};
@AliasFor(annotation = EnableDubboConfig.class, attribute = "multiple")
boolean multipleConfig() default true;
}
@EnableDubbo又再次引入了2个注解。可以看到@EnableDubbo配置的各种包扫描其实是@DubboComponentScan的属性,给@DubboComponentScan用的。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Import(DubboConfigConfigurationRegistrar.class)
public @interface EnableDubboConfig {
boolean multiple() default true;
}
# @EnableDubboConfig注解的作用
@EnableDubboConfig引入了DubboConfigConfigurationRegistrar
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);
}
}
}
DubboConfigConfigurationRegistrar只是往容器中注入了2个Bean。DubboConfigConfiguration.Single.class和DubboConfigConfiguration.Multiple.class 这2个类的作用差不多,只分析一个
@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),
@EnableDubboConfigBinding(prefix = "dubbo.config-center", type = ConfigCenterBean.class),
@EnableDubboConfigBinding(prefix = "dubbo.metadata-report", type = MetadataReportConfig.class)
})
public static class Single {
}
类上有@EnableDubboConfigBindings注解,然后引入了DubboConfigBindingsRegistrar类
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(DubboConfigBindingsRegistrar.class)
public @interface EnableDubboConfigBindings {
EnableDubboConfigBinding[] value();
}
DubboConfigBindingsRegistrar这个类的作用很简单,就是将配置文件中的配置转为对应的对象,并注入容器中。
如将以dubbo.application为前缀的配置转为ApplicationConfig对象,将以dubbo.registry为前缀的配置转为RegistryConfig对象

# @DubboComponentScan的作用
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(DubboComponentScanRegistrar.class)
public @interface DubboComponentScan {
String[] value() default {};
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
}
引入DubboComponentScanRegistrar
public class DubboComponentScanRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
registerServiceAnnotationBeanPostProcessor(packagesToScan, registry);
registerReferenceAnnotationBeanPostProcessor(registry);
}
}
DubboComponentScanRegistrar会往容器中注入2个BeanPostProcessor
ServiceAnnotationBeanPostProcessor:将包扫描路径中被@Service标注的类,转为ServiceBean,并注入到容器中 ReferenceAnnotationBeanPostProcessor:将被@Reference标注的属性,赋值为对应的ReferenceBean对象
