最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring如何重寫內(nèi)置Bean(Controller、Service等)

 更新時(shí)間:2025年01月06日 09:32:17   作者:catoop  
本文介紹了在Spring Boot工程中處理外部JAR包中Controller方法重寫的需求,通過PostProcessor方式和自定義注解@ExcludeBean兩種方法,解決了在不修改源代碼的情況下重寫接口的問題

Spring重寫內(nèi)置Bean(Controller、Service等)

場景

  • svc1.jar 中有一個(gè) TestController 類,當(dāng)前源代碼工程 demo 依賴了這個(gè) svc1.jar。
  • 當(dāng)前 demo 工程啟動正常,TestController 被初始化,TestController 中提供的接口 /svc1/test1、/svc1/test2、/svc1/test3 均可以正常訪問。
  • 因接口 /svc1/test2 對應(yīng)的方法中邏輯處理不滿足需求,需要對這個(gè)方法進(jìn)行重寫處理。
  • 該接口在 svc1.jar 包,不能直接修改源代碼。

處理方式一(簡單處理)

主要思路是在 Spring 注冊 Bean 之后進(jìn)行 PostProcessor 時(shí),將已經(jīng)注冊的 svc1.jar 中的 TestController 從上下文中刪除。

使我們新創(chuàng)建的繼承 TestController 的重寫類能被正常加載實(shí)例化,而不出現(xiàn) PathMapping 重復(fù)的報(bào)錯(cuò)沖突。

主要代碼如下:

/**
 * 排除容器中的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));
    }

    /**
     * 根據(jù)類 class 獲取 spring 默認(rèn)的 beanName
     *
     * @param clazz clazz
     * @return String
     */
    private String getDefaultBeanName(Class<?> clazz) {
        // 測試內(nèi)部類 AutowireUtils.ObjectFactoryDelegatingInvocationHandler 的默認(rèn) 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...");
    }

}

處理方式二(自定義注解)

我們可以自定義一個(gè)注解 @ExcludeBean,然后使用該注解來很方便的在任何地方來排除需要排除的類。

1、自定義注解

/** 
 * 自定義注解,用來排除原本會在spring上下文中的bean。
 * 一般用于刪除一個(gè)不可以修改的Bean,然后自定義一個(gè)類繼承原有類然后重寫特定的方法取代原來的類
 * 
 * @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、注解使用示例

我們來重寫一個(gè) Controller 的方法,主要應(yīng)用場景是:目標(biāo) Controller 是通過 jar 包依賴過來的,并且我們需要重寫其中的一個(gè)方法邏輯。

/**
 * 重寫 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!";
    }

}

補(bǔ)充

如果是基于一個(gè)接口然后有多個(gè)實(shí)現(xiàn)類的多實(shí)例場景,使用的地方是基于接口注入的。

也可以使用 @Primary 注解來修飾特定的類。

但是對于如 Controller 以及其他沒有定義并通過接口注入方式的可能就要使用我們本文的方法了。

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java開發(fā)中StepBuilder模式詳解

    Java開發(fā)中StepBuilder模式詳解

    Step builder多階段步驟構(gòu)造器模式是一種對象創(chuàng)建軟件設(shè)計(jì)模式,與傳統(tǒng)構(gòu)建器模式進(jìn)行比較時(shí),步驟構(gòu)建器模式提供了一些簡潔的好處,這篇文章主要介紹了Java開發(fā)中StepBuilder模式的相關(guān)資料,需要的朋友可以參考下
    2026-01-01
  • 詳解SpringBoot應(yīng)用服務(wù)啟動與安全終止

    詳解SpringBoot應(yīng)用服務(wù)啟動與安全終止

    這篇文章主要介紹了SpringBoot應(yīng)用服務(wù)啟動與安全終止,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • 詳解RocketMQ 消費(fèi)端如何監(jiān)聽消息

    詳解RocketMQ 消費(fèi)端如何監(jiān)聽消息

    這篇文章主要為大家介紹了RocketMQ 消費(fèi)端如何監(jiān)聽消息示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • JSON復(fù)雜數(shù)據(jù)處理之Json樹形結(jié)構(gòu)數(shù)據(jù)轉(zhuǎn)Java對象并存儲到數(shù)據(jù)庫的實(shí)現(xiàn)

    JSON復(fù)雜數(shù)據(jù)處理之Json樹形結(jié)構(gòu)數(shù)據(jù)轉(zhuǎn)Java對象并存儲到數(shù)據(jù)庫的實(shí)現(xiàn)

    這篇文章主要介紹了JSON復(fù)雜數(shù)據(jù)處理之Json樹形結(jié)構(gòu)數(shù)據(jù)轉(zhuǎn)Java對象并存儲到數(shù)據(jù)庫的實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下
    2016-03-03
  • Java運(yùn)算符從見過到掌握上

    Java運(yùn)算符從見過到掌握上

    計(jì)算機(jī)的最基本用途之一就是執(zhí)行數(shù)學(xué)運(yùn)算,作為一門計(jì)算機(jī)語言,Java也提供了一套豐富的運(yùn)算符來操縱變量,本篇對大家的學(xué)習(xí)或工作具有一定的價(jià)值,需要的朋友可以參考下
    2021-09-09
  • java遞歸算法的實(shí)例詳解

    java遞歸算法的實(shí)例詳解

    在本篇文章里小編給大家整理了關(guān)于java遞歸算法的實(shí)例內(nèi)容,以及相關(guān)知識點(diǎn)總結(jié),需要的朋友們可以學(xué)習(xí)下。
    2020-02-02
  • java 啟動exe程序,傳遞參數(shù)和獲取參數(shù)操作

    java 啟動exe程序,傳遞參數(shù)和獲取參數(shù)操作

    這篇文章主要介紹了java 啟動exe程序,傳遞參數(shù)和獲取參數(shù)操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • SpringBoot中循環(huán)依賴問題的原理與解決方案

    SpringBoot中循環(huán)依賴問題的原理與解決方案

    在Spring Boot開發(fā)中,依賴注入(DI)是核心特性之一,本文將通過一個(gè)實(shí)際錯(cuò)誤案例,深入分析Spring Boot循環(huán)依賴的成因、解決方案,并提供最佳實(shí)踐建議,希望對大家有所幫助
    2025-07-07
  • 基于Spring boot @Value 注解注入屬性值的操作方法

    基于Spring boot @Value 注解注入屬性值的操作方法

    這篇文章主要介紹了結(jié)合SpEL使用@Value-基于配置文件或非配置的文件的值注入-Spring Boot的相關(guān)知識,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-07-07
  • java中volatile不能保證線程安全(實(shí)例講解)

    java中volatile不能保證線程安全(實(shí)例講解)

    下面小編就為大家?guī)硪黄猨ava中volatile不能保證線程安全(實(shí)例講解)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-09-09

最新評論

临高县| 资溪县| 太保市| 平遥县| 宜兰县| 远安县| 通州市| 旺苍县| 微山县| 泾源县| 太和县| 夏河县| 虹口区| 德昌县| 吴桥县| 沾化县| 锦屏县| 山东| 高青县| 日土县| 灌云县| 稷山县| 盐池县| 富顺县| 镇原县| 保亭| 和顺县| 邯郸县| 东光县| 鲁甸县| 故城县| 娄底市| 叙永县| 突泉县| 瑞丽市| 仁寿县| 河池市| 漳州市| 七台河市| 长泰县| 安岳县|