0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Spring中11個(gè)最常用的擴(kuò)展點(diǎn)分享2

jf_78858299 ? 來(lái)源:JAVA旭陽(yáng) ? 作者:JAVA旭陽(yáng) ? 2023-05-11 10:48 ? 次閱讀

5.1 通用類

這種引入方式是最簡(jiǎn)單的,引入的類會(huì)被實(shí)例化為一個(gè)bean對(duì)象。

public class A {
}

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

}

通過(guò)@Import注解引入類A,spring可以自動(dòng)實(shí)例化A對(duì)象,然后在需要使用的地方通過(guò)注解@Autowired注入:

@Autowired
private A a;

5.2 配置類

這種引入方式是最復(fù)雜的,因?yàn)锧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注解的配置類通過(guò)@Import注解導(dǎo)入,配置類@Import、@ImportResource相關(guān)注解引入的類會(huì)一次性全部遞歸引入@PropertySource所在的屬性。

5.3 ImportSelector

該導(dǎo)入方法需要實(shí)現(xiàn)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方法返回的是一個(gè)數(shù)組,也就是說(shuō)可以同時(shí)引入多個(gè)類,非常方便。

5.4 ImportBeanDefinitionRegistrar

該導(dǎo)入方法需要實(shí)現(xiàn)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 {
}

這種方法是最靈活的。容器注冊(cè)對(duì)象可以在registerBeanDefinitions方法中獲取,可以手動(dòng)創(chuàng)建BeanDefinition注冊(cè)到BeanDefinitionRegistry種。

6. 當(dāng)工程啟動(dòng)時(shí)

有時(shí)候我們需要在項(xiàng)目啟動(dòng)的時(shí)候自定義一些額外的功能,比如加載一些系統(tǒng)參數(shù),完成初始化,預(yù)熱本地緩存等。我們應(yīng)該做什么?

好消息是 SpringBoot 提供了:

  • CommandLineRunner
  • ApplicationRunner

這兩個(gè)接口幫助我們實(shí)現(xiàn)了上面的需求。

它們的用法很簡(jiǎn)單,以ApplicationRunner接口為例:

@Component
public class TestRunner implements ApplicationRunner {

    @Autowired
    private LoadDataService loadDataService;

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

實(shí)現(xiàn)ApplicationRunner接口,重寫(xiě)run方法,在該方法中實(shí)現(xiàn)您的自定義需求。

如果項(xiàng)目中有多個(gè)類實(shí)現(xiàn)了ApplicationRunner接口,如何指定它們的執(zhí)行順序?

答案是使用@Order(n)注解,n的值越小越早執(zhí)行。當(dāng)然,順序也可以通過(guò)@Priority注解來(lái)指定。

7. 修改BeanDefinition

在實(shí)例化Bean對(duì)象之前,Spring IOC需要讀取Bean的相關(guān)屬性,保存在BeanDefinition對(duì)象中,然后通過(guò)BeanDefinition對(duì)象實(shí)例化Bean對(duì)象。

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

答案 :我們可以實(shí)現(xiàn) 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的相關(guān)對(duì)象,修改對(duì)象的屬性。

8. 初始化 Bean 前和后

有時(shí),您想在 bean 初始化前后實(shí)現(xiàn)一些您自己的邏輯。

這時(shí)候就可以實(shí)現(xiàn):BeanPostProcessor接口。

該接口目前有兩個(gè)方法:

  • postProcessBeforeInitialization:應(yīng)該在初始化方法之前調(diào)用。
  • postProcessAfterInitialization:此方法在初始化方法之后調(diào)用。
@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;
        }
    }

我們經(jīng)常使用的@Autowired、@Value、@Resource、@PostConstruct等注解都是通過(guò)AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor來(lái)實(shí)現(xiàn)的。

9. 初始化方法

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

  1. 使用@PostConstruct注解
  2. 實(shí)現(xiàn)InitializingBean接口

9.1 使用 @PostConstruct

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

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

9.2 實(shí)現(xiàn)初始化接口InitializingBean

