相关阅读
简介
本文基于Spring Boot 2.6.6 ,dubbo-spring-boot-starter 3.0.6 环境。
引入dubbo-spring-boot-starter 包,就会引入其依赖dubbo-spring-boot-autoconfigure ,该依赖实现了Dubbo自动配置功能,其spring.factories 文件内容如下:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.apache.dubbo.spring.boot.autoconfigure.DubboRelaxedBinding2AutoConfiguration
dubbo-spring-boot-autoconfigure 会引入依赖dubbo-spring-boot-autoconfigure-compatible ,该依赖也存在一个spring.factories 文件,其内容如下:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.apache.dubbo.spring.boot.autoconfigure.DubboAutoConfiguration,\
org.apache.dubbo.spring.boot.autoconfigure.DubboRelaxedBindingAutoConfiguration,\
org.apache.dubbo.spring.boot.autoconfigure.DubboListenerAutoConfiguration
org.springframework.context.ApplicationListener=\
org.apache.dubbo.spring.boot.context.event.WelcomeLogoApplicationListener
org.springframework.boot.env.EnvironmentPostProcessor=\
org.apache.dubbo.spring.boot.env.DubboDefaultPropertiesEnvironmentPostProcessor
org.springframework.context.ApplicationContextInitializer=\
org.apache.dubbo.spring.boot.context.DubboApplicationContextInitializer
综上可知,dubbo-spring-boot-autoconfigure 引入的自动配置类如下:
org.apache.dubbo.spring.boot.autoconfigure.DubboRelaxedBinding2AutoConfiguration ;org.apache.dubbo.spring.boot.autoconfigure.DubboAutoConfiguration ;org.apache.dubbo.spring.boot.autoconfigure.DubboRelaxedBindingAutoConfiguration ;org.apache.dubbo.spring.boot.autoconfigure.DubboListenerAutoConfiguration ;
DubboAutoConfiguration
DubboAutoConfiguration 是Dubbo自动配置的核心类,代码如下:
@ConditionalOnProperty(prefix = DUBBO_PREFIX, name = "enabled", matchIfMissing = true)
@Configuration
@AutoConfigureAfter(DubboRelaxedBindingAutoConfiguration.class)
@EnableConfigurationProperties(DubboConfigurationProperties.class)
@EnableDubboConfig
public class DubboAutoConfiguration {
@ConditionalOnProperty(prefix = DUBBO_SCAN_PREFIX, name = BASE_PACKAGES_PROPERTY_NAME)
@ConditionalOnBean(name = BASE_PACKAGES_BEAN_NAME)
@Bean
public ServiceAnnotationPostProcessor serviceAnnotationBeanProcessor(@Qualifier(BASE_PACKAGES_BEAN_NAME)
Set<String> packagesToScan) {
return new ServiceAnnotationPostProcessor(packagesToScan);
}
}
核心功能为:
- 引入属性配置类
DubboConfigurationProperties ; - 通过注解
EnableDubboConfig 开启Dubbo功能; - 注入
ServiceAnnotationPostProcessor 用于解析DubboService 注解;
DubboConfigurationProperties
DubboConfigurationProperties 声明了Dubbo中各组件的配置参数信息,核心代码如下:
@ConfigurationProperties(DUBBO_PREFIX)
public class DubboConfigurationProperties {
@NestedConfigurationProperty
private Config config = new Config();
@NestedConfigurationProperty
private Scan scan = new Scan();
@NestedConfigurationProperty
private ApplicationConfig application = new ApplicationConfig();
@NestedConfigurationProperty
private ModuleConfig module = new ModuleConfig();
@NestedConfigurationProperty
private RegistryConfig registry = new RegistryConfig();
@NestedConfigurationProperty
private ProtocolConfig protocol = new ProtocolConfig();
@NestedConfigurationProperty
private MonitorConfig monitor = new MonitorConfig();
@NestedConfigurationProperty
private ProviderConfig provider = new ProviderConfig();
@NestedConfigurationProperty
private ConsumerConfig consumer = new ConsumerConfig();
@NestedConfigurationProperty
private ConfigCenterBean configCenter = new ConfigCenterBean();
@NestedConfigurationProperty
private MetadataReportConfig metadataReport = new MetadataReportConfig();
@NestedConfigurationProperty
private MetricsConfig metrics = new MetricsConfig();
private Map<String, ModuleConfig> modules = new LinkedHashMap<>();
private Map<String, RegistryConfig> registries = new LinkedHashMap<>();
private Map<String, ProtocolConfig> protocols = new LinkedHashMap<>();
private Map<String, MonitorConfig> monitors = new LinkedHashMap<>();
private Map<String, ProviderConfig> providers = new LinkedHashMap<>();
private Map<String, ConsumerConfig> consumers = new LinkedHashMap<>();
private Map<String, ConfigCenterBean> configCenters = new LinkedHashMap<>();
private Map<String, MetadataReportConfig> metadataReports = new LinkedHashMap<>();
private Map<String, MetricsConfig> metricses = new LinkedHashMap<>();
}
EnableDubboConfig
EnableDubboConfig 的核心就是引入DubboConfigConfigurationRegistrar ,代码如下:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Import(DubboConfigConfigurationRegistrar.class)
public @interface EnableDubboConfig {
boolean multiple() default true;
}
DubboConfigConfigurationRegistrar 的registerBeanDefinitions 方法就是初始化Dubbo相关的Bean,代码如下:
public class DubboConfigConfigurationRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
DubboSpringInitializer.initialize(registry);
}
}
DubboSpringInitializer
DubboSpringInitializer 是Dubbo Spring初始化的入口,其initialize 代码如下:
public static void initialize(BeanDefinitionRegistry registry) {
if (contextMap.putIfAbsent(registry, new DubboSpringInitContext()) != null) {
return;
}
DubboSpringInitContext context = contextMap.get(registry);
ConfigurableListableBeanFactory beanFactory = findBeanFactory(registry);
initContext(context, registry, beanFactory);
}
private static void initContext(DubboSpringInitContext context, BeanDefinitionRegistry registry,
ConfigurableListableBeanFactory beanFactory) {
context.setRegistry(registry);
context.setBeanFactory(beanFactory);
customize(context);
ModuleModel moduleModel = context.getModuleModel();
if (moduleModel == null) {
ApplicationModel applicationModel;
if (findContextForApplication(ApplicationModel.defaultModel()) == null) {
applicationModel = ApplicationModel.defaultModel();
logger.info("Use default application: " + safeGetModelDesc(applicationModel));
} else {
applicationModel = FrameworkModel.defaultModel().newApplication();
logger.info("Create new application: " + safeGetModelDesc(applicationModel));
}
moduleModel = applicationModel.getDefaultModule();
context.setModuleModel(moduleModel);
logger.info("Use default module model of target application: " + safeGetModelDesc(moduleModel));
} else {
logger.info("Use module model from customizer: " + safeGetModelDesc(moduleModel));
}
logger.info("Bind " + safeGetModelDesc(moduleModel) + " to spring container: " + ObjectUtils.identityToString(registry));
if (context.getModuleAttributes().size() > 0) {
context.getModuleModel().getAttributes().putAll(context.getModuleAttributes());
}
registerContextBeans(beanFactory, context);
context.markAsBound();
DubboBeanUtils.registerCommonBeans(registry);
}
DubboSpringInitializer.initContext 将初始化后的DubboSpringInitContext 注册到Spring容器中,用户可实现自定义DubboSpringInitCustomizer 来定制化处理DubboSpringInitContext ;再借助DubboBeanUtils 注册其它Dubbo Bean; DubboBeanUtils.registerCommonBeans 方法代码如下:
static void registerCommonBeans(BeanDefinitionRegistry registry) {
registerInfrastructureBean(registry, ServicePackagesHolder.BEAN_NAME, ServicePackagesHolder.class);
registerInfrastructureBean(registry, ReferenceBeanManager.BEAN_NAME, ReferenceBeanManager.class);
registerInfrastructureBean(registry, ReferenceAnnotationBeanPostProcessor.BEAN_NAME,
ReferenceAnnotationBeanPostProcessor.class);
registerInfrastructureBean(registry, DubboConfigAliasPostProcessor.BEAN_NAME,
DubboConfigAliasPostProcessor.class);
registerInfrastructureBean(registry, DubboDeployApplicationListener.class.getName(), DubboDeployApplicationListener.class);
registerInfrastructureBean(registry, DubboConfigApplicationListener.class.getName(), DubboConfigApplicationListener.class);
registerInfrastructureBean(registry, DubboConfigDefaultPropertyValueBeanPostProcessor.BEAN_NAME,
DubboConfigDefaultPropertyValueBeanPostProcessor.class);
registerInfrastructureBean(registry, DubboConfigBeanInitializer.BEAN_NAME, DubboConfigBeanInitializer.class);
registerInfrastructureBean(registry, DubboInfraBeanRegisterPostProcessor.BEAN_NAME, DubboInfraBeanRegisterPostProcessor.class);
}
ServiceAnnotationPostProcessor
当存在配置参数dubbo.scan.base-packages 且该参数以dubbo-service-class-base-packages Bean存在于Spring容器中,那么就需要注入ServiceAnnotationPostProcessor 用于发现注解DubboService 标注的类; ServiceAnnotationPostProcessor 支持的注解类型如下:
private final static List<Class<? extends Annotation>> serviceAnnotationTypes = asList(
DubboService.class,
Service.class,
com.alibaba.dubbo.config.annotation.Service.class
);
ServiceAnnotationPostProcessor 实现了接口BeanFactoryPostProcessor ,可用于在Bean初始化前对BeanFactory做处理;AbstractApplicationContext.refresh 方法中执行invokeBeanFactoryPostProcessors(beanFactory) ,会执行Spring容器中所有的BeanFactoryPostProcessor ;ServiceAnnotationPostProcessor.postProcessBeanDefinitionRegistry 主要是将指定扫描包路径下的标注了Dubbo Service注解的类包装为AbstractBeanDefinition 并注入Spring容器,核心代码如下:
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
this.registry = registry;
scanServiceBeans(resolvedPackagesToScan, registry);
}
private void scanServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
scaned = true;
if (CollectionUtils.isEmpty(packagesToScan)) {
if (logger.isWarnEnabled()) {
logger.warn("packagesToScan is empty , ServiceBean registry will be ignored!");
}
return;
}
DubboClassPathBeanDefinitionScanner scanner =
new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);
BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry);
scanner.setBeanNameGenerator(beanNameGenerator);
for (Class<? extends Annotation> annotationType : serviceAnnotationTypes) {
scanner.addIncludeFilter(new AnnotationTypeFilter(annotationType));
}
ScanExcludeFilter scanExcludeFilter = new ScanExcludeFilter();
scanner.addExcludeFilter(scanExcludeFilter);
for (String packageToScan : packagesToScan) {
if (servicePackagesHolder.isPackageScanned(packageToScan)) {
if (logger.isInfoEnabled()) {
logger.info("Ignore package who has already bean scanned: " + packageToScan);
}
continue;
}
scanner.scan(packageToScan);
Set<BeanDefinitionHolder> beanDefinitionHolders =
findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator);
if (!CollectionUtils.isEmpty(beanDefinitionHolders)) {
if (logger.isInfoEnabled()) {
List<String> serviceClasses = new ArrayList<>(beanDefinitionHolders.size());
for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
serviceClasses.add(beanDefinitionHolder.getBeanDefinition().getBeanClassName());
}
logger.info("Found " + beanDefinitionHolders.size() + " classes annotated by Dubbo @Service under package [" + packageToScan + "]: " + serviceClasses);
}
for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
processScannedBeanDefinition(beanDefinitionHolder, registry, scanner);
servicePackagesHolder.addScannedClass(beanDefinitionHolder.getBeanDefinition().getBeanClassName());
}
} else {
if (logger.isWarnEnabled()) {
logger.warn("No class annotated by Dubbo @Service was found under package ["
+ packageToScan + "], ignore re-scanned classes: " + scanExcludeFilter.getExcludedCount());
}
}
servicePackagesHolder.addScannedPackage(packageToScan);
}
}
private void processScannedBeanDefinition(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry,
DubboClassPathBeanDefinitionScanner scanner) {
Class<?> beanClass = resolveClass(beanDefinitionHolder);
Annotation service = findServiceAnnotation(beanClass);
Map<String, Object> serviceAnnotationAttributes = AnnotationUtils.getAttributes(service, true);
String serviceInterface = resolveInterfaceName(serviceAnnotationAttributes, beanClass);
String annotatedServiceBeanName = beanDefinitionHolder.getBeanName();
String beanName = generateServiceBeanName(serviceAnnotationAttributes, serviceInterface);
AbstractBeanDefinition serviceBeanDefinition =
buildServiceBeanDefinition(serviceAnnotationAttributes, serviceInterface, annotatedServiceBeanName);
registerServiceBeanDefinition(beanName, serviceBeanDefinition, serviceInterface);
}
private AbstractBeanDefinition buildServiceBeanDefinition(Map<String, Object> serviceAnnotationAttributes,
String serviceInterface,
String refServiceBeanName) {
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");
propertyValues.addPropertyValues(new AnnotationPropertyValuesAdapter(serviceAnnotationAttributes, environment, ignoreAttributeNames));
addPropertyReference(builder, "ref", refServiceBeanName);
builder.addPropertyValue("interface", serviceInterface);
builder.addPropertyValue("parameters", DubboAnnotationUtils.convertParameters((String[]) serviceAnnotationAttributes.get("parameters")));
List<MethodConfig> methodConfigs = convertMethodConfigs(serviceAnnotationAttributes.get("methods"));
if (!methodConfigs.isEmpty()) {
builder.addPropertyValue("methods", methodConfigs);
}
String providerConfigId = (String) serviceAnnotationAttributes.get("provider");
if (StringUtils.hasText(providerConfigId)) {
addPropertyValue(builder, "providerIds", providerConfigId);
}
String[] registryConfigIds = (String[]) serviceAnnotationAttributes.get("registry");
if (registryConfigIds != null && registryConfigIds.length > 0) {
resolveStringArray(registryConfigIds);
builder.addPropertyValue("registryIds", StringUtils.join(registryConfigIds, ','));
}
String[] protocolConfigIds = (String[]) serviceAnnotationAttributes.get("protocol");
if (protocolConfigIds != null && protocolConfigIds.length > 0) {
resolveStringArray(protocolConfigIds);
builder.addPropertyValue("protocolIds", StringUtils.join(protocolConfigIds, ','));
}
String monitorConfigId = (String) serviceAnnotationAttributes.get("monitor");
if (StringUtils.hasText(monitorConfigId)) {
addPropertyReference(builder, "monitor", monitorConfigId);
}
String moduleConfigId = (String) serviceAnnotationAttributes.get("module");
if (StringUtils.hasText(moduleConfigId)) {
addPropertyReference(builder, "module", moduleConfigId);
}
return builder.getBeanDefinition();
}
DubboRelaxedBindingAutoConfiguration
DubboRelaxedBindingAutoConfiguration 会注入dubbo-service-class-base-packages Bean,用于配置ServiceAnnotationPostProcessor ,其配置条件如下:
@ConditionalOnProperty(prefix = DUBBO_PREFIX, name = "enabled", matchIfMissing = true)
@ConditionalOnClass(name = "org.springframework.boot.bind.RelaxedPropertyResolver")
如上所述,本类适配Spring Boot 1.x,而本文基于Spring Boot 2.6.6,故不会触发DubboRelaxedBindingAutoConfiguration 自动配置;DubboRelaxedBinding2AutoConfiguration 适配Spring Boot 2.0及以上;
DubboRelaxedBinding2AutoConfiguration
和DubboRelaxedBindingAutoConfiguration 作用一样,DubboRelaxedBinding2AutoConfiguration 会注入dubbo-service-class-base-packages Bean,用于配置ServiceAnnotationPostProcessor ,其配置条件如下:
@ConditionalOnProperty(prefix = DUBBO_PREFIX, name = "enabled", matchIfMissing = true)
@ConditionalOnClass(name = "org.springframework.boot.context.properties.bind.Binder")
@AutoConfigureBefore(DubboRelaxedBindingAutoConfiguration.class)
本文基于Spring Boot 2.6.6,故会触发DubboRelaxedBinding2AutoConfiguration 自动配置,其注入Bean代码如下:
public PropertyResolver dubboScanBasePackagesPropertyResolver(ConfigurableEnvironment environment) {
ConfigurableEnvironment propertyResolver = new AbstractEnvironment() {
@Override
protected void customizePropertySources(MutablePropertySources propertySources) {
Map<String, Object> dubboScanProperties = getSubProperties(environment.getPropertySources(), DUBBO_SCAN_PREFIX);
propertySources.addLast(new MapPropertySource("dubboScanProperties", dubboScanProperties));
}
};
ConfigurationPropertySources.attach(propertyResolver);
return propertyResolver;
}
@ConditionalOnMissingBean(name = BASE_PACKAGES_BEAN_NAME)
@Bean(name = BASE_PACKAGES_BEAN_NAME)
public Set<String> dubboBasePackages(ConfigurableEnvironment environment) {
PropertyResolver propertyResolver = dubboScanBasePackagesPropertyResolver(environment);
return propertyResolver.getProperty(BASE_PACKAGES_PROPERTY_NAME, Set.class, emptySet());
}
@ConditionalOnMissingBean(name = RELAXED_DUBBO_CONFIG_BINDER_BEAN_NAME, value = ConfigurationBeanBinder.class)
@Bean(RELAXED_DUBBO_CONFIG_BINDER_BEAN_NAME)
@Scope(scopeName = SCOPE_PROTOTYPE)
public ConfigurationBeanBinder relaxedDubboConfigBinder() {
return new BinderDubboConfigBinder();
}
DubboListenerAutoConfiguration
DubboListenerAutoConfiguration 用于注册Dubbo相关的ApplicationListener Bean如果不存在的话,代码如下:
@ConditionalOnProperty(prefix = DUBBO_PREFIX, name = "enabled", matchIfMissing = true)
@Configuration
public class DubboListenerAutoConfiguration {
@ConditionalOnMissingBean
@Bean
public DubboConfigBeanDefinitionConflictApplicationListener dubboConfigBeanDefinitionConflictApplicationListener() {
return new DubboConfigBeanDefinitionConflictApplicationListener();
}
@ConditionalOnMissingBean
@Bean
public AwaitingNonWebApplicationListener awaitingNonWebApplicationListener() {
return new AwaitingNonWebApplicationListener();
}
}
|