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

Spring鉤子接口匯總分析使用示例

 更新時(shí)間:2023年01月10日 14:41:53   作者:趙韓兵先生  
Spring提供了非常多的擴(kuò)展接口,官方將這些接口稱之為鉤子,這些鉤子會在特定的時(shí)間被回調(diào),以此來增強(qiáng)Spring功能,眾多優(yōu)秀的框架也是通過擴(kuò)展這些接口,來實(shí)現(xiàn)自身特定的功能,如SpringBoot、mybatis等

1、Aware 系列接口

Aware 系列接口是用來獲取 Spring 內(nèi)部對象的接口。Aware 自身是一個(gè)頂級接口,它有一系列子接口,在一個(gè) Bean 中實(shí)現(xiàn)這些子接口并重寫里面的 set 方法后,Spring 容器啟動時(shí),就會回調(diào)該 set 方法,而相應(yīng)的對象會通過方法參數(shù)傳遞進(jìn)去。我們以其中的 ApplicationContextAware 接口為例。

ApplicationContextAware

大部分 Aware 系列接口都有一個(gè)規(guī)律,它們以對象名稱為前綴,獲取的就是該對象,所以 ApplicationContextAware 獲取的對象是 ApplicationContext 。

public interface ApplicationContextAware extends Aware {
	void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}

ApplicationContextAware 繼承了 Aware 接口,并定義一個(gè) set 方法,參數(shù)就是 ApplicationContext 對象,當(dāng)然,其它系列的 Aware 接口也是類似的定義。其具體使用方式如下:

public class Test implements ApplicationContextAware {
    private ApplicationContext applicationContext;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

在 Spring 啟動過程中,會回調(diào) setApplicationContext 方法,并傳入 ApplicationContext 對象,之后就可對該對象進(jìn)行操作。其它系列的 Aware 接口也是如此使用。具體的調(diào)用時(shí)機(jī)會在后面詳細(xì)介紹。

以下是幾種常用的 Aware 接口:

  • BeanFactoryAware:獲取 BeanFactory 對象,它是基礎(chǔ)的容器接口。
  • BeanNameAware:獲取 Bean 的名稱。
  • EnvironmentAware:獲取 Environment 對象,它表示整個(gè)的運(yùn)行時(shí)環(huán)境,可以設(shè)置和獲取配置屬性。
  • ApplicationEventPublisherAware:獲取 ApplicationEventPublisher 對象,它是用來發(fā)布事件的。
  • ResourceLoaderAware:獲取 ResourceLoader 對象,它是獲取資源的工具。

2、InitializingBean

InitializingBean 是一個(gè)可以在 Bean 的生命周期執(zhí)行自定義操作的接口,凡是實(shí)現(xiàn)該接口的 Bean,在初始化階段都可以執(zhí)行自定義的操作。

public interface InitializingBean {
	void afterPropertiesSet() throws Exception;
}

從 InitializingBean 源碼中可以看出它有一個(gè) afterPropertiesSet 方法,當(dāng)一個(gè) Bean 實(shí)現(xiàn)該接口時(shí),在 Bean 的初始化階段,會回調(diào) afterPropertiesSet 方法,其初始化階段具體指 Bean 設(shè)置完屬性之后。

該接口使用方式如下:

@Component
public class Test implements InitializingBean {
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("Test 執(zhí)行初始化");
    }
}

定義啟動類: 

@SpringBootApplication
public class Main {
    public static void main(String[] args) {
        SpringApplication.run(Main.class, args);
    }
}

結(jié)果:

