吴忠躺衫网络科技有限公司

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Spring中11個最常用的擴展點分享2

jf_78858299 ? 來源:JAVA旭陽 ? 作者:JAVA旭陽 ? 2023-05-11 10:48 ? 次閱讀

5.1 通用類

這種引入方式是最簡單的,引入的類會被實例化為一個bean對象。

public class A {
}

@Import(A.class)
@Configuration
public class TestConfiguration {

}

通過@Import注解引入類A,spring可以自動實例化A對象,然后在需要使用的地方通過注解@Autowired注入:

@Autowired
private A a;

5.2 配置類

這種引入方式是最復雜的,因為@Configuration支持還支持多種組合注解,比如:

  • @Import
  • @ImportResource
  • @PropertySource
public class A {
}

public class B {
}

@Import(B.class)
@Configuration
public class AConfiguration {

    @Bean
    public A a() {
        return new A();
    }
}

@Import(AConfiguration.class)
@Configuration
public class TestConfiguration {
}

@Configuration注解的配置類通過@Import注解導入,配置類@Import@ImportResource相關注解引入的類會一次性全部遞歸引入@PropertySource所在的屬性。

5.3 ImportSelector

該導入方法需要實現ImportSelector接口

public class AImportSelector implements ImportSelector {

    private static final String CLASS_NAME = "com.sue.cache.service.test13.A";

    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{CLASS_NAME};
    }
}

@Import(AImportSelector.class)
@Configuration
public class TestConfiguration {
}

這種方法的好處是selectImports方法返回的是一個數組,也就是說可以同時引入多個類,非常方便。

5.4 ImportBeanDefinitionRegistrar

該導入方法需要實現ImportBeanDefinitionRegistrar接口:

public class AImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(A.class);
        registry.registerBeanDefinition("a", rootBeanDefinition);
    }
}

@Import(AImportBeanDefinitionRegistrar.class)
@Configuration
public class TestConfiguration {
}

這種方法是最靈活的。容器注冊對象可以在registerBeanDefinitions方法中獲取,可以手動創建BeanDefinition注冊到BeanDefinitionRegistry種。

6. 當工程啟動時

有時候我們需要在項目啟動的時候自定義一些額外的功能,比如加載一些系統參數,完成初始化,預熱本地緩存等。我們應該做什么?

好消息是 SpringBoot 提供了:

  • CommandLineRunner
  • ApplicationRunner

這兩個接口幫助我們實現了上面的需求。

它們的用法很簡單,以ApplicationRunner接口為例:

@Component
public class TestRunner implements ApplicationRunner {

    @Autowired
    private LoadDataService loadDataService;

    public void run(ApplicationArguments args) throws Exception {
        loadDataService.load();
    }
}

實現ApplicationRunner接口,重寫run方法,在該方法中實現您的自定義需求。

如果項目中有多個類實現了ApplicationRunner接口,如何指定它們的執行順序?

答案是使用@Order(n)注解,n的值越小越早執行。當然,順序也可以通過@Priority注解來指定。

7. 修改BeanDefinition

在實例化Bean對象之前,Spring IOC需要讀取Bean的相關屬性,保存在BeanDefinition對象中,然后通過BeanDefinition對象實例化Bean對象。

如果要修改BeanDefinition對象中的屬性怎么辦?

答案 :我們可以實現 BeanFactoryPostProcessor 接口。

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory;
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
        beanDefinitionBuilder.addPropertyValue("id", 123);
        beanDefinitionBuilder.addPropertyValue("name", "Tom");
        defaultListableBeanFactory.registerBeanDefinition("user", beanDefinitionBuilder.getBeanDefinition());
    }
}

postProcessBeanFactory方法中,可以獲取BeanDefinition的相關對象,修改對象的屬性。

8. 初始化 Bean 前和后

有時,您想在 bean 初始化前后實現一些您自己的邏輯。

這時候就可以實現:BeanPostProcessor接口。

該接口目前有兩個方法:

  • postProcessBeforeInitialization:應該在初始化方法之前調用。
  • postProcessAfterInitialization:此方法在初始化方法之后調用。
@Component
    public class MyBeanPostProcessor implements BeanPostProcessor {

        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            if (bean instanceof User) {
                ((User) bean).setUserName("Tom");
            }
            return bean;
        }
    }

我們經常使用的@Autowired@Value@Resource@PostConstruct等注解都是通過AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor來實現的。

9. 初始化方法

目前在Spring中初始化bean的方式有很多種:

  1. 使用@PostConstruct注解
  2. 實現InitializingBean接口

9.1 使用 @PostConstruct

@Service
public class AService {
    @PostConstruct
    public void init() {
        System.out.println("===init===");
    }
}

為需要初始化的方法添加注解@PostConstruct,使其在Bean初始化時執行。

