# bean-override **Repository Path**: ourteam/bean-override ## Basic Information - **Project Name**: bean-override - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-08-13 - **Last Updated**: 2025-08-14 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## 背景 在中大型 Spring/Spring Boot 项目里,配置常常被拆分成多个模块(数据源、缓存、消息、业务功能包等)。我们既想**按模块组合配置**,又希望**不依赖组件扫描就能显式引入**某些配置类。 @Import 正是为这种“**把别处定义的 Bean 定义/配置引入到当前上下文**”而设计的机制,它在**配置类解析阶段**被处理,比 Bean 实例化更早,属于**注册 BeanDefinition 的元编程工具**。 然而我们可能会遇到多个jar包中定义同名的类,导致出现`BeanDefinitionOverrideException` 一般情况下我们可以通过几个方式解决 - 在项目中覆写类,然后起个别名 但classloader如果先加载到框架里的类这种方式将无效 - 动态排除Configuration类,让其不生效。 思考如何通过扩展spring的方式解决此问题? ## 解决方案 我们知道,@Import注解具有更高的优先级被spring处理。在spring中自动配置类可以使用 spring.autoconfigure.exclude 方式进行排除,但是@Import类的不能。所以我们需要有一种方式让@Import方式导入的@Configuration类也有方式被排除,回顾@Import处理的源码和时机 - org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors - 注册ConfigurationClassPostProcessor 类,进行@Configuration类的扫描处理 - org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors - PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); - getBeanFactoryPostProcessors() 获取注册到AbstractApplicationContext 的BeanDefinitionRegistryPostProcessor 调用postProcessBeanDefinitionRegistry - org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors - 方法内的逻辑 ```java for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) { if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) { BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor) postProcessor; registryProcessor.postProcessBeanDefinitionRegistry(registry); registryProcessors.add(registryProcessor); } else { regularPostProcessors.add(postProcessor); } } ``` - 这个`registryProcessor.postProcessBeanDefinitionRegistry(registry);`就是我们扩展点之一 - org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry - 后续进行Configuration的扫描 - org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions - 后续处理Configuration的类 - org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitions - 后续处理每个Configuration类的@Bean方法 - org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForBeanMethod - 后续继续处理每个方法 - org.springframework.beans.factory.support.BeanDefinitionRegistry#registerBeanDefinition - 后续然后调用注册bean的方法 以上是处理Configuration类的主要源码路径。我们发现可以`registryProcessor.postProcessBeanDefinitionRegistry(registry);` 这个地方进行扩展。 扩展方式为: ```java public static void main(String[] args) { ConfigurableApplicationContext context = new SpringApplicationBuilder(BeanOverrideApplication.class) .initializers(new ApplicationContextInitializer() { @Override public void initialize(ConfigurableApplicationContext applicationContext) { applicationContext.addBeanFactoryPostProcessor(new MyBeanFactoryPostProcessor()); } }) .run(args); } ``` - 在ApplicationContextInitializer的时候进行注册`MyBeanFactoryPostProcessor` - 当然也可用spring.factoris中设置org.springframework.context.ApplicationContextInitializer=xxxx类进行注册 - 注意ApplicationContextInitializer 方式初始化比较早,可以保证MyBeanFactoryPostProcessor生效 - 一般的使用@Component或者@Bean方式注册的 BeanFactoryPostProcessor 是不会生效的。 - MyBeanFactoryPostProcessor 进行扩展 ConfigurationClassPostProcessor 注册自定义的ConfigurationClassPostProcessor ```java public class MyBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor { private static final Logger log = LoggerFactory.getLogger(MyBeanFactoryPostProcessor.class); @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { } @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { if (registry instanceof DefaultListableBeanFactory) { DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) registry; String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames(); for (String beanDefinitionName : beanDefinitionNames) { BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanDefinitionName); if (beanDefinition instanceof RootBeanDefinition) { RootBeanDefinition rootBeanDefinition = (RootBeanDefinition) beanDefinition; String beanClassName = rootBeanDefinition.getBeanClassName(); if ("org.springframework.context.annotation.internalConfigurationAnnotationProcessor".equals(beanDefinitionName) && "org.springframework.context.annotation.ConfigurationClassPostProcessor".equals(beanClassName)) { log.info("beanDefinitionName: {} beanDefinition:{}", beanDefinitionName, beanDefinition); registry.removeBeanDefinition(beanDefinitionName); rootBeanDefinition.setBeanClass(MyConfigurationClassPostProcessor.class); registry.registerBeanDefinition(beanDefinitionName, rootBeanDefinition); } } } } } } ``` - 使用自定义的ConfigurationClassPostProcessor 处理Configuration类 ```java package org.springframework.context.annotation; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.config.SingletonBeanRegistry; import org.springframework.beans.factory.parsing.ProblemReporter; import org.springframework.beans.factory.parsing.SourceExtractor; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.core.env.Environment; import org.springframework.core.env.StandardEnvironment; import org.springframework.core.io.ResourceLoader; import org.springframework.core.metrics.ApplicationStartup; import org.springframework.core.metrics.StartupStep; import org.springframework.core.type.classreading.CachingMetadataReaderFactory; import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.lang.Nullable; import org.springframework.util.ReflectionUtils; import java.lang.reflect.Field; import java.util.*; /** * @author wxl */public class MyConfigurationClassPostProcessor extends ConfigurationClassPostProcessor { private final Log logger = LogFactory.getLog(getClass()); private static final String IMPORT_REGISTRY_BEAN_NAME = ConfigurationClassPostProcessor.class.getName() + ".importRegistry"; @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { super.postProcessBeanDefinitionRegistry(registry); } /** * Build and validate a configuration model based on the registry of * {@link Configuration} classes. */ @Override public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) { List configCandidates = new ArrayList<>(); String[] candidateNames = registry.getBeanDefinitionNames(); for (String beanName : candidateNames) { BeanDefinition beanDef = registry.getBeanDefinition(beanName); if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) { if (logger.isDebugEnabled()) { logger.debug("Bean definition has already been processed as a configuration class: " + beanDef); } } else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, getMetadataReaderFactory())) { configCandidates.add(new BeanDefinitionHolder(beanDef, beanName)); } } // Return immediately if no @Configuration classes were found if (configCandidates.isEmpty()) { return; } // Sort by previously determined @Order value, if applicable configCandidates.sort((bd1, bd2) -> { int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition()); int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition()); return Integer.compare(i1, i2); }); // Detect any custom bean name generation strategy supplied through the enclosing application context SingletonBeanRegistry sbr = null; if (registry instanceof SingletonBeanRegistry) { sbr = (SingletonBeanRegistry) registry; if (!isLocalBeanNameGeneratorSet()) { BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton( AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR); if (generator != null) { setComponentScanBeanNameGenerator(generator); setImportBeanNameGenerator(generator); } } } if (getEnvironment() == null) { setEnvironment(new StandardEnvironment()); } // Parse each @Configuration class ConfigurationClassParser parser = new ConfigurationClassParser( getMetadataReaderFactory(), getProblemReporter(), getEnvironment(), getResourceLoader(), getComponentScanBeanNameGenerator(), registry); Set candidates = new LinkedHashSet<>(configCandidates); Set alreadyParsed = new HashSet<>(configCandidates.size()); do { StartupStep processConfig = getApplicationStartup().start("spring.context.config-classes.parse"); parser.parse(candidates); parser.validate(); Set configClasses = new LinkedHashSet<>(parser.getConfigurationClasses()); configClasses.removeAll(alreadyParsed); // Read the model and create bean definitions based on its content if (getReader() == null) { ConfigurationClassBeanDefinitionReader configurationClassBeanDefinitionReader = new ConfigurationClassBeanDefinitionReader( registry, getSourceExtractor(), getResourceLoader(), getEnvironment(), getImportBeanNameGenerator(), parser.getImportRegistry()); setReader(configurationClassBeanDefinitionReader); } //【todo 进行configClass过滤,排除】 configClasses.removeIf(this::isExcludedClass); // 读取所有@Configuration类进行bean定义注册 this.getReader().loadBeanDefinitions(configClasses); alreadyParsed.addAll(configClasses); processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end(); candidates.clear(); if (registry.getBeanDefinitionCount() > candidateNames.length) { String[] newCandidateNames = registry.getBeanDefinitionNames(); Set oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames)); Set alreadyParsedClasses = new HashSet<>(); for (ConfigurationClass configurationClass : alreadyParsed) { alreadyParsedClasses.add(configurationClass.getMetadata().getClassName()); } for (String candidateName : newCandidateNames) { if (!oldCandidateNames.contains(candidateName)) { BeanDefinition bd = registry.getBeanDefinition(candidateName); if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, getMetadataReaderFactory()) && !alreadyParsedClasses.contains(bd.getBeanClassName())) { candidates.add(new BeanDefinitionHolder(bd, candidateName)); } } } candidateNames = newCandidateNames; } } while (!candidates.isEmpty()); // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) { sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry()); } if (getMetadataReaderFactory() instanceof CachingMetadataReaderFactory) { // Clear cache in externally provided MetadataReaderFactory; this is a no-op // for a shared cache since it'll be cleared by the ApplicationContext. ((CachingMetadataReaderFactory) getMetadataReaderFactory()).clearCache(); } } private boolean isExcludedClass(ConfigurationClass configurationClass) { //排除逻辑 // if ("com.ccwxl.practice.cc.TaskBeanConfiguration".equals(configurationClass.getMetadata().getClassName())) { // logger.info("exclude class:" + configurationClass.getMetadata().getClassName()); // return true; // } return false; } @Nullable private void setReader(ConfigurationClassBeanDefinitionReader configurationClassBeanDefinitionReader) { Field reader = ReflectionUtils.findField(ConfigurationClassPostProcessor.class, "reader"); if (reader != null) { reader.setAccessible(true); ReflectionUtils.setField(reader, this, configurationClassBeanDefinitionReader); } } @Nullable public MetadataReaderFactory getMetadataReaderFactory() { Field metadataReaderFactory = ReflectionUtils.findField(ConfigurationClassPostProcessor.class, "metadataReaderFactory"); if (metadataReaderFactory != null) { metadataReaderFactory.setAccessible(true); Object field = ReflectionUtils.getField(metadataReaderFactory, this); if (field instanceof MetadataReaderFactory) { return (MetadataReaderFactory) field; } } return null; } @Nullable public ConfigurationClassBeanDefinitionReader getReader() { Field reader = ReflectionUtils.findField(ConfigurationClassPostProcessor.class, "reader"); if (reader != null) { reader.setAccessible(true); Object field = ReflectionUtils.getField(reader, this); if (field instanceof ConfigurationClassBeanDefinitionReader) { return (ConfigurationClassBeanDefinitionReader) field; } } return null; } // 新增的反射方法 @Nullable private boolean isLocalBeanNameGeneratorSet() { Field localBeanNameGeneratorSet = ReflectionUtils.findField(ConfigurationClassPostProcessor.class, "localBeanNameGeneratorSet"); if (localBeanNameGeneratorSet != null) { localBeanNameGeneratorSet.setAccessible(true); Object field = ReflectionUtils.getField(localBeanNameGeneratorSet, this); if (field instanceof Boolean) { return (Boolean) field; } } return false; } @Nullable private void setComponentScanBeanNameGenerator(BeanNameGenerator generator) { Field componentScanBeanNameGenerator = ReflectionUtils.findField(ConfigurationClassPostProcessor.class, "componentScanBeanNameGenerator"); if (componentScanBeanNameGenerator != null) { componentScanBeanNameGenerator.setAccessible(true); ReflectionUtils.setField(componentScanBeanNameGenerator, this, generator); } } @Nullable private void setImportBeanNameGenerator(BeanNameGenerator generator) { Field importBeanNameGenerator = ReflectionUtils.findField(ConfigurationClassPostProcessor.class, "importBeanNameGenerator"); if (importBeanNameGenerator != null) { importBeanNameGenerator.setAccessible(true); ReflectionUtils.setField(importBeanNameGenerator, this, generator); } } @Nullable private Environment getEnvironment() { Field environment = ReflectionUtils.findField(ConfigurationClassPostProcessor.class, "environment"); if (environment != null) { environment.setAccessible(true); Object field = ReflectionUtils.getField(environment, this); if (field instanceof Environment) { return (Environment) field; } } return null; } @Override public void setEnvironment(Environment environment) { Field envField = ReflectionUtils.findField(ConfigurationClassPostProcessor.class, "environment"); if (envField != null) { envField.setAccessible(true); ReflectionUtils.setField(envField, this, environment); } } @Nullable private ProblemReporter getProblemReporter() { Field problemReporter = ReflectionUtils.findField(ConfigurationClassPostProcessor.class, "problemReporter"); if (problemReporter != null) { problemReporter.setAccessible(true); Object field = ReflectionUtils.getField(problemReporter, this); if (field instanceof ProblemReporter) { return (ProblemReporter) field; } } return null; } @Nullable private ResourceLoader getResourceLoader() { Field resourceLoader = ReflectionUtils.findField(ConfigurationClassPostProcessor.class, "resourceLoader"); if (resourceLoader != null) { resourceLoader.setAccessible(true); Object field = ReflectionUtils.getField(resourceLoader, this); if (field instanceof ResourceLoader) { return (ResourceLoader) field; } } return null; } @Nullable private BeanNameGenerator getComponentScanBeanNameGenerator() { Field componentScanBeanNameGenerator = ReflectionUtils.findField(ConfigurationClassPostProcessor.class, "componentScanBeanNameGenerator"); if (componentScanBeanNameGenerator != null) { componentScanBeanNameGenerator.setAccessible(true); Object field = ReflectionUtils.getField(componentScanBeanNameGenerator, this); if (field instanceof BeanNameGenerator) { return (BeanNameGenerator) field; } } return null; } @Nullable private SourceExtractor getSourceExtractor() { Field sourceExtractor = ReflectionUtils.findField(ConfigurationClassPostProcessor.class, "sourceExtractor"); if (sourceExtractor != null) { sourceExtractor.setAccessible(true); Object field = ReflectionUtils.getField(sourceExtractor, this); if (field instanceof SourceExtractor) { return (SourceExtractor) field; } } return null; } @Nullable private BeanNameGenerator getImportBeanNameGenerator() { Field importBeanNameGenerator = ReflectionUtils.findField(ConfigurationClassPostProcessor.class, "importBeanNameGenerator"); if (importBeanNameGenerator != null) { importBeanNameGenerator.setAccessible(true); Object field = ReflectionUtils.getField(importBeanNameGenerator, this); if (field instanceof BeanNameGenerator) { return (BeanNameGenerator) field; } } return null; } @Nullable private ApplicationStartup getApplicationStartup() { Field applicationStartup = ReflectionUtils.findField(ConfigurationClassPostProcessor.class, "applicationStartup"); if (applicationStartup != null) { applicationStartup.setAccessible(true); Object field = ReflectionUtils.getField(applicationStartup, this); if (field instanceof ApplicationStartup) { return (ApplicationStartup) field; } } return null; } } ``` - 注意要将此类放到`org.springframework.context.annotation`包下面。 - 其中`isExcludedClass` 的方法可以定制逻辑,进行相关的Configuration类排除 ## 总结 - 可以动态让某个@Import导入的@Configuration类进行失效可以实现有效控制