Aware接口
在Spring中有許多的Aware接口,提供給應用開發者使用,通過Aware接口,我們可以通過set的方式拿到我們需要的bean對象(包括容器中提供的一些對象,ApplicationContext等),根據需要可以將其注入到本地對象的屬性中。
先來看一個Spring兩個基礎的接口
- BeanPostProcessor
- BeanFactoryPostProcessor
簡單來講:
BeanPostProcessor增加bean的信息,比如 autowaired 或 aware接口注入bean對象的屬性
BeanFactoryPostProcessor就用於增加BeanDefinition(配置元數據)的信息 比如添加bean的工程,提供一個帶BeanFactory參數的回調接口,說通俗一些就是可以管理我們的bean工廠內所有的beandefinition(未實例化)數據,可以隨心所欲的修改屬性。
這兩個接口,都是通過bean的形式添加到spring IOC容器中,即它們本身也是作為一種bean,而只不過這兩種bean提供一些特殊的用途而已。
有區別是的:BeanPostProcessor是在createBean的時候觸發,BeanFactoryPostProcessor會被提前調用用來修改BeanDefinition。
BeanPostProcessor
bean的后置處理器接口,在依賴注入的初始化方法前后進行調用
public interface BeanPostProcessor {
/**
* 初始化方法調用前要進行的處理邏輯
*/
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
/**
* 在初始化方法指定后要進行的處理邏輯
*/
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
所有Aware接口本身是一種修改bean信息的功能接口,但它自身並不會被觸發,既然是修改bean屬性的功能接口,所以它應該被一個BeanPostProcessor調用———— *AwareProcessor(例如ApplicationContextAwarePostProcessor)
Bean在創建過程,會在實例化后,如果實現了BeanPostProcessor接口,會在實例化后統一調用BeanPostProcessor接口
在我們日常開發中,可以通過在bean中實現ApplicationContextAware的方式將ApplicationContext注入到我們的bean對象中去
在Spring中其實是有一個BeanPostProcessor類——ApplicationContextAwareProcessor,用來處理實現了ApplicationContextAware等接口的bean。
ApplicationContextAware類源碼
public interface ApplicationContextAware extends Aware {
/**
* Set the ApplicationContext that this object runs in.
* Normally this call will be used to initialize the object.
* <p>Invoked after population of normal bean properties but before an init callback such
* as {@link org.springframework.beans.factory.InitializingBean#afterPropertiesSet()}
* or a custom init-method. Invoked after {@link ResourceLoaderAware#setResourceLoader},
* {@link ApplicationEventPublisherAware#setApplicationEventPublisher} and
* {@link MessageSourceAware}, if applicable.
* @param applicationContext the ApplicationContext object to be used by this object
* @throws ApplicationContextException in case of context initialization errors
* @throws BeansException if thrown by application context methods
* @see org.springframework.beans.factory.BeanInitializationException
*/
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
可以看到此aware接口主要是為了在實現類中注入applicationContext,提供這么一個回調方法
ApplicationContextAwareProcessor類源碼
class ApplicationContextAwareProcessor implements BeanPostProcessor {
private final ConfigurableApplicationContext applicationContext;
private final StringValueResolver embeddedValueResolver;
/**
* 將Context注入進來
*/
public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
this.applicationContext = applicationContext;
this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
}
/**
* 接口beanPostProcessor規定的方法,會在bean創建時,實例化后,初始化前,對bean對象應用
*/
@Override
@Nullable
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){
return bean;
}
AccessControlContext acc = null;
if (System.getSecurityManager() != null) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}
if (acc != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
// 檢測bean上是否實現了某個aware接口,有的話進行相關的調用
invokeAwareInterfaces(bean);
return null;
}, acc);
}
else {
invokeAwareInterfaces(bean);
}
return bean;
}
/**
* 如果某個bean實現了某個aware接口,給指定的bean設置相應的屬性值
*
* @param bean
*/
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
}
在ApplicationContextAwareProcessor中我們可以看到,其實它處理了好幾個aware接口,所以當我們的Bean只要實現了以下任意的接口,都會在invokeAwareInterfaces方法中被處理
- EnvironmentAware注入環境屬性,可以拿到系統屬性 環境屬性 ,還有import進去的自定義的屬性文件;
- EmbeddedValueResolverAware,處理屬性資源中的${}這種表達式,將當前EnvironmentAware中的屬性用來處理${}表達式;
- ResourceLoaderAware 獲取資源加載器,用它可以動態地添加資源;
- ApplicationEventPublisherAware 處理事件發布 與ApplicationEvent ApplicationListener一起使用
- MessageSourceAware 處理資源國際化
- ApplicationContextAware 注入ApplicationContext,可以getBean等操作
當然看到這個地方,肯定有人會疑惑,這個ApplicationContextAwareProcessor,我們並沒有在代碼中將其實例化為一個Bean。為什么只要實現了ApplicationContextAware接口的Bean對象,就可以注入進來ApplicationContext對象。
其實在Spring源碼中在准備beanFactory的時候就已經將ApplicationContextAwareProcessor添加到beanPostProcessor List列表中了
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Tell the internal bean factory to use the context's class loader etc.
beanFactory.setBeanClassLoader(getClassLoader());
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// Configure the bean factory with context callbacks.
// 添加beanPostProcessor,ApplicationContextAwareProcessor此類用來完成某些Aware對象的注入
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
一、實現SpringUtils工具類
我們希望在自定義的SpringUtils中注入一個ApplicationContext對象,能夠在代碼里通過getBean的形式來獲取IOC容器的中Bean對象
再次感謝spring的開發團隊,因為spring的易擴展性,它為我們提供了超級簡單的方法來獲取applicationContext對象
不多說,看代碼
@Component
public class SpringUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext;
/**
* 注入 applicationContext
*
* @param applicationContext
* @throws BeansException
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringUtils.applicationContext = applicationContext;
}
/**
* 獲取指定類的bean對象
*
* @param clazz 類類型
* @return
*/
public static <T> T getBean(Class<T> clazz) {
return applicationContext.getBean(clazz);
}
/**
* 獲取指定類的指定名稱的bean對象
*
* @param name bean名稱
* @param clazz 類類型
* @return
*/
public static <T> T getBean(String name, Class<T> clazz) {
return applicationContext.getBean(name, clazz);
}
}
一個靜態的SpringUtils就這樣寫好了,是不是So Easy???
二、自定義aware接口,並能夠在bean中自動注入自定義對象
第1步 實現aware接口,定義好需要注入的對象及其相應方法
public interface GlobalSessionAware extends Aware {
/**
* 注入全局的session
*
* @param session
*/
public void setGlobalSession(GlobalSession session);
}
第2步 實現BeanPostProcessor,並回調aware接口中的set方法,將BeanPostProcessor作為一個bean對象,加入到spring容器中
@Component
public class GlobalSessionAwarePostProcessor implements BeanPostProcessor, ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
Object session = this.applicationContext.getBean("globalSession");
if (session == null) {
return bean;
}
if (session instanceof GlobalSession && bean instanceof GlobalSessionAware) {
((GlobalSessionAware) bean).setGlobalSession((GlobalSession) session);
}
return bean;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
第3步 使用GlobalSession,在需要注入GlobalSession的bean中實現GlobalSessionAware接口
@Component
public class WebTT implements GlobalSessionAware {
private GlobalSession session;
/**
* GlobalSession
*
* @param session
*/
@Override
public void setGlobalSession(GlobalSession session) {
this.session = session;
}
}
到此已經實現了aware接口的自定義,這個地方我們需要知道的是,Awarer接口本身屬於修改bean信息的一種功能性接口,但它需要在創建bean時能夠被調用到,所以這個地方BeanPostProcessor就能夠實現這個功能