Spring通過工具類實(shí)現(xiàn)獲取容器中的Bean
1. Aware 接口
小伙伴們知道,Spring 容器最大的特點(diǎn)在于所有的 Bean 對(duì)于 Spring 容器的存在是沒有意識(shí)的,因此我們常說理論上你可以無縫將 Spring 容器切換為其他容器(然而在現(xiàn)實(shí)世界中,我們其實(shí)沒有這樣的選擇,除了 Spring 容器,難道還有更好用的?)。
當(dāng)然這只是一個(gè)理論,在實(shí)際開發(fā)中,我們往往要用到 Spring 容器為我們提供的諸多資源,例如想要獲取到容器中的配置、獲取到容器中的 Bean 等等。在這種情況下,就需要 Spring 容器中的 Bean 真正的意識(shí)到 Spring 容器的存在,才能要到這些東西,那么如何讓一個(gè) Bean 意識(shí)到 Spring 容器的存在呢?
這就依賴于 Spring 容器給我們提供的各種 Aware 接口了。
/**
?*?A?marker?superinterface?indicating?that?a?bean?is?eligible?to?be?notified?by?the
?*?Spring?container?of?a?particular?framework?object?through?a?callback-style?method.
?*?The?actual?method?signature?is?determined?by?individual?subinterfaces?but?should
?*?typically?consist?of?just?one?void-returning?method?that?accepts?a?single?argument.
?*
?*?<p>Note?that?merely?implementing?{@link?Aware}?provides?no?default?functionality.
?*?Rather,?processing?must?be?done?explicitly,?for?example?in?a
?*?{@link?org.springframework.beans.factory.config.BeanPostProcessor}.
?*?Refer?to?{@link?org.springframework.context.support.ApplicationContextAwareProcessor}
?*?for?an?example?of?processing?specific?{@code?*Aware}?interface?callbacks.
?*
?*?@author?Chris?Beams
?*?@author?Juergen?Hoeller
?*?@since?3.1
?*/
public?interface?Aware?{
}
從這個(gè)接口的注釋中,我們也能大概看出來,這個(gè)接口的子類,主要是提供了一些只有一個(gè)參數(shù)的 set 方法,通過這些方法可以讓 Spring 容器感知到某一件事情。
Aware 的實(shí)現(xiàn)有很多,大的方向來說主要有如下一些:

