springboot集成dubbo过程详解
作者:hello_zzw
本文详细介绍了Spring Boot集成Dubbo的过程,包括多个BeanPostProcessor和初始化器的作用,以及ClassPathBeanDefinitionScanner和DubboClassPathBeanDefinitionScanner的使用方法
springboot集成dubbo
BeanDefinitionRegistryPostProcessor
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
/**
* 允许开发者在Spring容器加载Bean定义(BeanDefinition)后,实例化Bean之前,动态修改或注册新的BeanDefinition
* 该接口在框架内部被广泛用于添加特殊Bean,也可用于自定义扩展
* 核心作用:
* 1.动态注册BeanDefinition:可以在运行时向容器中添加新的BeanDefinition,无需在配置文件中静态声明。
* 2.修改现有BeanDefinition:可以修改已注册的BeanDefinition属性(如作用域、懒加载等)
* 3.高级配置处理:在Bean实例化前完成复杂的配置解析或依赖处理
* 执行实际:
* 1.早于其他类型的BeanFactoryPostProcessor:Spring会先调用所有的BeanDefinitionRegistryPostProcessor,再调用其他类型的后处理器
* 2.在Bean实例化前:此时BeanDefinition已经加载,但所有Bean都未进行实例化
*/
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
BeanFactoryPostProcessor
@FunctionalInterface
public interface BeanFactoryPostProcessor {
/**
* Spring框架中的一个核心扩展点,允许开发这在Bean定义加载完成后、Bean实例化之前修改Bean定义。
* 主要作用:
* 1.动态修改Bean定义:可以在运行时调整Bean的属性值、作用域、依赖关系等
* 2.注册新的Bean定义:通过BeanDefinitionRegistry接口添加新的Bean定义
* 3.替换或增强Bean定义:例如,使用自定义实现替换某些Bean的默认配置
* 4.环境变量处理:解析占位符、注入外部配置等
* 5.框架扩展:Spring内部使用此机制实现了许多功能,如: PropertySourcesPlaceholderConfigurer 和 ConfigurationClassPostProcessor。
* 工作原理:
* 1.执行时机:在所有Bean定义加载完成后,Bean实例化之前执行。
* 2.顺序控制:通过实现Ordered或PriorityOrdered接口控制执行顺序。
* 3.处理对象:执行处理BeanDefinition,而非Bean实例。
* 典型应用场景:
* 1.属性占位符替换:动态替换配置文件中的${}占位符
* 2.条件性Bean注册:根据环境变量决定是否注册某些Bean
* 3.Bean定义增强:为特定Bean添加额外属性或方法
* 4.依赖注入调整:修改Bean之间的依赖注入关系
*/
void postProcessBeanFactory(ConfigurableListableBeanFactory var1) throws BeansException;
}
BeanPostProcessor
public interface BeanPostProcessor {
/**
* 用在Bean初始化之前进行自定义处理的关键方法
* 允许开发者在Bean实例化并完成依赖注入后,调用初始化回调(如 InitializingBean.afterPropertiesSet() 或 @PostConstruct)之前,对Bean进行额外处理。
* 核心功能:
* 1.实例化后处理:在Bean实例化并填充属性后执行。
* 2.自定义初始话:在Spring标准初始化回调前执行自定义逻辑
* 3.属性增强:动态修改Bean的属性或状态
* 4.注解处理:解析自定义注解并应用特定逻辑
* 5.实例替换:返回一个完全不同的Bean实例(慎用)
* 执行时机:
* 1.Bean声明周期顺序
* 实例化 -> 属性注入 -> postProcessBeforeInitialization -> 初始化回调 -> postProcessAfterInitialization
* 若处理器返回NULL,则Bean不会进行后续生命周期处理,直接被跳过
* 2.与其它回调的关系
* 早于@PostConstruct、InitializingBean.afterPropertiesSet()和init-method。
* 晚于@Autowired和@Resource等依赖注入注解的处理
* 典型应用场景:
* 1.配置验证:初始话前验证Bean的必要属性是否正确设置
* 2.属性预处理:转换或加密敏感配置(如数据库密码)
* 3.上下文注入:手动注入无法通过依赖注入获取的资源(如 ApplicationContext)
* 4.注解解析:处理自定义初始化注解(如 @Init)
* 5.性能监控:记录 Bean 初始化前的状态。
* 常见实现类
* AutowiredAnnotationBeanPostProcessor:处理@Autowired、@Value等依赖注入注解
* CommonAnnotationBeanPostProcessor:处理JSR-250注解,如@Resource、@PostConstruct
* AnnotationAwareAspectJAutoProxyCreator:为使用@Aspect注解的Bean创建AOP代理
* RequiredAnnotationBeanPostProcessor:检查@Required注解的属性是否已设置
*/
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
/**
* Bean初始化完成后进行自定义处理
* 核心功能
* 1.初始化后处理:在Bean完成所有初始话回调(@PostConstruct、InitializingBean.afterPropertiesSet()和init-method)后执行
* 2.包装实例:可以返回原始Bean或包装对象(如代理对象)
* 3.FactoryBean支持:同时作用于FactoryBean本身及其创建的对象
* 4.短路处理:即使Bean创建过程中被InstantiationAwareBeanPostProcessor短路,此方法扔会被调用
* 执行时机:
* 1.Bean声明周期顺序
* 实例化 -> 属性注入 -> postProcessBeforeInitialization -> 初始化回调 -> postProcessAfterInitialization
* 若处理器返回NULL,则Bean不会进行后续生命周期处理,直接被跳过
* 2.与其它回调的关系
* 晚于@PostConstruct、InitializingBean.afterPropertiesSet()和init-method。
* 早于 DisposableBean.destroy() 或 @PreDestroy 等销毁回调。
* 典型应用场景
* 1.AOP代理创建:AnnotationAwareAspectAutoProxyCreator通过此方法为Bean创建代理
* 2.Bean增强:添加额为的功能,如日志、事务、缓存
* 3.自定义注解处理:处理运行时注解,如@Cacheable、@Transactional
* 4.资源注册:将Bean注册到全局管理器或上下文
* 5.Bean验证:确保初始化后的Bean状态合法
* 常见实现类
* AnnotationAwareAspectJAutoProxyCreator:为使用@Aspect注解的Bean创建AOP代理
* ApplicationListenerDetector:检测并注册 ApplicationListener 类型的 Bean。
* MethodValidationPostProcessor:为方法参数添加 JSR-303 验证
* BeanValidationPostProcessor:对 Bean 进行 JSR-303 验证。
*/
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
InitializingBean
public interface InitializingBean {
/**
* 用于在 Bean 的属性设置完成后执行初始化逻辑。
* 实现该接口的 Bean 需要实现其唯一的方法 afterPropertiesSet(),Spring 容器会在 Bean 的所有属性都被设置后自动调用这个方法
* 使用场景:
* 1.自定义初始化逻辑:当 Bean 的属性全部设置完成后,需要执行额外的初始化操作(如资源初始化、数据加载等)。
* 2.参数校验:确保 Bean 的必要属性已被正确设置,避免运行时出现 NullPointerException。
* 注意事项:
* 1.异常处理:afterPropertiesSet() 方法声明了 throws Exception,因此可以抛出任何异常,但建议捕获并处理非预期异常,避免影响容器启动。
* 2.依赖顺序:确保 afterPropertiesSet() 中依赖的其他 Bean 已完成初始化(可通过 @DependsOn 注解控制依赖顺序)。
* 3.性能考虑:避免在 afterPropertiesSet() 中执行耗时操作,以免影响应用启动速度。
*/
void afterPropertiesSet() throws Exception;
}
DubboContextPostProcessor
public class DubboContextPostProcessor
implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware, EnvironmentAware {
/**
* The bean name of {@link DubboConfigConfigurationRegistrar}
*/
public static final String BEAN_NAME = "dubboContextPostProcessor";
private ApplicationContext applicationContext;
private ConfigurableEnvironment environment;
/**
* 主要负责初始化核心模型、环境配置和注册关键组件
*/
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// ApplicationModel:代表整个Dubbo应用实例,是全局上下文的核心容器
ApplicationModel applicationModel = DubboBeanUtils.getApplicationModel(beanFactory);
// ModuleModel:代表应用内的模块,支持多模块隔离(Dubbo3.x新增特性)
ModuleModel moduleModel = DubboBeanUtils.getModuleModel(beanFactory);
// 初始化Spring扩展注入器
// SpringExtensionInjector:负责将Spring容器中的Bean注入到Dubbo扩展点
// 支持在Dubbo SPI组件中使用Spring管理的Bean,如自定义负载均衡引用的Spring Bean
// 实现了Dubbo与Spring依赖注入体系的双向打通
SpringExtensionInjector.get(applicationModel).init(applicationContext);
SpringExtensionInjector.get(moduleModel).init(applicationContext);
DubboBeanUtils.getInitializationContext(beanFactory).setApplicationContext(applicationContext);
// 环境配置与属性提取
// 从Spring Environment中提取以`dubbo.`为前缀的属性
// 将这些属性放入Dubbo的 AppConfigMap ,作为应用级配置
// 支持配置的优先级:外部配置 > 注解 > XML > 默认值
SortedMap<String, String> dubboProperties = EnvironmentUtils.filterDubboProperties(environment);
applicationModel.getModelEnvironment().getAppConfigMap().putAll(dubboProperties);
// 注册 ConfigManager 单例
// ConfigManager:Dubbo3.x的配置管理中心,统一管理各类配置源
// 将其注册为 Spring 单例Bean,确保全局唯一性
// 负责配置的聚合、校验和动态刷新
beanFactory.registerSingleton(ConfigManager.BEAN_NAME, applicationModel.getApplicationConfigManager());
}
/**
* 在 Spring 容器加载完所有 Bean 定义但尚未实例化任何 Bean 之前被调用,主要用于动态注册或修改 Dubbo 相关的 Bean 定义
*/
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
// Dubbo 3.3.0 与 Spring 集成的核心初始化方法,负责在 Spring 应用启动时注册 Dubbo 基础设施组件
DubboSpringInitializer.initialize(beanDefinitionRegistry);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public void setEnvironment(Environment environment) {
this.environment = (ConfigurableEnvironment) environment;
}
}
DubboSpringInitializer
/**
* Dubbo spring initialization entry point
*/
public class DubboSpringInitializer {
private static final Logger logger = LoggerFactory.getLogger(DubboSpringInitializer.class);
private static final Map<BeanDefinitionRegistry, DubboSpringInitContext> REGISTRY_CONTEXT_MAP =
new ConcurrentHashMap<>();
public DubboSpringInitializer() {}
public static void initialize(BeanDefinitionRegistry registry) {
// Apache Dubbo框架与Spring整合时的核心上下文类。
// 主要用于Spring容器启动过程中初始话Dubbo服务的相关配置,实现服务的注册与发现、消费端引用等功能。
// 1.配置解析与注册
// 1.1.解析Spring配置文件中Dubbo相关标签(如"<dubbo:service>"、"<dubbo:reference>"等)的属性,并将其转换为Dubbo内部可识别的对象。
// 1.2.向注册中心(如zookeeper)注册服务提供者的接口信息,或为消费者获取服务地址
// 2.生命周期管理
// 2.1.在Spring容器启动时(ContextRefreshedEvent事件),启动Dubbo服务或建立客户端连接
// 2.2.在容器关闭时(ContextClosedEvent),优雅关闭Dubbo服务,释放资源。
// 3.整合Spring生态
// 3.1.通过实现Spring的ApplicationContextAware接口,获取Spring容器上下文,实现与SpringBean的依赖注入
DubboSpringInitContext context = new DubboSpringInitContext();
// 添加上下文到缓存中
// 如果已经存在过,直接返回,不再进行初始化。
if (REGISTRY_CONTEXT_MAP.putIfAbsent(registry, context) != null) {
return;
}
// 获取beanFactory
ConfigurableListableBeanFactory beanFactory = findBeanFactory(registry);
// 初始话化上下文
initContext(context, registry, beanFactory);
}
public static boolean remove(BeanDefinitionRegistry registry) {
return REGISTRY_CONTEXT_MAP.remove(registry) != null;
}
public static boolean remove(ApplicationContext springContext) {
AutowireCapableBeanFactory autowireCapableBeanFactory = springContext.getAutowireCapableBeanFactory();
for (Map.Entry<BeanDefinitionRegistry, DubboSpringInitContext> entry : REGISTRY_CONTEXT_MAP.entrySet()) {
DubboSpringInitContext initContext = entry.getValue();
if (initContext.getApplicationContext() == springContext
|| initContext.getBeanFactory() == autowireCapableBeanFactory
|| initContext.getRegistry() == autowireCapableBeanFactory) {
DubboSpringInitContext context = REGISTRY_CONTEXT_MAP.remove(entry.getKey());
logger.info("Unbind " + safeGetModelDesc(context.getModuleModel()) + " from spring container: "
+ ObjectUtils.identityToString(entry.getKey()));
return true;
}
}
return false;
}
static Map<BeanDefinitionRegistry, DubboSpringInitContext> getContextMap() {
return REGISTRY_CONTEXT_MAP;
}
static DubboSpringInitContext findBySpringContext(ApplicationContext applicationContext) {
for (DubboSpringInitContext initContext : REGISTRY_CONTEXT_MAP.values()) {
if (initContext.getApplicationContext() == applicationContext) {
return initContext;
}
}
return null;
}
/**
*
* @param context Apache Dubbo框架与Spring整合时的核心上下文类。
* @param registry
* 1.存储 BeanDefinition:将解析后的 Bean 定义(如 XML 配置、注解扫描结果)注册到内存中的注册表。
* 2.动态注册 Bean:允许在运行时动态添加或删除 BeanDefinition,为框架扩展提供支持。
* 3.统一接口:屏蔽不同容器实现(如 DefaultListableBeanFactory、GenericApplicationContext)的差异。
* @param beanFactory
*/
private static void initContext(
DubboSpringInitContext context,
BeanDefinitionRegistry registry,
ConfigurableListableBeanFactory beanFactory) {
context.setRegistry(registry);
context.setBeanFactory(beanFactory);
// 通过两种方式加载和执行扩展点(DubboSpringInitCustomizer、DubboSpringInitCustomizerHolder),允许用户或框架内部组件在初始化阶段介入并修改 Dubbo 的行为
customize(context);
// 初始化 ModuleModel
// Apache Dubbo 框架中的核心抽象,用于表示一个应用内的独立业务模块。在 Dubbo 的多模块架构中,它提供了对服务定义、配置和生命周期的统一管理。
ModuleModel moduleModel = context.getModuleModel();
if (moduleModel == null) {
ApplicationModel applicationModel;
if (findContextForApplication(ApplicationModel.defaultModel()) == null) {
// first spring context use default application instance
applicationModel = ApplicationModel.defaultModel();
logger.info("Use default application: " + applicationModel.getDesc());
} else {
// create a new application instance for later spring context
applicationModel = FrameworkModel.defaultModel().newApplication();
logger.info("Create new application: " + applicationModel.getDesc());
}
// init ModuleModel
moduleModel = applicationModel.getDefaultModule();
context.setModuleModel(moduleModel);
logger.info("Use default module model of target application: " + moduleModel.getDesc());
} else {
logger.info("Use module model from customizer: " + moduleModel.getDesc());
}
logger.info(
"Bind " + moduleModel.getDesc() + " to spring container: " + ObjectUtils.identityToString(registry));
// 将上下文(context)中的模块属性传递给 ModuleModel 对象
Map<String, Object> moduleAttributes = context.getModuleAttributes();
if (moduleAttributes.size() > 0) {
moduleModel.getAttributes().putAll(moduleAttributes);
}
// 将 Dubbo 的上下文对象注册为 Spring 容器中的单例 Bean
// 1.DubboSpringInitContext:Dubbo 与 Spring 集成的初始化上下文
// 2.ApplicationModel:Dubbo 应用模型,代表整个应用
// 3.ModuleModel:Dubbo 模块模型,代表应用中的一个业务模块
registerContextBeans(beanFactory, context);
// 将 DubboSpringInitContext 标记为已与当前执行环境绑定
// 通常用于防止上下文被重复绑定或确保在特定生命周期阶段后不能修改
context.markAsBound();
// 将 ModuleModel 的生命周期控制权移交给外部系统(如 Spring 容器)
// 意味着该模块的初始化、启动、销毁将由外部框架而非 Dubbo 内部机制管理
moduleModel.setLifeCycleManagedExternally(true);
// 检测当前是否处于 AOT( Ahead-of-Time 编译)模式
if (!AotWithSpringDetector.useGeneratedArtifacts()) {
// 如果不使用 AOT 生成的工件(即传统的 JIT 运行时),则执行注册逻辑
// ServicePackagesHolder
// DubboContextPostProcessor
// ReferenceBeanManager
// ReferenceAnnotationWithAotBeanPostProcessor
// DubboConfigAliasPostProcessor
// DubboDeployApplicationListener
// DubboConfigApplicationListener
// DubboConfigDefaultPropertyValueBeanPostProcessor
// DubboConfigBeanInitializer
// DubboInfraBeanRegisterPostProcessor
DubboBeanUtils.registerCommonBeans(registry);
}
}
private static String safeGetModelDesc(ScopeModel scopeModel) {
return scopeModel != null ? scopeModel.getDesc() : null;
}
private static ConfigurableListableBeanFactory findBeanFactory(BeanDefinitionRegistry registry) {
ConfigurableListableBeanFactory beanFactory;
if (registry instanceof ConfigurableListableBeanFactory) {
beanFactory = (ConfigurableListableBeanFactory) registry;
} else if (registry instanceof GenericApplicationContext) {
GenericApplicationContext genericApplicationContext = (GenericApplicationContext) registry;
beanFactory = genericApplicationContext.getBeanFactory();
} else {
throw new IllegalStateException("Can not find Spring BeanFactory from registry: "
+ registry.getClass().getName());
}
return beanFactory;
}
private static void registerContextBeans(
ConfigurableListableBeanFactory beanFactory, DubboSpringInitContext context) {
// register singleton
if (!beanFactory.containsSingleton(DubboSpringInitContext.class.getName())) {
registerSingleton(beanFactory, context);
}
if (!beanFactory.containsSingleton(
context.getApplicationModel().getClass().getName())) {
registerSingleton(beanFactory, context.getApplicationModel());
}
if (!beanFactory.containsSingleton(context.getModuleModel().getClass().getName())) {
registerSingleton(beanFactory, context.getModuleModel());
}
}
private static void registerSingleton(ConfigurableListableBeanFactory beanFactory, Object bean) {
beanFactory.registerSingleton(bean.getClass().getName(), bean);
}
private static DubboSpringInitContext findContextForApplication(ApplicationModel applicationModel) {
for (DubboSpringInitContext initializationContext : REGISTRY_CONTEXT_MAP.values()) {
if (initializationContext.getApplicationModel() == applicationModel) {
return initializationContext;
}
}
return null;
}
/**
* 通过两种方式加载和执行扩展点(DubboSpringInitCustomizer、DubboSpringInitCustomizerHolder),允许用户或框架内部组件在初始化阶段介入并修改 Dubbo 的行为 <br/>
*
* <p>DubboSpringInitCustomizer</p>
* Dubbo 3.3.0 版本引入的扩展点接口,用于在 Dubbo 与 Spring 集成的初始化阶段,
* 允许开发者或框架内部组件动态修改配置、注册 Bean 或执行自定义逻辑。
* <p>该接口类似于 Spring 的 BeanFactoryPostProcessor,在 BeanDefinition 加载完成后、
* Bean 实例化前执行,可用于实现以下功能:</p>
* <ul>
* <li>动态配置:在 Dubbo 服务导出和引用前,修改其配置参数</li>
* <li>组件注册:向 Spring 容器动态注册自定义 Bean 或修改现有 Bean</li>
* <li>条件初始化:根据环境变量或运行时条件,决定是否启用某些功能</li>
* <li>集成第三方框架:无缝对接其他框架(如 Spring Cloud、Kubernetes)</li>
* </ul>
* <p>执行时机:</p>
* <ol>
* <li>在 Spring 容器加载 BeanDefinition 后,实例化 Bean 前执行</li>
* <li>早于 @Service、@Reference 注解的处理</li>
* <li>按 SPI 优先级顺序执行多个自定义器</li>
* </ol>
*
* <p>DubboSpringInitCustomizerHolder</p>
* Dubbo 3.3.0 提供的线程本地工具类,用于在运行时动态注册 DubboSpringInitCustomizer。
* 解决了 SPI 扩展机制的局限性,允许开发者在不修改配置文件的情况下,临时注入自定义初始化逻辑。
* <p>核心作用:</p>
* <ul>
* <li>动态注册自定义器:在程序运行时添加 DubboSpringInitCustomizer 实现</li>
* <li>线程隔离:确保自定义器仅在当前线程的 Dubbo 初始化过程中生效</li>
* <li>临时扩展:避免修改全局 SPI 配置,适用于测试或条件性扩展</li>
* </ul>
* <p>使用场景:</p>
* <ul>
* <li>测试环境:在单元测试或集成测试中临时修改 Dubbo 配置</li>
* <li>条件性扩展:根据运行时条件决定是否启用某些功能</li>
* <li>动态修改配置:在不重启应用的情况下调整 Dubbo 参数</li>
* </ul>
*/
private static void customize(DubboSpringInitContext context) {
// find initialization customizers
Set<DubboSpringInitCustomizer> customizers = FrameworkModel.defaultModel()
.getExtensionLoader(DubboSpringInitCustomizer.class)
.getSupportedExtensionInstances();
for (DubboSpringInitCustomizer customizer : customizers) {
customizer.customize(context);
}
// load customizers in thread local holder
DubboSpringInitCustomizerHolder customizerHolder = DubboSpringInitCustomizerHolder.get();
customizers = customizerHolder.getCustomizers();
for (DubboSpringInitCustomizer customizer : customizers) {
customizer.customize(context);
}
customizerHolder.clearCustomizers();
}
}
DubboConfigAliasPostProcessor
/**
* Dubbo框架中用于处理配置别名的后置处理器
* 通过实现BeanPostProcessor接口,在Bean初始化完成后对特定配置Bean进行处理,建立不同配置Bean之间的别名机制
* 这个机制允许用户以更灵活的方式引用和复用配置
*/
public class DubboConfigAliasPostProcessor implements BeanDefinitionRegistryPostProcessor, BeanPostProcessor {
/**
* The bean name of {@link DubboConfigConfigurationRegistrar}
*/
public static final String BEAN_NAME = "dubboConfigAliasPostProcessor";
private BeanDefinitionRegistry registry;
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
this.registry = registry;
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// DO NOTHING
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// DO NOTHING
return bean;
}
/**
* Dubbo 框架中用于处理配置 Bean 别名注册的核心逻辑。
* 在 Bean 初始化完成后检查其是否为 Dubbo 配置 Bean(即 AbstractConfig 的子类),并为其注册别名。这个机制允许用户通过配置文件中的 id 属性更方便地引用这些配置。
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// 只处理类型为 AbstractConfig 的Bean(Dubbo配置Bean的基类)
if (bean instanceof AbstractConfig) {
String id = ((AbstractConfig) bean).getId();
if (hasText(id) // id必须存在
&& !nullSafeEquals(id, beanName) // id和BeanName不同
&& !BeanRegistrar.hasAlias(registry, beanName, id)) { // id不能已经是别名
// 将 id 注册为 Bean 别名
registry.registerAlias(beanName, id);
}
}
return bean;
}
}
DubboInfraBeanRegisterPostProcessor
/**
* 确保关键组件在正确的时机被注册和初始化,特别是处理Dubbo的服务引用注解(如@Reference)和属性占位符解析
*
* 核心功能与设计目的
* 1.提前注册ReferenceAnnotationBeanPostProcessor
* 1.1.确保@Reference注解能在属性占位符解析前被处理
* 1.2.支持早期初始化的Reference(例如在配置类中被依赖的引用)
* 2.确保PropertySourcesPlaceholderConfigurer存在
* 2.1.确保Dubbo中的占位符(如${dubbo.registry.address})能被正常解析
* 3.自身生命周期管理
* 3.1.处理完成后从注册表中移除自身,避免不必要的Bean实例化
*/
public class DubboInfraBeanRegisterPostProcessor implements BeanDefinitionRegistryPostProcessor {
/**
* The bean name of {@link ReferenceAnnotationBeanPostProcessor}
*/
public static final String BEAN_NAME = "dubboInfraBeanRegisterPostProcessor";
private BeanDefinitionRegistry registry;
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
// 保存BeanDefinitionRegistry引用,用于后续的Bean定义注册操作
this.registry = registry;
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 处理 Spring 3.2.x 兼容性问题
if (registry != null) {
// 提前注册 ReferenceAnnotationBeanPostProcessor
ReferenceAnnotationBeanPostProcessor referenceAnnotationBeanPostProcessor = beanFactory.getBean(
ReferenceAnnotationBeanPostProcessor.BEAN_NAME, ReferenceAnnotationBeanPostProcessor.class);
beanFactory.addBeanPostProcessor(referenceAnnotationBeanPostProcessor);
// PropertySourcesPlaceholderConfigurer 未注册的情况下,注册到 BeanFactory 中
DubboBeanUtils.registerPlaceholderConfigurerBeanIfNotExists(beanFactory, registry);
}
// 移除自定 Bean 定义,避免实例化
if (registry != null) {
registry.removeBeanDefinition(BEAN_NAME);
}
}
}
ServiceAnnotationPostProcessor
/**
* Dubbo框架中处理服务注解的核心组件,实现了多个Spring接口,能在Bean定义注册阶段扫描并处理带有Dubbo服务注解(如@Service、@DubboService)的类,将其转换为Dubbo的ServiceBean,并注册到Springring器中。
*
* 核心功能
* 1.注册多种服务注解:同时支持@Service、@DubboService等多种注解
* 2.包扫描与类检测:扫描指定包下带有服务注解的类
* 3.服务定义生成:将注解类转换为ServiceBean定义
* 4.注解服务Bean:将生成的ServiceBean注册到Spring容器
* 5.注解属性处理:解析注解属性并映射到ServiceBean的配置
*/
public class ServiceAnnotationPostProcessor
implements BeanDefinitionRegistryPostProcessor,
EnvironmentAware,
ResourceLoaderAware,
BeanClassLoaderAware,
ApplicationContextAware,
InitializingBean {
public static final String BEAN_NAME = "dubboServiceAnnotationPostProcessor";
/**
* 要扫描的Dubbo服务注解
*/
private static final List<Class<? extends Annotation>> serviceAnnotationTypes = loadServiceAnnotationTypes();
/**
* 获取要处理的Dubbo服务类注解标识
* @return
*/
private static List<Class<? extends Annotation>> loadServiceAnnotationTypes() {
// 是否启用Dubbo2的兼容模式 是否已经加载了服务类(存在注解com.alibaba.dubbo.config.annotation.Service)
if (Dubbo2CompactUtils.isEnabled() && Dubbo2CompactUtils.isServiceClassLoaded()) {
// 扫描org.apache.dubbo.config.annotation.DubboService、org.apache.dubbo.config.annotation.Service、com.alibaba.dubbo.config.annotation.Service三个注解标识的类
return asList(
// @since 2.7.7 Add the @DubboService , the issue : https://github.com/apache/dubbo/issues/6007
DubboService.class,
// @since 2.7.0 the substitute @com.alibaba.dubbo.config.annotation.Service
Service.class,
// @since 2.7.3 Add the compatibility for legacy Dubbo's @Service , the issue :
// https://github.com/apache/dubbo/issues/4330
Dubbo2CompactUtils.getServiceClass());
} else {
// 扫描org.apache.dubbo.config.annotation.DubboService、org.apache.dubbo.config.annotation.Service注解标识的类
return asList(
// @since 2.7.7 Add the @DubboService , the issue : https://github.com/apache/dubbo/issues/6007
DubboService.class,
// @since 2.7.0 the substitute @com.alibaba.dubbo.config.annotation.Service
Service.class);
}
}
private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());
/**
* 要扫描的包
*/
protected final Set<String> packagesToScan;
/**
* 存储已解析的需要扫描的包路径集合
*/
private Set<String> resolvedPackagesToScan;
/**
* 用于获取应用程序的配置属性和运行环境信息
* 1.解析占位符(如 ${dubbo.application.name})
* 2.获取环境变量和系统属性
* 3.条件判断(如判断是否为生产环境)
*/
private Environment environment;
/**
* 资源加载器接口,用于定位和加载应用程序中的资源(如类路径下的文件、URL 资源等)。
* 在 Dubbo 服务扫描过程中,它主要用于查找和加载指定包路径下的类文件,以便识别带有 @DubboService 或 @Service 注解的服务类
*/
private ResourceLoader resourceLoader;
/**
* classLoader 是 Dubbo 实现动态类加载和服务发现的基础组件,通过与 Spring 框架的集成,Dubbo 能够:
* 1.扫描并加载指定包路径下的服务类
* 2.解析注解中的类引用
* 3.支持复杂类加载环境(如微服务、容器化部署)
*/
private ClassLoader classLoader;
/**
* 在 Dubbo 服务扫描和注册过程中,registry是核心组件,负责将扫描到的服务类转换为 Bean 定义并注册到 Spring 容器中。
* 1.注册 Bean 定义(registerBeanDefinition(String beanName, BeanDefinition beanDefinition))
* 2.获取 Bean 定义(getBeanDefinition(String beanName))
* 3.检查 Bean 是否存在(containsBeanDefinition(String beanName))
*/
private BeanDefinitionRegistry registry;
/**
* 用于跟踪和管理已扫描包及服务类的辅助组件。它确保 Dubbo 服务扫描过程中不会重复处理相同的包或类,并提供服务类的元数据缓存,提升性能
* 1.记录已扫描的包路径,避免重复扫描
* 2.记录已注册的服务类,确保服务唯一性
* 3.提供包路径和类名的缓存机制
*/
protected ServicePackagesHolder servicePackagesHolder;
/**
* 标识服务扫描是否已完成的标志位
* 确保在 Spring 容器的生命周期中,服务扫描逻辑仅执行一次,避免重复扫描和注册服务 Bean。
*/
private volatile boolean scanned = false;
public ServiceAnnotationPostProcessor(String... packagesToScan) {
this(asList(packagesToScan));
}
public ServiceAnnotationPostProcessor(Collection<?> packagesToScan) {
this.packagesToScan = (Set<String>) packagesToScan.stream().collect(Collectors.toSet());
}
@Override
public void afterPropertiesSet() throws Exception {
// 处理用户配置的包路径,解析其中的占位符(如${dubbo.scan.base-packages}),并返回标准化的包路径集合
this.resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
// 保存BeanDefinitionRegistry引用,用于后续的Bean定义注册操作
this.registry = registry;
// 扫描dubbo组件
scanServiceBeans(resolvedPackagesToScan, registry);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
if (this.registry == null) {
// 兼容Spring3.x的处理
this.registry = (BeanDefinitionRegistry) beanFactory;
}
// 获取所有Spring中配置的BeanDefinition名称
String[] beanNames = beanFactory.getBeanDefinitionNames();
for (String beanName : beanNames) {
// 获取已经加载的BeanDefinition
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
// 获取BeanDefinition中dubbo服务类注解的配置
Map<String, Object> annotationAttributes = getServiceAnnotationAttributes(beanDefinition);
// 如果存在dubbo服务类注解,
if (annotationAttributes != null) {
// process @DubboService at java-config @bean method
processAnnotatedBeanDefinition(
beanName, (AnnotatedBeanDefinition) beanDefinition, annotationAttributes);
}
}
if (!scanned) {
//兼容Spring 3.0未调用postProcessBeanDefinitionRegistry方法进行服务扫描的情况
scanServiceBeans(resolvedPackagesToScan, registry);
}
}
/**
* Dubbo用于扫描和注册服务Bean的核心逻辑。它通过指定包路径扫描带有Dubbo服务注解的类,并将这些类注册为SpringBean
*/
private void scanServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
// 标识为已扫描
scanned = true;
// 检查扫描包是否为空
if (CollectionUtils.isEmpty(packagesToScan)) {
if (logger.isWarnEnabled()) {
logger.warn(
CONFIG_NO_BEANS_SCANNED,
"",
"",
"packagesToScan is empty , ServiceBean registry will be ignored!");
}
return;
}
// 创建自定义 BeanDefinitionScanner ,用于扫描 Dubbo 服务注解
DubboClassPathBeanDefinitionScanner scanner =
new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);
// 设置 Bean 名称生成器
BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry);
scanner.setBeanNameGenerator(beanNameGenerator);
// 添加包含过滤器,只扫描带有 Dubbo 服务注解的类
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;
}
// AOT 模式下的特殊处理
if (AotWithSpringDetector.useGeneratedArtifacts()) {
scanner.setIncludeAnnotationConfig(false);
}
// 执行包扫描
scanner.scan(packageToScan);
// 查找扫描到的 Bean 定义
Set<BeanDefinitionHolder> beanDefinitionHolders =
findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator);
// 处理扫描到的 Bean 定义
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);
}
// 处理每个服务 Bean 定义
for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
processScannedBeanDefinition(beanDefinitionHolder);
servicePackagesHolder.addScannedClass(
beanDefinitionHolder.getBeanDefinition().getBeanClassName());
}
} else {
// 未找到服务注解类是的警告
if (logger.isWarnEnabled()) {
logger.warn(
CONFIG_NO_ANNOTATIONS_FOUND,
"No annotations were found on the class",
"",
"No class annotated by Dubbo @DubboService or @Service was found under package ["
+ packageToScan + "], ignore re-scanned classes: "
+ scanExcludeFilter.getExcludedCount());
}
}
servicePackagesHolder.addScannedPackage(packageToScan);
}
}
/**
* 用于解析和获取 Spring Bean 名称生成器的逻辑。
* 它的主要功能是从 Spring 容器中查找已注册的BeanNameGenerator,如果找不到则创建一个默认实例
*
*/
private BeanNameGenerator resolveBeanNameGenerator(BeanDefinitionRegistry registry) {
BeanNameGenerator beanNameGenerator = null;
// 尝试从容器中获取已注册的BeanNameGenerator
if (registry instanceof SingletonBeanRegistry) {
SingletonBeanRegistry singletonBeanRegistry = SingletonBeanRegistry.class.cast(registry);
beanNameGenerator =
(BeanNameGenerator) singletonBeanRegistry.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
}
// 如果未找到自定义生成器,则创建默认实例
if (beanNameGenerator == null) {
if (logger.isInfoEnabled()) {
logger.info("BeanNameGenerator bean can't be found in BeanFactory with name ["
+ CONFIGURATION_BEAN_NAME_GENERATOR + "]");
logger.info("BeanNameGenerator will be a instance of " + AnnotationBeanNameGenerator.class.getName()
+ " , it maybe a potential problem on bean name generation.");
}
beanNameGenerator = new AnnotationBeanNameGenerator();
}
return beanNameGenerator;
}
/**
* 用于查找和收集指定包路径下服务 Bean 定义的核心逻辑。
* 它的主要功能是扫描包路径,识别带有服务注解的类,并将其转换为BeanDefinitionHolder对象集合
*
*/
private Set<BeanDefinitionHolder> findServiceBeanDefinitionHolders(
ClassPathBeanDefinitionScanner scanner,
String packageToScan,
BeanDefinitionRegistry registry,
BeanNameGenerator beanNameGenerator) {
// 1. 使用扫描器查找候选组件(带有服务注解的类)
Set<BeanDefinition> beanDefinitions = scanner.findCandidateComponents(packageToScan);
// 2. 创建有序集合,用于存储Bean定义持有者
Set<BeanDefinitionHolder> beanDefinitionHolders = new LinkedHashSet<>(beanDefinitions.size());
// 3. 遍历所有候选组件,生成Bean名称并封装为持有者
for (BeanDefinition beanDefinition : beanDefinitions) {
// 生成唯一的Bean名称
String beanName = beanNameGenerator.generateBeanName(beanDefinition, registry);
// 创建Bean定义持有者(包含Bean定义和名称)
BeanDefinitionHolder beanDefinitionHolder = new BeanDefinitionHolder(beanDefinition, beanName);
// 添加到结果集合
beanDefinitionHolders.add(beanDefinitionHolder);
}
return beanDefinitionHolders;
}
/**
* 这个方法处理通过包扫描发现的服务类(带有@DubboService或@Service注解的类),将其转换为 Dubbo 服务 Bean 并注册到 Spring 容器中
*
* 1.解析服务类:
* 从BeanDefinitionHolder中获取并解析服务类的Class对象。
* 2.查找服务注解:
* 通过findServiceAnnotation方法查找类上的服务注解(如@DubboService或@Service)。
* 3.提取注解属性:
* 使用 Spring 的AnnotationUtils提取注解中的配置属性(如group、version、timeout等)。
* 4.确定服务接口:
* 通过resolveInterfaceName方法确定服务实现的接口名称。优先使用注解中显式指定的interfaceClass或interfaceName,否则使用服务类实现的第一个接口。
* 5.生成服务 Bean 名称:
* 生成格式为ServiceBean:接口名:版本号的唯一名称,确保同一接口的不同版本可以共存。
* 6.构建服务 Bean 定义:
* 创建ServiceBean的 Bean 定义,设置其属性值为注解中的配置,并关联到实际的服务实现类。
* 7.注册服务 Bean:
* 将构建好的ServiceBean注册到 Spring 容器中,使其成为一个可被管理的 Bean。
*/
private void processScannedBeanDefinition(BeanDefinitionHolder beanDefinitionHolder) {
// 解析服务类
Class<?> beanClass = resolveClass(beanDefinitionHolder);
// 查找服务注解(@DubboService或@Service)
Annotation service = findServiceAnnotation(beanClass);
// 获取服务注解的属性(如group、version等)
Map<String, Object> serviceAnnotationAttributes = AnnotationUtils.getAttributes(service, true);
// 解析服务接口名称
String serviceInterface = resolveInterfaceName(serviceAnnotationAttributes, beanClass);
// 获取Spring扫描生成的Bean名称
String annotatedServiceBeanName = beanDefinitionHolder.getBeanName();
// 生成Dubbo服务Bean的名称
String beanName = generateServiceBeanName(serviceAnnotationAttributes, serviceInterface);
// 构建服务Bean定义
AbstractBeanDefinition serviceBeanDefinition =
buildServiceBeanDefinition(serviceAnnotationAttributes, serviceInterface, annotatedServiceBeanName);
// 注册服务Bean到Spring容器
registerServiceBeanDefinition(beanName, serviceBeanDefinition, serviceInterface);
}
/**
* 在给定的类上查找特定类型的注解,并支持 Spring 的合并注解机制。
*/
private Annotation findServiceAnnotation(Class<?> beanClass) {
return serviceAnnotationTypes.stream()
.map(annotationType ->
// 检查Spring的AnnotatedElementUtils类是否存在且包含findMergedAnnotation方法
ClassUtils.isPresent("org.springframework.core.annotation.AnnotatedElementUtils", Thread.currentThread()
.getContextClassLoader())
&& ReflectUtils.hasMethod(org.springframework.core.annotation.AnnotatedElementUtils.class, "findMergedAnnotation")
// 如果Spring工具类可用,则使用Spring的合并注解查找
? org.springframework.core.annotation.AnnotatedElementUtils.findMergedAnnotation(beanClass, annotationType)
// 否则使用Dubbo自定义的注解查找工具
: org.apache.dubbo.common.utils.AnnotationUtils.findAnnotation(beanClass, annotationType))
.filter(Objects::nonNull)
.findFirst()
.orElse(null);
}
/**
* 用于为 Dubbo 服务生成唯一的 Bean 名称
*/
private String generateServiceBeanName(Map<String, Object> serviceAnnotationAttributes, String serviceInterface) {
ServiceBeanNameBuilder builder = create(serviceInterface, environment)
.group((String) serviceAnnotationAttributes.get("group"))
.version((String) serviceAnnotationAttributes.get("version"));
return builder.build();
}
private Class<?> resolveClass(BeanDefinitionHolder beanDefinitionHolder) {
BeanDefinition beanDefinition = beanDefinitionHolder.getBeanDefinition();
return resolveClass(beanDefinition);
}
private Class<?> resolveClass(BeanDefinition beanDefinition) {
String beanClassName = beanDefinition.getBeanClassName();
return resolveClassName(beanClassName, classLoader);
}
/**
* 处理用户配置的包路径,解析其中的占位符(如${dubbo.scan.base-packages}),并返回标准化的包路径集合
*/
private Set<String> resolvePackagesToScan(Set<String> packagesToScan) {
// 创建有序集合,保持包路径的顺序并去重
Set<String> resolvedPackagesToScan = new LinkedHashSet<>(packagesToScan.size());
// 遍历每个待扫描的包路径
for (String packageToScan : packagesToScan) {
// 检查路径是否有内容(非空且非空白字符)
if (StringUtils.hasText(packageToScan)) {
// 去除首尾空格并解析占位符(如 ${dubbo.scan.base-packages})
String resolvedPackageToScan = environment.resolvePlaceholders(packageToScan.trim());
// 将解析后的路径添加到结果集合
resolvedPackagesToScan.add(resolvedPackageToScan);
}
}
return resolvedPackagesToScan;
}
/**
* 创建一个ServiceBean的定义,将其属性值设置为注解中的配置(如group、version),并关联到实际的服务实现类(通过refServiceBeanName引用)。
*/
private AbstractBeanDefinition buildServiceBeanDefinition(
Map<String, Object> serviceAnnotationAttributes, String serviceInterface, String refServiceBeanName) {
BeanDefinitionBuilder builder = rootBeanDefinition(ServiceBean.class);
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
String[] ignoreAttributeNames = ObjectUtils.of(
"provider",
"monitor",
"application",
"module",
"registry",
"protocol",
"methods",
"interfaceName",
"parameters",
"executor");
propertyValues.addPropertyValues(
new AnnotationPropertyValuesAdapter(serviceAnnotationAttributes, environment, ignoreAttributeNames));
// set config id, for ConfigManager cache key
// builder.addPropertyValue("id", beanName);
// References "ref" property to annotated-@Service Bean
addPropertyReference(builder, "ref", refServiceBeanName);
// Set interface
builder.addPropertyValue("interface", serviceInterface);
// Convert parameters into map
builder.addPropertyValue("parameters", DubboAnnotationUtils.convertParameters((String[])
serviceAnnotationAttributes.get("parameters")));
// Add methods parameters
List<MethodConfig> methodConfigs = convertMethodConfigs(serviceAnnotationAttributes.get("methods"));
if (!methodConfigs.isEmpty()) {
if (AotWithSpringDetector.isAotProcessing()) {
List<String> methodsJson = new ArrayList<>();
methodConfigs.forEach(methodConfig -> methodsJson.add(JsonUtils.toJson(methodConfig)));
builder.addPropertyValue("methodsJson", methodsJson);
} else {
builder.addPropertyValue("methods", methodConfigs);
}
}
// convert provider to providerIds
String providerConfigId = (String) serviceAnnotationAttributes.get("provider");
if (StringUtils.hasText(providerConfigId)) {
addPropertyValue(builder, "providerIds", providerConfigId);
}
// Convert registry[] to registryIds
String[] registryConfigIds = (String[]) serviceAnnotationAttributes.get("registry");
if (registryConfigIds != null && registryConfigIds.length > 0) {
resolveStringArray(registryConfigIds);
builder.addPropertyValue("registryIds", StringUtils.join(registryConfigIds, ','));
}
// Convert protocol[] to protocolIds
String[] protocolConfigIds = (String[]) serviceAnnotationAttributes.get("protocol");
if (protocolConfigIds != null && protocolConfigIds.length > 0) {
resolveStringArray(protocolConfigIds);
builder.addPropertyValue("protocolIds", StringUtils.join(protocolConfigIds, ','));
}
// TODO Could we ignore these attributes: applicatin/monitor/module ? Use global config
// monitor reference
String monitorConfigId = (String) serviceAnnotationAttributes.get("monitor");
if (StringUtils.hasText(monitorConfigId)) {
addPropertyReference(builder, "monitor", monitorConfigId);
}
// module reference
String moduleConfigId = (String) serviceAnnotationAttributes.get("module");
if (StringUtils.hasText(moduleConfigId)) {
addPropertyReference(builder, "module", moduleConfigId);
}
String executorBeanName = (String) serviceAnnotationAttributes.get("executor");
if (StringUtils.hasText(executorBeanName)) {
addPropertyReference(builder, "executor", executorBeanName);
}
// service bean definition should not be lazy
builder.setLazyInit(false);
return builder.getBeanDefinition();
}
private String[] resolveStringArray(String[] strs) {
if (strs == null) {
return null;
}
for (int i = 0; i < strs.length; i++) {
strs[i] = environment.resolvePlaceholders(strs[i]);
}
return strs;
}
private List convertMethodConfigs(Object methodsAnnotation) {
if (methodsAnnotation == null) {
return Collections.EMPTY_LIST;
}
return MethodConfig.constructMethodConfig((Method[]) methodsAnnotation);
}
private void addPropertyReference(BeanDefinitionBuilder builder, String propertyName, String beanName) {
String resolvedBeanName = environment.resolvePlaceholders(beanName);
builder.addPropertyReference(propertyName, resolvedBeanName);
}
private void addPropertyValue(BeanDefinitionBuilder builder, String propertyName, String value) {
String resolvedBeanName = environment.resolvePlaceholders(value);
builder.addPropertyValue(propertyName, resolvedBeanName);
}
/**
* 处理通过工厂方法创建的服务 Bean,从中提取如@DubboService或@Service等注解的属性值
*/
private Map<String, Object> getServiceAnnotationAttributes(BeanDefinition beanDefinition) {
// 检查是否为注解类型的Bean定义
if (beanDefinition instanceof AnnotatedBeanDefinition) {
AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) beanDefinition;
// 获取工厂方法元数据(如果是通过@Bean方法创建的Bean)
MethodMetadata factoryMethodMetadata = SpringCompatUtils.getFactoryMethodMetadata(annotatedBeanDefinition);
if (factoryMethodMetadata != null) {
// 尝试所有支持的服务注解类型
for (Class<? extends Annotation> annotationType : serviceAnnotationTypes) {
// 检查工厂方法是否带有该类型的注解
if (factoryMethodMetadata.isAnnotated(annotationType.getName())) {
// 获取注解属性
Map<String, Object> annotationAttributes =
factoryMethodMetadata.getAnnotationAttributes(annotationType.getName());
// 过滤掉默认值,只保留显式设置的属性
return filterDefaultValues(annotationType, annotationAttributes);
}
}
}
}
return null;
}
/**
* 处理 Java 配置中带有@DubboService注解的方法的过程。它从带注解的方法中提取服务元数据,构建服务 Bean 定义,并将其注册到 Spring 容器中。
* 1.提取注解属性
* 从@DubboService注解中获取配置属性(如group、version等),存储在serviceAnnotationAttributes
* 2.解析服务接口类型
* 2.1 通过SpringCompatUtils.getFactoryMethodReturnType获取@Bean方法的返回类型名称(即服务接口类型)。
* 2.2 使用类加载器解析该类型名称为Class对象。
* 3.确定服务接口名称
* 调用resolveInterfaceName方法,优先从注解属性中获取接口名,若未指定则使用方法返回类型
* 4.生成服务 Bean 名称
* 根据注解属性和接口名生成唯一的ServiceBean名称(例如ServiceBean:demoService:1.2.3)
* 5.构建服务 Bean 定义
* 调用buildServiceBeanDefinition创建一个ServiceBean的定义,将其属性值设置为注解中的配置(如group、version),并关联到实际的服务实现类(通过refServiceBeanName引用)。
* 6.注册服务 Bean
*/
private void processAnnotatedBeanDefinition(
String refServiceBeanName,
AnnotatedBeanDefinition refServiceBeanDefinition,
Map<String, Object> attributes) {
Map<String, Object> serviceAnnotationAttributes = new LinkedHashMap<>(attributes);
// 通过 Spring 的反射工具获取方法返回类型,确保正确识别服务接口。
String returnTypeName = SpringCompatUtils.getFactoryMethodReturnType(refServiceBeanDefinition);
Class<?> beanClass = resolveClassName(returnTypeName, classLoader);
// 解析接口名
String serviceInterface = resolveInterfaceName(serviceAnnotationAttributes, beanClass);
// 获取 Bean 名称
// 生成的名称格式通常为 ServiceBean:接口名:版本号,确保唯一性
String serviceBeanName = generateServiceBeanName(serviceAnnotationAttributes, serviceInterface);
// 创建一个ServiceBean的定义,将其属性值设置为注解中的配置(如group、version),并关联到实际的服务实现类(通过refServiceBeanName引用)。
AbstractBeanDefinition serviceBeanDefinition =
buildServiceBeanDefinition(serviceAnnotationAttributes, serviceInterface, refServiceBeanName);
// 设置ServiceBean的ID属性
serviceBeanDefinition.getPropertyValues().add(Constants.ID, serviceBeanName);
// 将其注册到Spring容器中,完成服务暴露
registerServiceBeanDefinition(serviceBeanName, serviceBeanDefinition, serviceInterface);
}
/**
* 将服务接口对应的 Bean 定义注册到 Spring 容器中,同时处理可能出现的重复注册问题。
*/
private void registerServiceBeanDefinition(
String serviceBeanName, AbstractBeanDefinition serviceBeanDefinition, String serviceInterface) {
// 检查容器中是否已存在同名的Bean定义
if (registry.containsBeanDefinition(serviceBeanName)) {
BeanDefinition existingDefinition = registry.getBeanDefinition(serviceBeanName);
// 如果已存在的Bean定义与当前定义完全相同,则跳过注册
if (existingDefinition.equals(serviceBeanDefinition)) {
// exist equipment bean definition
return;
}
// 否则记录错误并抛出异常,避免冲突
String msg = "Found duplicated BeanDefinition of service interface [" + serviceInterface
+ "] with bean name [" + serviceBeanName + "], existing definition [ " + existingDefinition
+ "], new definition [" + serviceBeanDefinition + "]";
logger.error(CONFIG_DUPLICATED_BEAN_DEFINITION, "", "", msg);
throw new BeanDefinitionStoreException(
serviceBeanDefinition.getResourceDescription(), serviceBeanName, msg);
}
// 将服务Bean定义注册到Spring容器
registry.registerBeanDefinition(serviceBeanName, serviceBeanDefinition);
if (logger.isInfoEnabled()) {
logger.info("Register ServiceBean[" + serviceBeanName + "]: " + serviceBeanDefinition);
}
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.servicePackagesHolder =
applicationContext.getBean(ServicePackagesHolder.BEAN_NAME, ServicePackagesHolder.class);
}
private class ScanExcludeFilter implements TypeFilter {
private int excludedCount;
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
String className = metadataReader.getClassMetadata().getClassName();
boolean excluded = servicePackagesHolder.isClassScanned(className);
if (excluded) {
excludedCount++;
}
return excluded;
}
public int getExcludedCount() {
return excludedCount;
}
}
}
org.springframework.context.annotation.ClassPathBeanDefinitionScanner#scan
org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan
org.apache.dubbo.config.spring.context.annotation.DubboClassPathBeanDefinitionScanner#findCandidateComponents
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
