Spring rewrites built-in beans (Controller, Service, etc.)
Scene
-
One of them
TestController
Class, the current source code project demo depends on this。
- The demo project is started normally, and the TestController is initialized.
TestController
The interface provided in/svc1/test1
、/svc1/test2
、/svc1/test3
All are accessible normally. - Because of the interface
/svc1/test2
The logical processing in the corresponding method does not meet the requirements, so this method needs to be rewrited. - The interface is
Package, the source code cannot be modified directly.
Processing method 1 (simple processing)
The main idea is to register the PostProcessor after Spring registers a bean.The TestController in , is removed from the context.
This enables our newly created rewrite class inheriting TestController to be loaded and instantiated normally without repeated error collisions with PathMapping.
The main code is as follows:
/** * Exclude beans in containers * * @author Shan Hongyu * @since 2024/11/28 13:14 */ @Slf4j @Configuration public class ExcludeComponentConfiguration implements BeanDefinitionRegistryPostProcessor { @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { (getDefaultBeanName()); (getDefaultBeanName()); } /** * Get the default beanName of spring according to class class * * @param clazz clazz * @return String */ private String getDefaultBeanName(Class<?> clazz) { // Test the default BeanName of the inner class // ((())) // Used before spring 6.0 () return ((())); } }
/** * Rewrite the FileController class * * @author Shan Hongyu * @since 2024/11/28 12:03 */ @RestController //The annotation must be included, and those annotations of Mapping are not requiredpublic class OverrideFileController extends FileController { @Override public void fileDownload(@RequestParam("fileId") Long fileId, @RequestParam("isInline") Integer isInline, HttpServletResponse response, HttpServletRequest request) { ("override filedownload..."); } }
Processing method 2 (custom annotation)
We can customize annotation@ExcludeBean
, and then use this annotation to easily exclude classes that need to be excluded anywhere.
1. Custom annotations
/** * Custom annotations to exclude beans that would have been in the spring context. * It is generally used to delete a bean that cannot be modified, and then customize a class to inherit the original class and then rewrite a specific method to replace the original class. * * @author Shan Hongyu * @since 2024/12/5 9:36 */ @Target({}) @Retention() @Documented @Component public @interface ExcludeBean { Class<?>[] clazz() default {}; String[] name() default {}; }
2. Automatic configuration class
/** * Exclude Spring Bean automatic configuration classes * @author Shan Hongyu * @since 2024/12/5 9:13 */ @AutoConfiguration public class ExcludeBeanAutoConfiguration implements BeanDefinitionRegistryPostProcessor { @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { // not implemented } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { if (beanFactory instanceof BeanDefinitionRegistry bdr) { (()) .map(item -> (item, , false)).filter(Objects::nonNull) .flatMap(item -> ((()), (()).map(cls -> ((()))))) .distinct() .forEach(bdr::removeBeanDefinition); } } }
3. Configure automatic configuration
@AutoConfiguration
For details on how to enable automatic configuration annotations, please refer to the article:SpringBoot Automatic Configuration @AutoConfiguration added in version 2.7
4. Annotation usage examples
Let's rewrite a Controller method. The main application scenario is: the target Controller is depended on through the jar package, and we need to rewrite one of the method logic.
/** * Rewrite specific methods in the Controller class TestApi * * @author Shan Hongyu * @since 2024/11/28 9:06 */ @ExcludeBean(clazz = ) @RestController public class OverrideTestApi extends TestApi { /** * Rewrite Hello method * * @return String */ @Override public String hello() { return "Hello, Override!"; } }
Replenish
If it is based on one interface and then there are multiple implementation classes, the use is based on interface injection.
Can also be used@Primary
Annotations to modify specific classes.
But forController
As well as other methods that are not defined and injected through interfaces, we need to use the methods in this article.
Summarize
The above is personal experience. I hope you can give you a reference and I hope you can support me more.