Spring扩展——Aware接口

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Spring扩展——Aware接⼝
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就能够实现这个功能。

相关文档
最新文档