9.2 實現初始化接口InitializingBean

@Service
public class BService implements InitializingBean {

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("===init===");
    }
}

實現InitializingBean接口,重寫afterPropertiesSet方法,在該方法中可以完成初始化功能。

10. 關閉Spring容器前

有時候,我們需要在關閉spring容器之前做一些額外的工作,比如關閉資源文件。

此時你可以實現 DisposableBean 接口并重寫它的 destroy 方法。

@Service
public class DService implements InitializingBean, DisposableBean {

    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean destroy");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean afterPropertiesSet");
    }
}

這樣,在spring容器銷毀之前,會調用destroy方法做一些額外的工作。

通常我們會同時實現InitializingBeanDisposableBean接口,重寫初始化方法和銷毀方法。

11. 自定義Beanscope

我們都知道spring core默認只支持兩種Scope

  • Singleton單例,從spring容器中獲取的每一個bean都是同一個對象。
  • prototype多實例,每次從spring容器中獲取的bean都是不同的對象。

Spring Web 再次擴展了 Scope,添加

  • RequestScope:同一個請求中從spring容器中獲取的bean都是同一個對象。
  • SessionScope:同一個session從spring容器中獲取的bean都是同一個對象。

盡管如此,有些場景還是不符合我們的要求。

比如我們在同一個線程中要從spring容器中獲取的bean都是同一個對象,怎么辦?

答案 :這需要一個自定義范圍。

  1. 實現 Scope 接口
public class ThreadLocalScope implements Scope {
    private static final ThreadLocal THREAD_LOCAL_SCOPE = new ThreadLocal();

    @Override
    public Object get(String name, ObjectFactory? objectFactory) {
        Object value = THREAD_LOCAL_SCOPE.get();
        if (value != null) {
            return value;
        }

        Object object = objectFactory.getObject();
        THREAD_LOCAL_SCOPE.set(object);
        return object;
    }

    @Override
    public Object remove(String name) {
        THREAD_LOCAL_SCOPE.remove();
        return null;
    }

    @Override
    public void registerDestructionCallback(String name, Runnable callback) {
    }

    @Override
    public Object resolveContextualObject(String key) {
        return null;
    }

    @Override
    public String getConversationId() {
        return null;
    }
}
  1. 將新定義的Scope注入到Spring容器中
@Component
public class ThreadLocalBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        beanFactory.registerScope("threadLocalScope", new ThreadLocalScope());
    }
}
  1. 使用新定義的Scope
@Scope("threadLocalScope")
@Service
public class CService {
    public void add() {
    }
}

總結

本文總結了Spring中很常用的11個擴展點,可以在Bean創建、初始化到銷毀各個階段注入自己想要的邏輯,也有Spring MVC相關的攔截器等擴展點,希望對大家有幫助。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 轉換器
    +關注

    關注

    27

    文章

    8745

    瀏覽量

    148055
  • 框架
    +關注

    關注

    0

    文章

    403

    瀏覽量

    17543
  • spring
    +關注

    關注

    0

    文章

    340

    瀏覽量

    14390
