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注解的属性是否已设置*/@Nullabledefault 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 验证。*/@Nullabledefault 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 DubboContextPostProcessorimplements BeanDefinitionRegistryPostProcessor, ApplicationContextAware, EnvironmentAware {/*** The bean name of {@link DubboConfigConfigurationRegistrar}*/public static final String BEAN_NAME = "dubboContextPostProcessor";private ApplicationContext applicationContext;private ConfigurableEnvironment environment;/*** 主要负责初始化核心模型、环境配置和注册关键组件*/@Overridepublic 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 定义*/@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {// Dubbo 3.3.0 与 Spring 集成的核心初始化方法,负责在 Spring 应用启动时注册 Dubbo 基础设施组件DubboSpringInitializer.initialize(beanDefinitionRegistry);}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}@Overridepublic 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;}// 获取beanFactoryConfigurableListableBeanFactory 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 instanceapplicationModel = ApplicationModel.defaultModel();logger.info("Use default application: " + applicationModel.getDesc());} else {// create a new application instance for later spring contextapplicationModel = FrameworkModel.defaultModel().newApplication();logger.info("Create new application: " + applicationModel.getDesc());}// init ModuleModelmoduleModel = 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// DubboInfraBeanRegisterPostProcessorDubboBeanUtils.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 singletonif (!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 customizersSet<DubboSpringInitCustomizer> customizers = FrameworkModel.defaultModel().getExtensionLoader(DubboSpringInitCustomizer.class).getSupportedExtensionInstances();for (DubboSpringInitCustomizer customizer : customizers) {customizer.customize(context);}// load customizers in thread local holderDubboSpringInitCustomizerHolder 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;@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {this.registry = registry;}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {// DO NOTHING}@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {// DO NOTHINGreturn bean;}/*** Dubbo 框架中用于处理配置 Bean 别名注册的核心逻辑。* 在 Bean 初始化完成后检查其是否为 Dubbo 配置 Bean(即 AbstractConfig 的子类),并为其注册别名。这个机制允许用户通过配置文件中的 id 属性更方便地引用这些配置。*/@Overridepublic 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;@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {// 保存BeanDefinitionRegistry引用,用于后续的Bean定义注册操作this.registry = registry;}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {// 处理 Spring 3.2.x 兼容性问题if (registry != null) {// 提前注册 ReferenceAnnotationBeanPostProcessorReferenceAnnotationBeanPostProcessor 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 ServiceAnnotationPostProcessorimplements 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/6007DubboService.class,// @since 2.7.0 the substitute @com.alibaba.dubbo.config.annotation.ServiceService.class,// @since 2.7.3 Add the compatibility for legacy Dubbo's @Service , the issue :// https://github.com/apache/dubbo/issues/4330Dubbo2CompactUtils.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/6007DubboService.class,// @since 2.7.0 the substitute @com.alibaba.dubbo.config.annotation.ServiceService.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());}@Overridepublic void afterPropertiesSet() throws Exception {// 处理用户配置的包路径,解析其中的占位符(如${dubbo.scan.base-packages}),并返回标准化的包路径集合this.resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);}@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {// 保存BeanDefinitionRegistry引用,用于后续的Bean定义注册操作this.registry = registry;// 扫描dubbo组件scanServiceBeans(resolvedPackagesToScan, registry);}@Overridepublic 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) {// 获取已经加载的BeanDefinitionBeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);// 获取BeanDefinition中dubbo服务类注解的配置Map<String, Object> annotationAttributes = getServiceAnnotationAttributes(beanDefinition);// 如果存在dubbo服务类注解,if (annotationAttributes != null) {// process @DubboService at java-config @bean methodprocessAnnotatedBeanDefinition(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;// 尝试从容器中获取已注册的BeanNameGeneratorif (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 BeanaddPropertyReference(builder, "ref", refServiceBeanName);// Set interfacebuilder.addPropertyValue("interface", serviceInterface);// Convert parameters into mapbuilder.addPropertyValue("parameters", DubboAnnotationUtils.convertParameters((String[])serviceAnnotationAttributes.get("parameters")));// Add methods parametersList<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 providerIdsString providerConfigId = (String) serviceAnnotationAttributes.get("provider");if (StringUtils.hasText(providerConfigId)) {addPropertyValue(builder, "providerIds", providerConfigId);}// Convert registry[] to registryIdsString[] registryConfigIds = (String[]) serviceAnnotationAttributes.get("registry");if (registryConfigIds != null && registryConfigIds.length > 0) {resolveStringArray(registryConfigIds);builder.addPropertyValue("registryIds", StringUtils.join(registryConfigIds, ','));}// Convert protocol[] to protocolIdsString[] 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 referenceString monitorConfigId = (String) serviceAnnotationAttributes.get("monitor");if (StringUtils.hasText(monitorConfigId)) {addPropertyReference(builder, "monitor", monitorConfigId);}// module referenceString 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 lazybuilder.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 definitionreturn;}// 否则记录错误并抛出异常,避免冲突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);}}@Overridepublic void setEnvironment(Environment environment) {this.environment = environment;}@Overridepublic void setResourceLoader(ResourceLoader resourceLoader) {this.resourceLoader = resourceLoader;}@Overridepublic void setBeanClassLoader(ClassLoader classLoader) {this.classLoader = classLoader;}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.servicePackagesHolder =applicationContext.getBean(ServicePackagesHolder.BEAN_NAME, ServicePackagesHolder.class);}private class ScanExcludeFilter implements TypeFilter {private int excludedCount;@Overridepublic 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/diannao/87130.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Seata 全面深入学习指南

Seata 全面深入学习指南 学习目录 第一部分:Seata 基础篇 分布式事务基础概念Seata 概述与核心架构Seata 部署与快速入门第二部分:Seata 核心机制 Seata 事务模式详解 AT 模式TCC 模式SAGA 模式XA 模式Seata 事务协调机制Seata 高可用设计第三部分:Seata 高级特性 Seata 配…

【Linux】基于策略模式的简单日志设计

&#x1f4dd;前言&#xff1a; 这篇文章我们来讲讲Linux——基于策略模式的简单日志设计 &#x1f3ac;个人简介&#xff1a;努力学习ing &#x1f4cb;个人专栏&#xff1a;Linux &#x1f380;CSDN主页 愚润求学 &#x1f304;其他专栏&#xff1a;C学习笔记&#xff0c;C语…

C#引用传递代码记录

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;namespace 值传递和引用传递 {internal class Program{static void Main(string[] args){person P1new person();P1.name "张三";person P2 …

React动态渲染:如何用map循环渲染一个列表(List)

React动态渲染&#xff1a;如何用map循环渲染一个列表(List)&#xff1f; 系列回顾&#xff1a; 在上一篇中&#xff0c;我们学习了如何通过onClick等事件处理&#xff0c;让React应用响应用户的操作。现在我们的组件已经能“听懂话”了。但是&#xff0c;目前为止我们展示的内…

React Native【实战范例】水平滚动分类 FlatList

import React from "react"; import { FlatList, SafeAreaView, StyleSheet, Text, View } from "react-native"; interface itemType {id: string;title: string;icon: string; } // 水平滚动数据 const horizontalData: itemType[] [{ id: "1"…

iOS swiftUI的实用举例

SwiftUI 是 Apple 推出的声明式 UI 框架&#xff0c;以下是一些实用技巧和最佳实践&#xff0c;可以帮助你更高效地开发 iOS/macOS/watchOS/tvOS 应用。 1. 布局技巧 灵活的空间占用 // 使用 Spacer 填充可用空间 HStack {Text("Left")Spacer() // 填充中间空间 …

SpringMVC异步处理Servlet

使用SpringMVC异步处理Servlet解决的问题 可以不阻塞有限的tomcat 线程&#xff08;默认是200~250个&#xff0c;springboot3是200个&#xff09;&#xff0c;确保网络请求可以持续响应特定业务使用自定义线程池&#xff0c;可以处理的业务量更大对上层业务完全无感知&#xf…

同步与异步编程范式全景研究——从CPU时钟周期到云原生架构的范式演进

第一章 时空观的根本分歧 1.1 物理时间的约束性 同步操作的本质是对牛顿绝对时间的服从&#xff0c;其阻塞特性源于冯诺依曼体系下指令顺序执行的基因。现代CPU的流水线技术&#xff08;如Intel Hyper-Threading&#xff09;通过指令级并行实现伪异步&#xff0c;但开发者仍需…

【零散技术】5分钟完成Odoo18 登陆页面全自定义

序言:时间是我们最宝贵的财富,珍惜手上的每个时分 从最初的tinyERP到Open ERP&#xff0c;再由OpenERP到Odoo&#xff0c;虽然UI已经过了多次大改&#xff0c;Odoo登录界面依旧丑陋&#xff0c;同时还有各种Odoo版权信息&#xff0c;对于定制项目而言是不友好的。 今天以Odoo18…

Vue3 + TypeScript + Element Plus + el-pagination 分页查询实例分享

前端技术栈&#xff1a;Vue3 TypeScript Element Plus el-pagination 后端技术栈&#xff1a;Java Spring Boot Mybatis 应用异常情况说明&#xff1a;点击页码2&#xff0c;会发送两次请求&#xff0c;并且自动跳回页码1 代码&#xff1a; Reagent.vue <script set…

LoadRunner 2023 安装部署

下载地址&#xff1a;链接: https://caiyun.139.com/w/i/2nQQRYCZ1Ssjl 提取码:3gz0 复制内容打开139-云盘 主要下载Micro_Focus_LoadRunner_2023_Community_Edition.exe来安装就可以。 如要汉化&#xff0c;则再下载安装Language_Packs.exe的安装包 说明&#xff1a;LoadR…

ABC410 : F - Balanced Rectangles

https://atcoder.jp/contests/abc410/tasks/abc410_fhttps://atcoder.jp/contests/abc410/tasks/abc410_f首先可以一眼看出暴力 &#xff1a;枚举左上角和右下角&#xff0c;用前缀和算出矩形中#的数量&#xff0c;判断即可 但这样是,爆!!! 考虑优化&#xff0c;我们可以枚举…

嵌入式学习笔记 - HAL库对外设的封装

一 外设封装结构 HAL库对外设的封装使用了xx_HandleTypeDef类型的外设句柄结构体&#xff0c;这个句柄结构体的第一个成员Instance(xx_TypeDef类型)一般为该外设的所有寄存器的起始基地址&#xff0c;第二个成员Init&#xff08;xx_InitTypeDef类型&#xff09;一般为该外设的设…

高精度模板

加法 P1601 AB Problem&#xff08;高精&#xff09; #include<iostream>using namespace std; const int N 1e6 10; int a[N],b[N],c[N]; int len1,len2,lenMax; //长度要提前定义在全局&#xff0c;在函数中要使用 void add(int c[],int a[],int b[]) {for(int i0…

monorepo使用指北

|  WARN  node_modules is present. Lockfile only installation will make it out-of-date  ERR_PNPM_FETCH_404  GET https://registry.npmjs.org/common%2Fcommon: Not Found - 404 This error happened while installing a direct dependency of G:\monorepo\vue3 comm…

Java八股文——Spring「MyBatis篇」

与传统的JDBC相比&#xff0c;MyBatis的优点&#xff1f; 面试官您好&#xff0c;MyBatis相比于传统的JDBC&#xff0c;它并不是要完全颠覆JDBC&#xff0c;而是作为JDBC的一个强大的“增强框架”。它的核心价值在于&#xff0c;在保留了SQL最大灵活性的前提下&#xff0c;极大…

JavaScript基础-常用的鼠标事件

一、前言 在前端开发中&#xff0c;鼠标事件 是实现用户交互的重要手段之一。通过监听用户的点击、移动、悬停等操作&#xff0c;我们可以构建出丰富而灵活的网页交互体验。 本文将带你深入了解&#xff1a; JavaScript 中常见的鼠标事件&#xff1b;各类鼠标事件的触发时机…

windows录频软件

一.很反感有些做软件的&#xff0c;把别人开源的改个界面收费&#xff0c;所以我找了一个开源免费的。 二.准备工具 一台电脑&#xff0c; Captura:完全开源免费的录频软件。 ffmpeg&#xff1a;音频格式转换软件&#xff0c;这可是非常大名鼎鼎的工具。 三.安装Captura 网址…

python中的模块化编程:日期模块、math算术模块、random模块

内置模块&#xff08;math、random、时间&#xff09;自定义模块&#xff08;自己写的部分代码&#xff09;第三方模块&#xff08;引入的第三方代码库的模块&#xff09; math模块 import math#圆周率 print(math.pi) #自然常数 print(math.e) #圆周率的二倍 print(math.tau…

【学习笔记】Langchain基础(二)

前文&#xff1a;【学习笔记】Langchain基础 文章目录 8 [LangGraph] 实现 Building Effective Agents&#xff0c;各种 workflows 及 AgentAugmented LLMPrompt ChainingParallelizationRoutingOrchestrator-Worker (协调器-工作器)Evaluator-optimizer (Actor-Critic)Agent 8…