Dubbo与Spring的整合原理与流程分析
看Dubbo整合Spring的使用, 几个注解就结束了,但是内部运作原理一概不知, 框架内部报错,丢出异常都不知道是怎么回事, 最终还是决定花点时间看看dubbo的一些流程源码。
主要内容
看看Dubbo与Spring是如何做到无缝结合, 以及注解类是怎么被加载的。
- Dubbo中propertie?件解析以及处理流程原理
- Dubbo中@Service注解解析以及处理流程原理
- Dubbo中@Reference注解解析以及处理流程原理
启动类
public class 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 {
}
}
两个关键的注解:
- @EnableDubbo注解:指定我们dubbo服务类的包路径, 这些服务类是使用Dubbo服务的@Service注解修饰的服务类;
- @PropertySource注解: 用来指定我们Dubbo配置文件的路径, 然后通过@Value注解使用配置文件的内容,类似SpringBoot的application.properties文件一样被加载;
1. @EnableDubbo注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@EnableDubboConfig
@DubboComponentScan
public @interface EnableDubbo {
}
该注解上面有两个关键的注解:
- EnableDubboConfig
读取properties配置文件, 并将配置转换成一个个的配置Bean; - DubboComponentScan
扫描服务提供者和引用者类(即使用@Service修饰的类)
2. @EnableDubboConfig与@DubboComponentScan
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Import(DubboConfigConfigurationRegistrar.class)
public @interface EnableDubboConfig {
boolean multiple() default true;
}
通过@Import注解,引入DubboConfigConfigurationRegistrar类, 将这个类转换一个Bean注入容器, 另外, 还会使用这个类将所有的配置转换成Bean注入容器;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(DubboComponentScanRegistrar.class)
public @interface DubboComponentScan {
String[] value() default {};
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
}
通过@Import注解,引入DubboComponentScanRegistrar类, 将这个类转换一个Bean注入容器, 另外, 还会使用这个类扫描所有的服务提供类,转换成ServiceBean注入容器;
3. 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");
registerBeans(registry, DubboConfigConfiguration.Single.class);
if (multiple) {
registerBeans(registry, DubboConfigConfiguration.Multiple.class);
}
}
}
- 获取EnableDubboConfig的所有属性值;
- 获取EnableDubboConfig的Multiple值;
- 注册单例绑定Bean;
- 注册多例绑定Bean;
当Spring启动后, 肯定会通过AnnotationBeanDefinitionReader来执行registerBeanDefinitions方法的。(看了挺多博客, 都是这么说, Spring源码没了解那么深);
3.1 DubboConfigConfiguration.Single类
@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),
@EnableDubboConfigBinding(prefix = "dubbo.metrics", type = MetricsConfig.class)
})
public static class Single {
}
Single类 通过 @EnableDubboConfigBinding注解可以看出,根据Dubbo的配置前缀进行Bean类型的绑定, 例如dubbo.application配置, 对应的类型是一个ApplicationConfig类的Bean;
3.2 DubboConfigConfiguration.Multiple
@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),
@EnableDubboConfigBinding(prefix = "dubbo.config-centers", type = ConfigCenterBean.class, multiple = true),
@EnableDubboConfigBinding(prefix = "dubbo.metadata-reports", type = MetadataReportConfig.class, multiple = true),
@EnableDubboConfigBinding(prefix = "dubbo.metricses", type = MetricsConfig.class, multiple = true)
})
public static class Multiple {
}
#dubbo.protocol.name=dubbo
#dubbo.protocol.port=20881
#dubbo.protocol.host=0.0.0.0
dubbo.protocols.p1.name=dubbo
dubbo.protocols.p1.port=20880
dubbo.protocols.p1.host=0.0.0.0
dubbo.protocols.p2.name=dubbo
dubbo.protocols.p2.port=20881
dubbo.protocols.p2.host=0.0.0.0
- dubbo.protocol.: 会生成单个Bean, Bean的类型是ProtocolConfig
- dubbo.protocols: 会生成多个Bean, Bean的类型是ProtocolConfig, Bean的名称与p1, p2有关
3.3 @EnableDubboConfigBindings注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(DubboConfigBindingsRegistrar.class)
public @interface EnableDubboConfigBindings {
EnableDubboConfigBinding[] value();
}
- value值是一个EnableDubboConfigBinding数组
- 通过@Import注解,导入DubboConfigBindingsRegistrar.class类, 该类会获取@EnableDubboConfigBindings注解中的value,也就是多个@EnableDubboConfigBinding注解,然后利用DubboConfigBindingRegistrar去处理这些@EnableDubboConfigBinding注解。
DubboConfigBindingsRegistrar
- Spring启动时, AnnotationBeanDefinitionReader来执行registerBeanDefinitions方法;
public class DubboConfigBindingsRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware {
private ConfigurableEnvironment environment;
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
System.out.println("执行DubboConfigBindingsRegistrar");
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
importingClassMetadata.getAnnotationAttributes(EnableDubboConfigBindings.class.getName()));
AnnotationAttributes[] annotationAttributes = attributes.getAnnotationArray("value");
DubboConfigBindingRegistrar registrar = new DubboConfigBindingRegistrar();
registrar.setEnvironment(environment);
for (AnnotationAttributes element : annotationAttributes) {
registrar.registerBeanDefinitions(element, registry);
}
}
}
- 获取EnableDubboConfigBindings所有的属性值
- 获取EnableDubboConfigBindings的value属性值;
- 创建配置绑定注册Bean工具类对象, 用来注册一个个的配置Bean
- 遍历循环, 逐个解析@EnableDubboConfigBinding注解类;第一个参数事注解类信息,第二个参数是Spring容器,方便将Bean注入容器;
DubboConfigBindingRegistrar
解析@EnableDubboConfigBinding注解类
public class DubboConfigBindingRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware {
private final Log log = LogFactory.getLog(getClass());
private ConfigurableEnvironment environment;
protected void registerBeanDefinitions(AnnotationAttributes attributes, BeanDefinitionRegistry registry) {
String prefix = environment.resolvePlaceholders(attributes.getString("prefix"));
Class<? extends AbstractConfig> configClass = attributes.getClass("type");
boolean multiple = attributes.getBoolean("multiple");
registerDubboConfigBeans(prefix, configClass, multiple, registry);
}
}
作用:
- 获取绑定注解prefix属性, 即配置的属性dubbo.application
- 获取绑定注解type属性, 是每一中配置对应的类型Class信息;
- 获取绑定注解multiple属性
- 根据prefix, type, multipart生成Bean注入容器registry;
private void registerDubboConfigBeans(String prefix,
Class<? extends AbstractConfig> configClass,
boolean multiple,
BeanDefinitionRegistry registry) {
Map<String, Object> properties = getSubProperties(environment.getPropertySources(), prefix);
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;
}
Set<String> beanNames = multiple ? resolveMultipleBeanNames(properties) :
Collections.singleton(resolveSingleBeanName(properties, configClass, registry));
for (String beanName : beanNames) {
registerDubboConfigBean(beanName, configClass, registry);
registerDubboConfigBindingBeanPostProcessor(prefix, beanName, multiple, registry);
}
registerDubboConfigBeanCustomizers(registry);
}
工作:
- getSubProperties:获取propertis信息中,包含了绑定注解前缀prefix的配置
- resolveMultipleBeanNames | resolveSingleBeanName: 生成注入容器的Bean的名称;
- 遍历生成的Bean名称;
3.1 registerDubboConfigBean为每个Bean名称注入一个空的BeanDefinition对象 3.2 registerDubboConfigBindingBeanPostProcessor为每个Bean注册一个DubboConfigBindingBeanPostProcessor后置处理器; - registerDubboConfigBeanCustomizers:注册一个NamePropertyDefaultValueDubboConfigBeanCustomizer的bean
- getSubProperties(Iterable<PropertySource<?>> propertySources, String prefix)
public static Map<String, Object> getSubProperties(Iterable<PropertySource<?>> propertySources, String prefix) {
AbstractEnvironment environment = new AbstractEnvironment() {
};
MutablePropertySources mutablePropertySources = environment.getPropertySources();
for (PropertySource<?> source : propertySources) {
mutablePropertySources.addLast(source);
}
return getSubProperties(environment, prefix);
}
public static Map<String, Object> getSubProperties(ConfigurableEnvironment environment, String prefix) {
Map<String, Object> subProperties = new LinkedHashMap<>();
MutablePropertySources propertySources = environment.getPropertySources();
String normalizedPrefix = normalizePrefix(prefix);
for (PropertySource<?> source : propertySources) {
if (source instanceof EnumerablePropertySource) {
for (String name : ((EnumerablePropertySource<?>) source).getPropertyNames()) {
if (!subProperties.containsKey(name) && name.startsWith(normalizedPrefix)) {
String subName = name.substring(normalizedPrefix.length());
if (!subProperties.containsKey(subName)) {
Object value = source.getProperty(name);
if (value instanceof String) {
value = environment.resolvePlaceholders((String) value);
}
subProperties.put(subName, value);
}
}
}
}
}
return Collections.unmodifiableMap(subProperties);
}
- resolveMultipleBeanNames(properties)
获取Multiple下的bean名称;
private Set<String> resolveMultipleBeanNames(Map<String, Object> properties) {
Set<String> beanNames = new LinkedHashSet<String>();
for (String propertyName : properties.keySet()) {
int index = propertyName.indexOf(".");
if (index > 0) {
String beanName = propertyName.substring(0, index);
beanNames.add(beanName);
}
}
return beanNames;
}
- resolveSingleBeanName(properties, configClass, registry)
获取single配置的Bean名称;
private String resolveSingleBeanName(Map<String, Object> properties, Class<? extends AbstractConfig> configClass,
BeanDefinitionRegistry registry) {
String beanName = (String) properties.get("id");
if (!StringUtils.hasText(beanName)) {
BeanDefinitionBuilder builder = rootBeanDefinition(configClass);
beanName = BeanDefinitionReaderUtils.generateBeanName(builder.getRawBeanDefinition(), registry);
}
return beanName;
}
- registerDubboConfigBean(beanName, configClass, registry)
创建一个空的BeanDefinition类,并放入IOC容器
private void registerDubboConfigBean(String beanName, Class<? extends AbstractConfig> configClass,
BeanDefinitionRegistry registry) {
BeanDefinitionBuilder builder = rootBeanDefinition(configClass);
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
registry.registerBeanDefinition(beanName, beanDefinition);
if (log.isInfoEnabled()) {
log.info("The dubbo config bean definition [name : " + beanName + ", class : " + configClass.getName() +
"] has been registered.");
}
}
- registerDubboConfigBindingBeanPostProcessor(prefix, beanName, multiple, registry)
创建一个DubboConfigBindingBeanPostProcessor后置处理器, 并注入容器;
private void registerDubboConfigBindingBeanPostProcessor(String prefix, String beanName, boolean multiple,
BeanDefinitionRegistry registry) {
Class<?> processorClass = DubboConfigBindingBeanPostProcessor.class;
BeanDefinitionBuilder builder = rootBeanDefinition(processorClass);
String actualPrefix = multiple ? normalizePrefix(prefix) + beanName : prefix;
builder.addConstructorArgValue(actualPrefix).addConstructorArgValue(beanName);
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registerWithGeneratedName(beanDefinition, registry);
if (log.isInfoEnabled()) {
log.info("The BeanPostProcessor bean definition [" + processorClass.getName()
+ "] for dubbo config bean [name : " + beanName + "] has been registered.");
}
}
public static String registerWithGeneratedName(AbstractBeanDefinition definition, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
String generatedName = generateBeanName(definition, registry, false);
registry.registerBeanDefinition(generatedName, definition);
return generatedName;
}
public static String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry, boolean isInnerBean) throws BeanDefinitionStoreException {
String generatedBeanName = definition.getBeanClassName();
if (!StringUtils.hasText(generatedBeanName)) {
} else {
String id = generatedBeanName;
if (isInnerBean) {
id = generatedBeanName + "#" + ObjectUtils.getIdentityHexString(definition);
} else {
for(int counter = -1; counter == -1 || registry.containsBeanDefinition(id); id = generatedBeanName + "#" + counter) {
++counter;
}
}
return id;
}
}
3. registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry)
注册各个Dubbo配置Bean到容器中;
public class DubboConfigConfigurationRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
System.out.println("执行DubboConfigConfigurationRegistrar");
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
importingClassMetadata.getAnnotationAttributes(EnableDubboConfig.class.getName()));
boolean multiple = attributes.getBoolean("multiple");
registerBeans(registry, DubboConfigConfiguration.Single.class);
if (multiple) {
registerBeans(registry, DubboConfigConfiguration.Multiple.class);
}
}
}
回到开头的第3步骤;
4. registerBeans(registry, DubboConfigConfiguration.Multiple.class)
Spring中的AnnotatedBeanDefinitionReader来解析annotatedClasses会解析该类上的注解,然后进行处理
public static void registerBeans(BeanDefinitionRegistry registry, Class<?>... annotatedClasses) {
if (ObjectUtils.isEmpty(annotatedClasses)) {
return;
}
Iterator<Class<?>> iterator = new ArrayList<>(asList(annotatedClasses)).iterator();
while (iterator.hasNext()) {
Class<?> annotatedClass = iterator.next();
if (isPresentBean(registry, annotatedClass)) {
iterator.remove();
}
}
AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(registry);
if (logger.isDebugEnabled()) {
logger.debug(registry.getClass().getSimpleName() + " will register annotated classes : " + asList(annotatedClasses) + " .");
}
reader.register(annotatedClasses);
}
总结
@EnableDubboConfig注解的作用就是通过DubboConfigConfigurationRegistrar 解析配置文件里面所有的dubbo配置项。
- 通过AnnotatedBeanDefinitionReader来解析Multiple/Single类型上的EnableDubboConfigBindings的值(是一个@EnableDubboConfigBinding数组)
- 读取配置文件中Dubbo的所有配置项,根据@EnableDubboConfigBinding绑定注解的prefix前缀,匹配配置项的key, 然后将单个配置项,或者一组配置项转换成一个个type类型Class的BeanDefinition的Bean, 注入IOC容器;
- 然后每个XxConfig的Bean会生成对应一个DubboConfigBindingBeanPostProcessor的Bean注入IOC容器
|