每一個(gè) Aware 的作用如下:
- ApplicationEventPublisherAware:實(shí)現(xiàn)該接口的對(duì)象可以獲取事件發(fā)布的能力。
- ServletContextAware:實(shí)現(xiàn)該接口的對(duì)象可以獲取到 ServletContext 對(duì)象。
- MessageSourceAware:實(shí)現(xiàn)該接口的對(duì)象可以獲取到 MessageSource 對(duì)象,MessageSource 支持多消息源,主要用于主要用于國際化。
- ResourceLoaderAware:實(shí)現(xiàn)該接口的對(duì)象可以獲取到一個(gè) ResourceLoader,Spring ResourceLoader 則為我們提供了一個(gè)統(tǒng)一的 getResource() 方法來通過資源路徑檢索外部資源,例如文本文件、XML 文件、屬性文件或圖像文件等。
- ApplicationStartupAware:實(shí)現(xiàn)該接口的對(duì)象可以獲取到一個(gè) ApplicationStartup 對(duì)象,這個(gè)比較新,是 Spring 5.3 中新推出的,通過 ApplicationStartup 可以標(biāo)記應(yīng)用程序啟動(dòng)期間的步驟,并收集有關(guān)執(zhí)行上下文或其處理時(shí)間的數(shù)據(jù)。
- NotificationPublisherAware:實(shí)現(xiàn)該接的對(duì)象可以獲取到一個(gè) NotificationPublisher 對(duì)象,通過該對(duì)象可以實(shí)現(xiàn)通知的發(fā)送。
- EnvironmentAware:實(shí)現(xiàn)該接口的對(duì)象可以獲取到一個(gè) Environment 對(duì)象,通過 Environment 可以獲取到容器的環(huán)境信息。
- BeanFactoryAware:實(shí)現(xiàn)該接口的對(duì)象可以獲取到一個(gè) BeanFactory 對(duì)象,通過 BeanFactory 可以完成 Bean 的查詢等操作。
- ImportAware:實(shí)現(xiàn)該接口的對(duì)象可以獲取到一個(gè) AnnotationMetadata 對(duì)象,ImportAware 接口是需要和 @Import 注解一起使用的。在 @Import 作為元注解使用時(shí),通過 @Import 導(dǎo)入的配置類如果實(shí)現(xiàn)了 ImportAware 接口就可以獲取到導(dǎo)入該配置類接口的數(shù)據(jù)配置。
- EmbeddedValueResolverAware:實(shí)現(xiàn)該接口的對(duì)象可以獲取到一個(gè) StringValueResolver 對(duì)象,通過 StringValueResolver 對(duì)象,可以讀取到 Spring 容器中的 properties 配置的值(YAML 配置也可以)。
- ServletConfigAware:實(shí)現(xiàn)該接口的對(duì)象可以獲取到一個(gè) ServletConfig 對(duì)象,不過這個(gè)似乎沒什么用,我們很少自己去配置 ServletConfig。
- LoadTimeWeaverAware:實(shí)現(xiàn)該接口的對(duì)象可以獲取到一個(gè) LoadTimeWeaver 對(duì)象,通過該對(duì)象可以獲取加載 Spring Bean 時(shí)織入的第三方模塊,如 AspectJ 等。
- BeanClassLoaderAware:實(shí)現(xiàn)該接口的對(duì)象可以獲取到一個(gè) ClassLoader 對(duì)象,ClassLoader 能干嘛不需要我多說了吧。
- BeanNameAware:實(shí)現(xiàn)該接口的對(duì)象可以獲取到一個(gè)當(dāng)前 Bean 的名稱。
- ApplicationContextAware:實(shí)現(xiàn)該接口的對(duì)象可以獲取到一個(gè) ApplicationContext 對(duì)象,通過 ApplicationContext 可以獲取容器中的 Bean、環(huán)境等信息。
這是 Spring 中提供的一堆 Aware。
接下來松哥隨便寫個(gè)例子大家來看下 Aware 的用法。
2. BeanFactoryAware
實(shí)現(xiàn)該接口的對(duì)象可以獲取到一個(gè) BeanFactory 對(duì)象,通過 BeanFactory 可以完成 Bean 的查詢等操作。這算是一個(gè)比較常見的 Aware 了,我們一起來看下。
這里為了省事,我就在 Spring Boot 中來和大家演示。
首先我們來定義一個(gè)簡單的 UserService:
@Service
public?class?UserService?{
????public?void?hello()?{
????????System.out.println("hello?javaboy!");
????}
}
然后提供一個(gè)工具類:
@Component
public?class?BeanUtils?implements?BeanFactoryAware?{
????private?static?BeanFactory?beanFactory?=?null;
????@Override
????public?void?setBeanFactory(BeanFactory?beanFactory)?throws?BeansException?{
????????BeanUtils.beanFactory?=?beanFactory;
????}
????public?static?<T>?T?getBean(String?beanName)?{
????????return?(T)?beanFactory.getBean(beanName);
????}
}
有了這個(gè)工具類,接下來我們就可以在一個(gè)非 Spring 管理的 Bean 中,隨時(shí)隨地的查詢 Bean 了,像下面這樣:
UserService?userService?=?BeanUtils.getBean("userService");
userService.hello();
3. TienChin 項(xiàng)目實(shí)踐
為什么會(huì)有今天這篇文章呢?主要是在松哥最近做的 TienChin 項(xiàng)目中,有一個(gè)地方涉及到這塊知識(shí)點(diǎn)了,但是有的小伙伴不熟悉,因此就拎出來和大家梳理下。
在 TienChin 項(xiàng)目中,在記錄日志的時(shí)候,因?yàn)槿罩臼且粋€(gè)延遲任務(wù),所以提前準(zhǔn)備好了相關(guān)的 Bean 已經(jīng)注冊(cè)到 Spring 容器中了,像下面這樣:
@Configuration
public?class?ThreadPoolConfig?{
????/**
?????*?執(zhí)行周期性或定時(shí)任務(wù)
?????*/
????@Bean(name?=?"scheduledExecutorService")
????protected?ScheduledExecutorService?scheduledExecutorService()?{
????????return?new?ScheduledThreadPoolExecutor(corePoolSize,
????????????????new?BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(),
????????????????new?ThreadPoolExecutor.CallerRunsPolicy())?{
????????????@Override
????????????protected?void?afterExecute(Runnable?r,?Throwable?t)?{
????????????????super.afterExecute(r,?t);
????????????????Threads.printException(r,?t);
????????????}
????????};
????}
}
@Component
public?final?class?SpringUtils?implements?BeanFactoryPostProcessor,?ApplicationContextAware?{
????/**
?????*?Spring應(yīng)用上下文環(huán)境
?????*/
????private?static?ConfigurableListableBeanFactory?beanFactory;
????private?static?ApplicationContext?applicationContext;
????@Override
????public?void?postProcessBeanFactory(ConfigurableListableBeanFactory?beanFactory)?throws?BeansException?{
????????SpringUtils.beanFactory?=?beanFactory;
????}
????@Override
????public?void?setApplicationContext(ApplicationContext?applicationContext)?throws?BeansException?{
????????SpringUtils.applicationContext?=?applicationContext;
????}
????/**
?????*?獲取對(duì)象
?????*
?????*?@param?name
?????*?@return?Object?一個(gè)以所給名字注冊(cè)的bean的實(shí)例
?????*?@throws?org.springframework.beans.BeansException
?????*/
????@SuppressWarnings("unchecked")
????public?static?<T>?T?getBean(String?name)?throws?BeansException?{
????????return?(T)?beanFactory.getBean(name);
????}
????/**
?????*?獲取類型為requiredType的對(duì)象
?????*
?????*?@param?clz
?????*?@return
?????*?@throws?org.springframework.beans.BeansException
?????*/
????public?static?<T>?T?getBean(Class<T>?clz)?throws?BeansException?{
????????T?result?=?(T)?beanFactory.getBean(clz);
????????return?result;
????}
}
而寫日志的異步任務(wù)工具類,并非一個(gè)容器,所以要通過這個(gè)工具類獲取相應(yīng)的 Bean,如下:
public?class?AsyncManager?{
????/**
?????*?操作延遲10毫秒
?????*/
????private?final?int?OPERATE_DELAY_TIME?=?10;
????/**
?????*?異步操作任務(wù)調(diào)度線程池
?????*/
????private?ScheduledExecutorService?executor?=?SpringUtils.getBean("scheduledExecutorService");
????/**
?????*?單例模式
?????*/
????private?AsyncManager()?{
????}
????private?static?AsyncManager?me?=?new?AsyncManager();
????public?static?AsyncManager?me()?{
????????return?me;
????}
????/**
?????*?執(zhí)行任務(wù)
?????*
?????*?@param?task?任務(wù)
?????*/
????public?void?execute(TimerTask?task)?{
????????executor.schedule(task,?OPERATE_DELAY_TIME,?TimeUnit.MILLISECONDS);
????}
}
有了 SpringUtils 我們就可以在一個(gè)非 Spring 容器所管理的 Bean 中,獲取到 Spring 容器中的 Bean 了。
到此這篇關(guān)于Spring通過工具類實(shí)現(xiàn)獲取容器中的Bean的文章就介紹到這了,更多相關(guān)Spring獲取Bean內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java內(nèi)存劃分:運(yùn)行時(shí)數(shù)據(jù)區(qū)域
聽說Java運(yùn)行時(shí)環(huán)境的內(nèi)存劃分是挺進(jìn)BAT的必經(jīng)之路,這篇文章主要給大家介紹了關(guān)于Java運(yùn)行時(shí)數(shù)據(jù)區(qū)域(內(nèi)存劃分)的相關(guān)資料,需要的朋友可以參考下2021-07-07
詳解java調(diào)用存儲(chǔ)過程并封裝成map
這篇文章主要介紹了詳解java調(diào)用存儲(chǔ)過程并封裝成map的相關(guān)資料,希望通過本文能幫助到大家實(shí)現(xiàn)這樣的功能,需要的朋友可以參考下2017-09-09
Java使用 try-with-resources 實(shí)現(xiàn)自動(dòng)關(guān)閉資源的方法
這篇文章主要介紹了Java使用 try-with-resources 實(shí)現(xiàn)自動(dòng)關(guān)閉資源的方法,本文通過示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06
java實(shí)現(xiàn)文件上傳下載和圖片壓縮代碼示例
本文給大家介紹的是項(xiàng)目中經(jīng)常需要用到的一個(gè)常用的功能,使用java實(shí)現(xiàn)文件的上傳下載和圖片的壓縮功能,這里推薦給大家,有需要的小伙伴參考下。2015-03-03

