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
繁體地址,請注明出處:http://hk.pswp.cn/diannao/87130.shtml
英文地址,請注明出處:http://en.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…