@Service
public class BService implements InitializingBean {

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

實(shí)現(xiàn)InitializingBean接口,重寫(xiě)afterPropertiesSet方法,在該方法中可以完成初始化功能。

10. 關(guān)閉Spring容器前

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

此時(shí)你可以實(shí)現(xiàn) DisposableBean 接口并重寫(xiě)它的 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容器銷毀之前,會(huì)調(diào)用destroy方法做一些額外的工作。

通常我們會(huì)同時(shí)實(shí)現(xiàn)InitializingBeanDisposableBean接口,重寫(xiě)初始化方法和銷毀方法。

11. 自定義Beanscope

我們都知道spring core默認(rèn)只支持兩種Scope

  • Singleton單例,從spring容器中獲取的每一個(gè)bean都是同一個(gè)對(duì)象。
  • prototype多實(shí)例,每次從spring容器中獲取的bean都是不同的對(duì)象。

Spring Web 再次擴(kuò)展了 Scope,添加

  • RequestScope:同一個(gè)請(qǐng)求中從spring容器中獲取的bean都是同一個(gè)對(duì)象。
  • SessionScope:同一個(gè)session從spring容器中獲取的bean都是同一個(gè)對(duì)象。

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

比如我們?cè)谕粋€(gè)線程中要從spring容器中獲取的bean都是同一個(gè)對(duì)象,怎么辦?

答案 :這需要一個(gè)自定義范圍。

  1. 實(shí)現(xiàn) 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() {
    }
}

總結(jié)

