新聞中心
1. Aware 接口
當(dāng)然這只是一個(gè)理論,在實(shí)際開發(fā)中,我們往往要用到 Spring 容器為我們提供的諸多資源,例如想要獲取到容器中的配置、獲取到容器中的 Bean 等等。在這種情況下,就需要 Spring 容器中的 Bean 真正的意識到 Spring 容器的存在,才能要到這些東西,那么如何讓一個(gè) Bean 意識到 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.
*
*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)該接口的對象可以獲取事件發(fā)布的能力。
- ServletContextAware:實(shí)現(xiàn)該接口的對象可以獲取到 ServletContext 對象。
- MessageSourceAware:實(shí)現(xiàn)該接口的對象可以獲取到 MessageSource 對象,MessageSource 支持多消息源,主要用于主要用于國際化。
- ResourceLoaderAware:實(shí)現(xiàn)該接口的對象可以獲取到一個(gè) ResourceLoader,Spring ResourceLoader 則為我們提供了一個(gè)統(tǒng)一的 getResource() 方法來通過資源路徑檢索外部資源,例如文本文件、XML 文件、屬性文件或圖像文件等。
- ApplicationStartupAware:實(shí)現(xiàn)該接口的對象可以獲取到一個(gè) ApplicationStartup 對象,這個(gè)比較新,是 Spring 5.3 中新推出的,通過 ApplicationStartup 可以標(biāo)記應(yīng)用程序啟動期間的步驟,并收集有關(guān)執(zhí)行上下文或其處理時(shí)間的數(shù)據(jù)。
- NotificationPublisherAware:實(shí)現(xiàn)該接的對象可以獲取到一個(gè) NotificationPublisher 對象,通過該對象可以實(shí)現(xiàn)通知的發(fā)送。
- EnvironmentAware:實(shí)現(xiàn)該接口的對象可以獲取到一個(gè) Environment 對象,通過 Environment 可以獲取到容器的環(huán)境信息。
- BeanFactoryAware:實(shí)現(xiàn)該接口的對象可以獲取到一個(gè) BeanFactory 對象,通過 BeanFactory 可以完成 Bean 的查詢等操作。
- ImportAware:實(shí)現(xiàn)該接口的對象可以獲取到一個(gè) AnnotationMetadata 對象,ImportAware 接口是需要和 @Import 注解一起使用的。在 @Import 作為元注解使用時(shí),通過 @Import 導(dǎo)入的配置類如果實(shí)現(xiàn)了 ImportAware 接口就可以獲取到導(dǎo)入該配置類接口的數(shù)據(jù)配置。
- EmbeddedValueResolverAware:實(shí)現(xiàn)該接口的對象可以獲取到一個(gè) StringValueResolver 對象,通過 StringValueResolver 對象,可以讀取到 Spring 容器中的 properties 配置的值(YAML 配置也可以)。
- ServletConfigAware:實(shí)現(xiàn)該接口的對象可以獲取到一個(gè) ServletConfig 對象,不過這個(gè)似乎沒什么用,我們很少自己去配置 ServletConfig。
- LoadTimeWeaverAware:實(shí)現(xiàn)該接口的對象可以獲取到一個(gè) LoadTimeWeaver 對象,通過該對象可以獲取加載 Spring Bean 時(shí)織入的第三方模塊,如 AspectJ 等。
- BeanClassLoaderAware:實(shí)現(xiàn)該接口的對象可以獲取到一個(gè) ClassLoader 對象,ClassLoader 能干嘛不需要我多說了吧。
- BeanNameAware:實(shí)現(xiàn)該接口的對象可以獲取到一個(gè)當(dāng)前 Bean 的名稱。
- ApplicationContextAware:實(shí)現(xiàn)該接口的對象可以獲取到一個(gè) ApplicationContext 對象,通過 ApplicationContext 可以獲取容器中的 Bean、環(huán)境等信息。
這是 Spring 中提供的一堆 Aware。
接下來松哥隨便寫個(gè)例子大家來看下 Aware 的用法。
2. BeanFactoryAware
實(shí)現(xiàn)該接口的對象可以獲取到一個(gè) BeanFactory 對象,通過 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 staticT 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í)踐
為什么會有今天這篇文章呢?主要是在松哥最近做的 TienChin 項(xiàng)目中,有一個(gè)地方涉及到這塊知識點(diǎn)了,但是有的小伙伴不熟悉,因此就拎出來和大家梳理下。
在 TienChin 項(xiàng)目中,在記錄日志的時(shí)候,因?yàn)槿罩臼且粋€(gè)延遲任務(wù),所以提前準(zhǔn)備好了相關(guān)的 Bean 已經(jīng)注冊到 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;
}
/**
* 獲取對象
*
* @param name
* @return Object 一個(gè)以所給名字注冊的bean的實(shí)例
* @throws org.springframework.beans.BeansException
*/
@SuppressWarnings("unchecked")
public staticT getBean(String name) throws BeansException {
return (T) beanFactory.getBean(name);
}
/**
* 獲取類型為requiredType的對象
*
* @param clz
* @return
* @throws org.springframework.beans.BeansException
*/
public staticT getBean(Class 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 了。
網(wǎng)頁題目:工具類如何獲取到Spring容器中的Bean?
文章路徑:http://www.dlmjj.cn/article/djddish.html


咨詢
建站咨詢
