Spring如何重写内置Bean(Controller、Service等)
Spring重写内置Bean(Controller、Service等)
场景
svc1.jar
中有一个TestController
类,当前源代码工程 demo 依赖了这个svc1.jar
。- 当前 demo 工程启动正常,TestController 被初始化,
TestController
中提供的接口/svc1/test1
、/svc1/test2
、/svc1/test3
均可以正常访问。 - 因接口
/svc1/test2
对应的方法中逻辑处理不满足需求,需要对这个方法进行重写处理。 - 该接口在
svc1.jar
包,不能直接修改源代码。
处理方式一(简单处理)
主要思路是在 Spring 注册 Bean 之后进行 PostProcessor 时,将已经注册的 svc1.jar
中的 TestController 从上下文中删除。
使我们新创建的继承 TestController 的重写类能被正常加载实例化,而不出现 PathMapping 重复的报错冲突。
主要代码如下:
/** * 排除容器中的Bean * * @author 单红宇 * @since 2024/11/28 13:14 */ @Slf4j @Configuration public class ExcludeComponentConfiguration implements BeanDefinitionRegistryPostProcessor { @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { registry.removeBeanDefinition(getDefaultBeanName(FileController.class)); registry.removeBeanDefinition(getDefaultBeanName(UserController.class)); } /** * 根据类 class 获取 spring 默认的 beanName * * @param clazz clazz * @return String */ private String getDefaultBeanName(Class<?> clazz) { // 测试内部类 AutowireUtils.ObjectFactoryDelegatingInvocationHandler 的默认 BeanName // StringUtils.uncapitalizeAsProperty(ClassUtils.getShortName(AutowireUtils.ObjectFactoryDelegatingInvocationHandler.class.getName())) // spring 6.0 之前使用 StringUtils.uncapitalize() return org.springframework.util.StringUtils.uncapitalizeAsProperty(ClassUtils.getShortName(clazz.getName())); } }
/** * 重写FileController类 * * @author 单红宇 * @since 2024/11/28 12:03 */ @RestController //该注解必须要有,Mapping那些注解不需要 public class OverrideFileController extends FileController { @Override public void fileDownload(@RequestParam("fileId") Long fileId, @RequestParam("isInline") Integer isInline, HttpServletResponse response, HttpServletRequest request) { System.out.println("override filedownload..."); } }
处理方式二(自定义注解)
我们可以自定义一个注解 @ExcludeBean
,然后使用该注解来很方便的在任何地方来排除需要排除的类。
1、自定义注解
/** * 自定义注解,用来排除原本会在spring上下文中的bean。 * 一般用于删除一个不可以修改的Bean,然后自定义一个类继承原有类然后重写特定的方法取代原来的类 * * @author 单红宇 * @since 2024/12/5 9:36 */ @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface ExcludeBean { Class<?>[] clazz() default {}; String[] name() default {}; }
2、自动配置类
/** * 排除 Spring Bean 自动配置类 * @author 单红宇 * @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) { Arrays.stream(beanFactory.getBeanNamesForAnnotation(ExcludeBean.class)) .map(item -> beanFactory.findAnnotationOnBean(item, ExcludeBean.class, false)).filter(Objects::nonNull) .flatMap(item -> Stream.concat(Arrays.stream(item.name()), Arrays.stream(item.clazz()).map(cls -> org.springframework.util.StringUtils.uncapitalizeAsProperty(ClassUtils.getShortName(cls.getName()))))) .distinct() .forEach(bdr::removeBeanDefinition); } } }
3、配置自动配置
@AutoConfiguration
自动配置注解启用的方法详见文章: SpringBoot 自动配置 @AutoConfiguration 在 2.7 版本新增
4、注解使用示例
我们来重写一个 Controller 的方法,主要应用场景是:目标 Controller 是通过 jar 包依赖过来的,并且我们需要重写其中的一个方法逻辑。
/** * 重写 Controller 类 TestApi 中的特定方法 * * @author 单红宇 * @since 2024/11/28 9:06 */ @ExcludeBean(clazz = TestApi.class) @RestController public class OverrideTestApi extends TestApi { /** * 重写 Hello 方法 * * @return String */ @Override public String hello() { return "Hello, Override!"; } }
补充
如果是基于一个接口然后有多个实现类的多实例场景,使用的地方是基于接口注入的。
也可以使用 @Primary
注解来修饰特定的类。
但是对于如 Controller
以及其他没有定义并通过接口注入方式的可能就要使用我们本文的方法了。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
相关文章
Spring中@Transactional注解关键属性和用法小结
在Spring框架中,@Transactional 是一个注解,用于声明事务性的方法,它提供了一种声明式的事务管理方式,避免了在代码中直接编写事务管理相关的代码,本文给大家介绍@Transactional 注解的一些关键属性和用法,感兴趣的朋友一起看看吧2023-12-12MyBatis批量插入数据到Oracle数据库中的两种方式(实例代码)
本文通过实例代码给大家分享了MyBatis批量插入数据到Oracle数据库中的两种方式,非常不错,具有参考借鉴价值,需要的朋友参考下吧2017-09-09Spring MVC集成springfox-swagger2构建restful API的方法详解
这篇文章主要给大家介绍了关于Spring MVC集成springfox-swagger2构建restful API的相关资料,文中介绍介绍的非常详细,需要的朋友可以参考借鉴,下面来一起看看吧。2017-06-06java利用CompletionService保证任务先完成先获取到执行结果
这篇文章主要为大家详细介绍了java如何利用CompletionService来保证任务先完成先获取到执行结果,文中的示例代码讲解详细,需要的可以参考下2023-08-08
最新评论