收藏 人收藏

    評論

    相關推薦

    什么是java spring

    的事情。然而,Spring的用途不僅限于服務器端的開發。從簡單性、可測試性和松耦合的角度而言,任何Java應用都可以從Spring受益。Spring是一
    發表于 09-11 11:16

    Spring工作原理

    Spring所提供的這些服務和功能。Spring里用的最經典的一設計模式就是:模板方法模式。(這里我都不介紹了,是一常用的設計模式)
    發表于 07-10 07:41

    啟動Spring Boot項目應用的三種方法

    基礎。我們知道了Spring Boot是什么了,那么我們又該如何啟動Spring Boot應用呢?這里小編給大家推薦常用的三種方法。分別是IDEA編輯器啟動、命令啟動、java命令j
    發表于 01-14 17:33

    STM32時鐘系統最常用的知識

    ,講一最常用的知識。其它的型號大同小異。時鐘含義特點HSE外部高速時鐘信號一般選擇外接晶振,最常用的時鐘信號。電機驅動板外接12MhzHSI內部高速時鐘信號由單片...
    發表于 08-11 07:39

    高手最常用的電腦五組合鍵

    高手最常用的電腦五組合鍵 winkey+d : 這是高手最常用的第一快捷組合鍵。這個快捷鍵組合可以將桌面上的所有窗口瞬間最小化,無論是聊天的窗口還是
    發表于 02-24 10:41 ?61次下載

    Spring認證_什么是Spring GraphQL?

    數據整合 Spring GraphQL 支持使用 Querydsl 通過 Spring Data Querydsl 擴展 來獲取數據。Querydsl 提供了一種靈活但類型安全的方法,通過使用注釋
    的頭像 發表于 08-09 11:31 ?668次閱讀
    <b class='flag-5'>Spring</b>認證_什么是<b class='flag-5'>Spring</b> GraphQL?

    最常用11款Kubernetes工具

    助于改善 Kubernetes 開發人員的體驗。本文列出作者自己最常用11 款 Kubernetes 工具,并對它們進行了分類介紹。 Kubernetes 是一非常強大的容器編排平臺。但在
    的頭像 發表于 08-23 10:43 ?2206次閱讀

    10電源設計最常用公式的解析

    本文將為你解析10電源設計最常用的公式。非常實用,推薦收藏哦~
    發表于 02-10 11:40 ?8次下載
    10<b class='flag-5'>個</b>電源設計<b class='flag-5'>最常用</b>公式的解析

    Spring最常用11擴展

    除此之外,我們在使用spring的過程,有沒有發現它的擴展能力非常強。由于這個優勢的存在,讓spring擁有強大的包容能力,讓很多第三方應用能夠輕松投入
    的頭像 發表于 01-11 10:31 ?947次閱讀

    剖析Spring最常用擴展(上)

    我們一說到spring,可能第一想到的是 `IOC`(控制反轉) 和 `AOP`(面向切面編程)。 沒錯,它們是spring的基石,得益于它們的優秀設計,使得spring能夠從
    的頭像 發表于 02-15 16:06 ?793次閱讀
    剖析<b class='flag-5'>Spring</b>中<b class='flag-5'>最常用</b>的<b class='flag-5'>擴展</b><b class='flag-5'>點</b>(上)

    剖析Spring最常用擴展

    我們一說到spring,可能第一想到的是 `IOC`(控制反轉) 和 `AOP`(面向切面編程)。 沒錯,它們是spring的基石,得益于它們的優秀設計,使得spring能夠從
    的頭像 發表于 02-15 16:06 ?546次閱讀
    剖析<b class='flag-5'>Spring</b>中<b class='flag-5'>最常用</b>的<b class='flag-5'>擴展</b><b class='flag-5'>點</b>(<b class='flag-5'>中</b>)

    剖析Spring最常用擴展(下)

    我們一說到spring,可能第一想到的是 `IOC`(控制反轉) 和 `AOP`(面向切面編程)。 沒錯,它們是spring的基石,得益于它們的優秀設計,使得spring能夠從
    的頭像 發表于 02-15 16:07 ?514次閱讀

    基于spring的SPI擴展機制是如何實現的?

    基本上,你一說是基于 spring 的 SPI 擴展機制,再把spring.factories文件和EnableAutoConfiguration提一下,那么這個問題就答的八九不離十了。
    的頭像 發表于 03-07 09:17 ?1101次閱讀

    Spring11最常用擴展分享1

    在使用spring的過程,我們有沒有發現它的擴展能力很強呢?由于這個優勢的存在,使得spring具有很強的包容性,所以很多第三方應用或者框架可以很容易的投入到
    的頭像 發表于 05-11 10:48 ?592次閱讀

    Verilog最常用2種數據類型

    Verilog 最常用2 種數據類型就是線網(wire)與寄存器(reg),其余類型可以理解為這兩種數據類型的擴展或輔助。
    的頭像 發表于 05-29 16:27 ?2452次閱讀
    Verilog<b class='flag-5'>最常用</b>的<b class='flag-5'>2</b>種數據類型
    圣淘沙百家乐官网的玩法技巧和规则 | 法拉利百家乐的玩法技巧和规则 | 云鼎百家乐程序开发有限公司| 金城百家乐官网买卖路| 德州扑克玩法说明| 百家乐庄6点| 高楼24层风水好吗| 百家乐官网哪条下路好| 瑞博国际| 大发888娱乐城技巧| 百家乐龙虎台布作弊技巧| 百家乐官网冼牌机| 百家乐官网贴| 百家乐官网闲庄概率| 娱乐城去澳门| 二八杠游戏| 玩百家乐有何技巧| 百家乐打印程序| 678百家乐官网博彩娱乐场开户注册| 百家乐官网tt娱乐城| 金冠娱乐城网站| 棋牌游戏开发商| 百家乐电子| 百家乐最佳打| 菲律百家乐太阳城| 百家乐包赢技巧| 鼎尚百家乐官网的玩法技巧和规则 | 百家乐官网赢家打法| 百家乐官网闲拉长龙| 赌场风云2| 娱乐城注册送18体验金| 大发888娱乐城下载英皇国际| 百家乐娱乐网官网网| 百家乐软件稳赚| 百家乐游戏补牌规则| 百家乐官网博彩网太阳城娱乐城| 大世界百家乐官网娱乐平台| 百家乐官网三珠投注法| 网上百家乐官网分析软件| 利赢百家乐官网现金网| 百家乐官网高手qq|