本文總結(jié)了Spring中很常用的11個(gè)擴(kuò)展點(diǎn),可以在Bean創(chuàng)建、初始化到銷毀各個(gè)階段注入自己想要的邏輯,也有Spring MVC相關(guān)的攔截器等擴(kuò)展點(diǎn),希望對(duì)大家有幫助。

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 轉(zhuǎn)換器
    +關(guān)注

    關(guān)注

    27

    文章

    8602

    瀏覽量

    146716
  • 框架
    +關(guān)注

    關(guān)注

    0

    文章

    398

    瀏覽量

    17405
  • spring
    +關(guān)注

    關(guān)注

    0

    文章

    338

    瀏覽量

    14296
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    什么是java spring

    的事情。然而,Spring的用途不僅限于服務(wù)器端的開(kāi)發(fā)。從簡(jiǎn)單性、可測(cè)試性和松耦合的角度而言,任何Java應(yīng)用都可以從Spring受益。Spring是一
    發(fā)表于 09-11 11:16

    Spring工作原理

    Spring所提供的這些服務(wù)和功能。Spring里用的最經(jīng)典的一個(gè)設(shè)計(jì)模式就是:模板方法模式。(這里我都不介紹了,是一個(gè)常用的設(shè)計(jì)模式)
    發(fā)表于 07-10 07:41

    啟動(dòng)Spring Boot項(xiàng)目應(yīng)用的三種方法

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

    STM32時(shí)鐘系統(tǒng)最常用的知識(shí)

    ,講一點(diǎn)最常用的知識(shí)。其它的型號(hào)大同小異。時(shí)鐘含義特點(diǎn)HSE外部高速時(shí)鐘信號(hào)一般選擇外接晶振,最常用的時(shí)鐘信號(hào)。電機(jī)驅(qū)動(dòng)板外接12MhzHSI內(nèi)部高速時(shí)鐘信號(hào)由單片...
    發(fā)表于 08-11 07:39

    高手最常用的電腦五個(gè)組合鍵

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

    Spring認(rèn)證_什么是Spring GraphQL?

    數(shù)據(jù)整合 Spring GraphQL 支持使用 Querydsl 通過(guò) Spring Data Querydsl 擴(kuò)展 來(lái)獲取數(shù)據(jù)。Querydsl 提供了一種靈活但類型安全的方法,通過(guò)使用注釋
    的頭像 發(fā)表于 08-09 11:31 ?577次閱讀
    <b class='flag-5'>Spring</b>認(rèn)證_什么是<b class='flag-5'>Spring</b> GraphQL?

    最常用11款Kubernetes工具

    助于改善 Kubernetes 開(kāi)發(fā)人員的體驗(yàn)。本文列出作者自己最常用11 款 Kubernetes 工具,并對(duì)它們進(jìn)行了分類介紹。 Kubernetes 是一個(gè)非常強(qiáng)大的容器編排平臺(tái)。但在
    的頭像 發(fā)表于 08-23 10:43 ?2134次閱讀

    10個(gè)電源設(shè)計(jì)最常用公式的解析

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

    Spring最常用11個(gè)擴(kuò)展點(diǎn)

    除此之外,我們?cè)谑褂?b class='flag-5'>spring的過(guò)程,有沒(méi)有發(fā)現(xiàn)它的擴(kuò)展能力非常強(qiáng)。由于這個(gè)優(yōu)勢(shì)的存在,讓spring擁有強(qiáng)大的包容能力,讓很多第三方應(yīng)用能夠輕松投入
    的頭像 發(fā)表于 01-11 10:31 ?844次閱讀

    剖析Spring最常用擴(kuò)展點(diǎn)(上)

    我們一說(shuō)到spring,可能第一個(gè)想到的是 `IOC`(控制反轉(zhuǎn)) 和 `AOP`(面向切面編程)。 沒(méi)錯(cuò),它們是spring的基石,得益于它們的優(yōu)秀設(shè)計(jì),使得spring能夠從
    的頭像 發(fā)表于 02-15 16:06 ?713次閱讀
    剖析<b class='flag-5'>Spring</b>中<b class='flag-5'>最常用</b>的<b class='flag-5'>擴(kuò)展</b><b class='flag-5'>點(diǎn)</b>(上)

    剖析Spring最常用擴(kuò)展點(diǎn)

    我們一說(shuō)到spring,可能第一個(gè)想到的是 `IOC`(控制反轉(zhuǎn)) 和 `AOP`(面向切面編程)。 沒(méi)錯(cuò),它們是spring的基石,得益于它們的優(yōu)秀設(shè)計(jì),使得spring能夠從
    的頭像 發(fā)表于 02-15 16:06 ?476次閱讀
    剖析<b class='flag-5'>Spring</b>中<b class='flag-5'>最常用</b>的<b class='flag-5'>擴(kuò)展</b><b class='flag-5'>點(diǎn)</b>(<b class='flag-5'>中</b>)

    剖析Spring最常用擴(kuò)展點(diǎn)(下)

    我們一說(shuō)到spring,可能第一個(gè)想到的是 `IOC`(控制反轉(zhuǎn)) 和 `AOP`(面向切面編程)。 沒(méi)錯(cuò),它們是spring的基石,得益于它們的優(yōu)秀設(shè)計(jì),使得spring能夠從
    的頭像 發(fā)表于 02-15 16:07 ?428次閱讀

    基于spring的SPI擴(kuò)展機(jī)制是如何實(shí)現(xiàn)的?

    基本上,你一說(shuō)是基于 spring 的 SPI 擴(kuò)展機(jī)制,再把spring.factories文件和EnableAutoConfiguration提一下,那么這個(gè)問(wèn)題就答的八九不離十了。
    的頭像 發(fā)表于 03-07 09:17 ?989次閱讀

    Spring11個(gè)最常用擴(kuò)展點(diǎn)分享1

    在使用spring的過(guò)程,我們有沒(méi)有發(fā)現(xiàn)它的擴(kuò)展能力很強(qiáng)呢?由于這個(gè)優(yōu)勢(shì)的存在,使得spring具有很強(qiáng)的包容性,所以很多第三方應(yīng)用或者框架可以很容易的投入到
    的頭像 發(fā)表于 05-11 10:48 ?526次閱讀

    Verilog最常用2種數(shù)據(jù)類型

    Verilog 最常用2 種數(shù)據(jù)類型就是線網(wǎng)(wire)與寄存器(reg),其余類型可以理解為這兩種數(shù)據(jù)類型的擴(kuò)展或輔助。
    的頭像 發(fā)表于 05-29 16:27 ?2136次閱讀
    Verilog<b class='flag-5'>最常用</b>的<b class='flag-5'>2</b>種數(shù)據(jù)類型