SoFunction
Updated on 2025-04-06

How to implement @OverrideBean annotation for Spring overlay container

Spring override container bean annotation implementation @OverrideBean

During project development, sometimes a third-party framework will automatically inject beans into Spring containers. When we have the need to modify the corresponding built-in bean implementation, we can use the method of replacing the built-in beans by replacing the columns. You need to pay attention to the following two points:

  • 1. When the corresponding bean is used in other places, it is based on interface injection.
  • 2. If it is not a bean based on interface injection, you may need to rewrite the same package name in this way (there may be problems and is not recommended).

From the above two points, we can also draw a conclusion, that is, the benefits of "interface-based programming".

Please refer to the code for specific implementation

(Code snippet, for reference only, modified according to the actual usage scenario):

import ;
import ;
import ;
import ;

/**
  * Overwrite Beans in Spring containers
  *
  * @author shanhy
  * @date 2021/4/25 13:40
  */
@Retention()
@Target()
public @interface OverrideBean {

    /**
      * Name of the bean that needs to be replaced
      *
      * @return
      */
    String value();
    
}
import org.;
import org.;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;

import ;
import ;
import ;
import ;

/**
  * Rewrite the configuration class of the bean
  *
  * @author shanhy
  * @date 2021/4/25 13:41
  */
@Configuration
public class OverrideBeanConfiguration implements BeanDefinitionRegistryPostProcessor, BeanFactoryAware {

    private static final Logger log = ();

    private BeanFactory beanFactory;

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        ("searching for classes annotated with @OverrideBean");

        // Customize Scanner to scan the specified annotation under classpath        ClassPathOverrideBeanAnnotationScanner scanner = new ClassPathOverrideBeanAnnotationScanner(registry);
        try {
            // Get the package path            List<String> packages = ();

            if (()) {
                for (String p : packages) {
                    ("Using auto-configuration base package: {}", p);
                }
            }

            // Scan all loaded packages            ((packages));
        } catch (IllegalStateException ex) {
            ("could not determine auto-configuration package, automatic OverrideBean scanning disabled.", ex);
        }
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException {
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
         = beanFactory;
    }

    private static class ClassPathOverrideBeanAnnotationScanner extends ClassPathBeanDefinitionScanner {

        ClassPathOverrideBeanAnnotationScanner(BeanDefinitionRegistry registry) {
            super(registry, false);
            // Set filter.  Scan only @OverrideBean            addIncludeFilter(new AnnotationTypeFilter());
        }

        @Override
        public Set<BeanDefinitionHolder> doScan(String... basePackages) {
            List<String> overrideClassNames = new ArrayList<>();
            // Scan all packages to specify the beans specified by annotationClass            Set<BeanDefinitionHolder> beanDefinitions = (basePackages);

            GenericBeanDefinition definition;
            for (BeanDefinitionHolder holder : beanDefinitions) {
                definition = (GenericBeanDefinition) ();

                // Get the class name and create a Class object                String className = ();
                Class<?> clazz = classNameToClass(className);

                // parse the value on the annotation                OverrideBean annotation = (clazz).getAnnotation();
                if (annotation == null || ().length() == 0) {
                    continue;
                }

                // Replace the bean with the specified name in the value using the currently loaded @OverrideBean specified                if ((getRegistry()).containsBeanDefinition(())) {
                    getRegistry().removeBeanDefinition(());
                    getRegistry().registerBeanDefinition((), definition);
                    (());
                }
            }
            ("found override beans: " + overrideClassNames);

            return beanDefinitions;
        }

        //Reflection gets the Class object through the class name        private Class<?> classNameToClass(String className) {
            try {
                return (className);
            } catch (ClassNotFoundException e) {
                ("create instance failed.", e);
            }
            return null;
        }
    }

}

Summarize

The above is personal experience. I hope you can give you a reference and I hope you can support me more.