...
2020-02-24 08:43:41.435  INFO 26193 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'httpTraceFilter' to: [/*]
2020-02-24 08:43:41.435  INFO 26193 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'webMvcMetricsFilter' to: [/*]
Test 執(zhí)行初始化
2020-02-24 08:43:41.577  INFO 26193 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2020-02-24 08:43:41.756  INFO 26193 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@23529fee: startup date [Mon Feb 24 08:43:39 CST 2020]; root of context hierarchy
...

最終,afterPropertiesSet 方法被執(zhí)行并打印輸出語句。

3、BeanPostProcessor

BeanPostProcessor 和 InitializingBean 有點(diǎn)類似,也是可以在 Bean 的生命周期執(zhí)行自定義操作,一般稱之為 Bean 的后置處理器,不同的是,BeanPostProcessor 可以在 Bean 初始化前、后執(zhí)行自定義操作,且針對的目標(biāo)也不同,InitializingBean 針對的是實(shí)現(xiàn) InitializingBean 接口的 Bean,而 BeanPostProcessor 針對的是所有的 Bean。

public interface BeanPostProcessor {
	// Bean 初始化前調(diào)用
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
	// Bean 初始化后調(diào)用
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
}

所有的 Bean 在初始化前、后都會回調(diào)接口中的 postProcessBeforeInitialization 和 postProcessAfterInitialization 方法,入?yún)⑹钱?dāng)前正在初始化的 Bean 對象和 BeanName。值得注意的是 Spring 內(nèi)置了非常多的 BeanPostProcessor ,以此來完善自身功能,這部分會在后面文章深入討論。

這里通過自定義 BeanPostProcessor 來了解該接口的使用方式:

// 一般自定義的 BeanPostProcessor 命名格式都是以 BeanPostProcessor 為后綴。
@Component
public class TestBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(beanName + " 初始化前執(zhí)行操作");
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(beanName + " 初始化后執(zhí)行操作");
        return bean;
    }
}

啟動類:

@SpringBootApplication
public class Main {
    public static void main(String[] args) {
        SpringApplication.run(Main.class);
    }
}

結(jié)果:

...
2020-02-24 23:37:08.949  INFO 26615 --- [           main] com.loong.diveinspringboot.test.Main     : No active profile set, falling back to default profiles: default
2020-02-24 23:37:08.994  INFO 26615 --- [           main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@2133814f: startup date [Mon Feb 24 23:37:08 CST 2020]; root of context hierarchy
2020-02-24 23:37:09.890  INFO 26615 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode!
org.springframework.context.event.internalEventListenerProcessor 初始化前執(zhí)行操作
org.springframework.context.event.internalEventListenerProcessor 初始化后執(zhí)行操作
org.springframework.context.event.internalEventListenerFactory 初始化前執(zhí)行操作
org.springframework.context.event.internalEventListenerFactory 初始化后執(zhí)行操作
main 初始化前執(zhí)行操作
main 初始化后執(zhí)行操作
test 初始化前執(zhí)行操作
Test 執(zhí)行初始化
test 初始化后執(zhí)行操作
...
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration初始化前執(zhí)行操作
2020-02-24 23:37:13.097  INFO 26615 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2020-02-24 23:37:13.195  INFO 26615 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2020-02-24 23:37:13.207  INFO 26615 --- [           main] com.loong.diveinspringboot.test.Main     : Started Main in 4.657 seconds (JVM running for 5.078)
...

可以看到,輸出的結(jié)果中不僅包括自定義的 Test,還包括 Spring 內(nèi)部的 Bean 。

BeanPostProcessor 使用場景其實(shí)非常多,因?yàn)樗梢垣@取正在初始化的 Bean 對象,然后可以依據(jù)該 Bean 對象做一些定制化的操作,如:判斷該 Bean 是否為某個(gè)特定對象、獲取 Bean 的注解元數(shù)據(jù)等。事實(shí)上,Spring 內(nèi)部也正是這樣使用的,這部分也會在后面章節(jié)詳細(xì)討論。

4、BeanFactoryPostProcessor

BeanFactoryPostProcessor 是 Bean 工廠的后置處理器,一般用來修改上下文中的 BeanDefinition,修改 Bean 的屬性值。

public interface BeanFactoryPostProcessor {
    // 入?yún)⑹且粋€(gè) Bean 工廠:ConfigurableListableBeanFactory。該方法執(zhí)行時(shí),所有 BeanDefinition 都已被加載,但還未實(shí)例化 Bean。
    // 可以對其進(jìn)行覆蓋或添加屬性,甚至可以用于初始化 Bean。
	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

BeanFactoryPostProcessor 提供了一個(gè) postProcessBeanFactory 方法,當(dāng)所有的 BeanDefinition 被加載時(shí),該方法會被回調(diào)。值得注意的是,Spring 內(nèi)置了許多 BeanFactoryPostProcessor 的實(shí)現(xiàn),以此來完善自身功能。

這里,我們來實(shí)現(xiàn)一個(gè)自定義的 BeanFactoryPostProcessor:

@Component
public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        String beanNames[] = beanFactory.getBeanDefinitionNames();
        for (String beanName : beanNames) {
            BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
            System.out.println(beanDefinition);
        }
    }
}

主要是通過 Bean 工廠獲取所有的 BeanDefinition 。

接著啟動程序:

@SpringBootApplication
public class Main {
    public static void main(String[] args) {
        SpringApplication.run(Main.class);
    }
}

結(jié)果:

2020-02-25 21:46:00.754  INFO 28907 --- [           main] ConfigServletWebServerApplicationContext : ...
2020-02-25 21:46:01.815  INFO 28907 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : ...
Root bean: class [org.springframework.context.annotation.ConfigurationClassPostProcessor]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
Root bean: class [org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
...
2020-02-25 21:46:04.926  INFO 28907 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : ...
2020-02-25 21:46:04.989  INFO 28907 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : ...
2020-02-25 21:46:04.993  INFO 28907 --- [           main] com.loong.diveinspringboot.test.Main     : ...

可以看到,BeanDefinition 正確輸出,里面是一些 Bean 的相關(guān)定義,如:是否懶加載、Bean 的 Class 以及 Bean 的屬性等。

5、FactoryBean

FactoryBean 也是一種 Bean,不同于普通的 Bean,它是用來創(chuàng)建 Bean 實(shí)例的,屬于工廠 Bean,不過它和普通的創(chuàng)建不同,它提供了更為靈活的方式,其實(shí)現(xiàn)有點(diǎn)類似于設(shè)計(jì)模式中的工廠模式和修飾器模式。

Spring 框架內(nèi)置了許多 FactoryBean 的實(shí)現(xiàn),它們在很多應(yīng)用如(Spring的AOP、ORM、事務(wù)管理)及與其它第三框架(ehCache)集成時(shí)都有體現(xiàn)。

public interface FactoryBean<T> {
	// 該方法會返回該 FactoryBean “生產(chǎn)”的對象實(shí)例,我們需要實(shí)現(xiàn)該方法以給出自己的對象實(shí)例化邏輯
	T getObject() throws Exception;
	// Bean的類型
	Class<?> getObjectType();
	// 是否是單例
	default boolean isSingleton() {
		return true;
	}
}

自定義 FactoryBean:

@Component
public class TestFactoryBean implements FactoryBean<Test> {
    @Override
    public Test getObject() throws Exception {
        // 這里可以靈活的創(chuàng)建 Bean,如:代理、修飾
        return new Test();
    }
    @Override
    public Class<?> getObjectType() {
        return null;
    }
}

Test 類:

public class Test {
    public void hello() {
        System.out.println("Test -- hello");
    }
}

啟動類:

@SpringBootApplication
public class Main {
    public static void main(String[] args) {
        SpringApplication springApplication = new SpringApplication();
        ConfigurableApplicationContext run = springApplication.run(Main.class);
        Test bean = (Test) run.getBean("testFactoryBean");
        bean.hello();
    }
}

輸出:

2020-02-27 23:16:00.334  INFO 32234 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2020-02-27 23:16:00.338  INFO 32234 --- [           main] com.loong.diveinspringboot.test.Main     : Started Main in 3.782 seconds (JVM running for 4.187)
Test -- hello

可以看到,啟動類中 getBean 的參數(shù)是 testFactoryBean ,從這可以看出,當(dāng)容器中的 Bean 實(shí)現(xiàn)了 FactoryBean 后,通過 getBean(String BeanName) 獲取到的 Bean 對象并不是 FactoryBean 的實(shí)現(xiàn)類對象,而是這個(gè)實(shí)現(xiàn)類中的 getObject() 方法返回的對象。如果想獲取 FactoryBean 的實(shí)現(xiàn)類,需通過這種方式:getBean(&BeanName),在 BeanName 之前加上&。

6、ApplicationListener

ApplicationListener 是 Spring 實(shí)現(xiàn)事件機(jī)制的核心接口,屬于觀察者設(shè)計(jì)模式,一般配合 ApplicationEvent 使用。在 Spring 容器啟動過程中,會在相應(yīng)的階段通過 ApplicationContext 發(fā)布 ApplicationEvent 事件,之后所有的 ApplicationListener 會被回調(diào),根據(jù)事件類型,執(zhí)行不同的操作。

public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
	void onApplicationEvent(E event);
}

在 onApplicationEvent 方法中,通過 instanceof 判斷 event 的事件類型。

自定義 ApplicationListener:

@Component
public class TestApplicationListener implements ApplicationListener {
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof TestApplicationEvent) {
            TestApplicationEvent testApplicationEvent = (TestApplicationEvent) event;
            System.out.println(testApplicationEvent.getName());
        }
    }
}

當(dāng)自定義的 TestApplicationListener 被回調(diào)時(shí),判斷當(dāng)前發(fā)布的事件類型是否是自定義的 TestApplicationEvent,如果是則輸出事件名稱。

自定義 TestApplicationEvent:

public class TestApplicationEvent extends ApplicationEvent {
    private String name;
    public TestApplicationEvent(Object source, String name) {
        super(source);
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

啟動類:

@SpringBootApplication
public class Main {
    public static void main(String[] args) {
        SpringApplication springApplication = new SpringApplication();
        ConfigurableApplicationContext run = springApplication.run(Main.class);
        run.publishEvent(new TestApplicationEvent(new Main(),"Test 事件"));
    }
}

通過 ApplicationContext 發(fā)布 TestApplicationEvent 事件。當(dāng)然也可以在業(yè)務(wù)代碼中通過 ApplicationContextAware 獲取 ApplicationContext 發(fā)布事件。

結(jié)果:

2020-02-27 08:37:10.972  INFO 30984 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2020-02-27 08:37:11.026  INFO 30984 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2020-02-27 08:37:11.029  INFO 30984 --- [           main] com.loong.diveinspringboot.test.Main     : Started Main in 3.922 seconds (JVM running for 4.367)
Test 事件

ApplicationListener 也被 SpringBoot 進(jìn)行擴(kuò)展,來實(shí)現(xiàn)自身特定的事件機(jī)制。這部分也在前面的文章討論過,感興趣的同學(xué)可自行翻閱。

到此這篇關(guān)于Spring鉤子接口匯總分析使用示例的文章就介紹到這了,更多相關(guān)Spring鉤子接口內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 關(guān)于ReentrantLock的實(shí)現(xiàn)原理解讀

    關(guān)于ReentrantLock的實(shí)現(xiàn)原理解讀

    這篇文章主要介紹了關(guān)于ReentrantLock的實(shí)現(xiàn)原理,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • Java獲取支付寶OpenID的實(shí)現(xiàn)方法

    Java獲取支付寶OpenID的實(shí)現(xiàn)方法

    在Java中,通過支付寶開放平臺API可以獲取用戶的OpenID,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-09-09
  • java父類和子類初始化順序的深入理解

    java父類和子類初始化順序的深入理解

    本篇文章是對java父類和子類初始化順序進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-06-06
  • Java中如何將?int[]?數(shù)組轉(zhuǎn)換為?ArrayList(list)

    Java中如何將?int[]?數(shù)組轉(zhuǎn)換為?ArrayList(list)

    這篇文章主要介紹了Java中將?int[]?數(shù)組?轉(zhuǎn)換為?List(ArrayList),本文通過示例代碼給大家講解的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-12-12
  • JAVA利用接口實(shí)現(xiàn)多繼承問題的代碼實(shí)操演示

    JAVA利用接口實(shí)現(xiàn)多繼承問題的代碼實(shí)操演示

    Java語言并不支持多繼承,這是由于多繼承會帶來許多復(fù)雜的問題,例如"菱形問題"等,下面這篇文章主要給大家介紹了關(guān)于JAVA利用接口實(shí)現(xiàn)多繼承問題的相關(guān)資料,需要的朋友可以參考下
    2024-03-03
  • 詳解SpringBoot配置文件啟動時(shí)動態(tài)配置參數(shù)方法

    詳解SpringBoot配置文件啟動時(shí)動態(tài)配置參數(shù)方法

    這篇文章主要介紹了詳解SpringBoot配置文件啟動時(shí)動態(tài)配置參數(shù)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • Spring?JPA使用CriteriaBuilder動態(tài)構(gòu)造查詢方式

    Spring?JPA使用CriteriaBuilder動態(tài)構(gòu)造查詢方式

    這篇文章主要介紹了Spring?JPA使用CriteriaBuilder動態(tài)構(gòu)造查詢方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • java商城項(xiàng)目實(shí)戰(zhàn)之購物車功能實(shí)現(xiàn)

    java商城項(xiàng)目實(shí)戰(zhàn)之購物車功能實(shí)現(xiàn)

    這篇文章主要為大家詳細(xì)介紹了java商城項(xiàng)目實(shí)戰(zhàn)之購物車功能實(shí)現(xiàn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-04-04
  • java實(shí)現(xiàn)簡易聊天功能

    java實(shí)現(xiàn)簡易聊天功能

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)簡易聊天功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-09-09
  • Java中消息隊(duì)列任務(wù)的平滑關(guān)閉詳解

    Java中消息隊(duì)列任務(wù)的平滑關(guān)閉詳解

    對于消息隊(duì)列的監(jiān)聽,我們一般使用Java寫一個(gè)獨(dú)立的程序,在Linux服務(wù)器上運(yùn)行。程序啟動后,通過消息隊(duì)列客戶端接收消息,放入一個(gè)線程池進(jìn)行異步處理,并發(fā)的快速處理。這篇文章主要給大家介紹了關(guān)于Java中消息隊(duì)列任務(wù)的平滑關(guān)閉的相關(guān)資料,需要的朋友可以參考下。
    2017-11-11

最新評論

聊城市| 孝感市| 和平区| 凤山县| 梧州市| 昂仁县| 玉田县| 平度市| 来宾市| 灵川县| 雷山县| 西和县| 女性| 大洼县| 牙克石市| 永吉县| 西盟| 潞西市| 汨罗市| 昆明市| 白玉县| 汉源县| 广饶县| 观塘区| 永仁县| 沛县| 海原县| 宣汉县| 张家港市| 历史| 郯城县| 通化县| 建始县| 崇明县| 边坝县| 会昌县| 类乌齐县| 大宁县| 铜梁县| 余江县| 玛曲县|