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就能够实现这个功能
Spring扩展——Aware接口的更多相关文章
- 学习 Spring (五) Aware 接口
Spring入门篇 学习笔记 Spring 中提供了一些以 Aware 结尾的接口,实现了 Aware 接口的 bean 在被初始化之后可以获取相应资源 通过 Aware 接口,可以对 Spring ...
- Spring 学习——Aware接口
Aware 作用 Spring中提供了一些以Aware结尾的接口,实现了Aware接口的Bean在初始化后,可以通过一些接口获取相应的资源. 通过Aware接口,可以对Spring的资源进行一些操作( ...
- spring(五):spring中Aware接口的使用
spring中自定义组件需要使用spring的底层组件时,可以通过自定义组件实现相关XxxAware接口,重写其中的方法进而实现 例如:自定义一个组件,该组件中需要使用ApplicationConte ...
- spring4.1.8扩展实战之二:Aware接口揭秘
Aware.java是个没有定义任何方法的接口,拥有众多子接口,在spring源码中有多处都在使用这些子接口完成各种场景下的回调操作,当业务有需要时,我们只需创建类来实现相关接口,再声明为bean,就 ...
- spring扩展点之四:Spring Aware容器感知技术,BeanNameAware和BeanFactoryAware接口,springboot中的EnvironmentAware
aware:英 [əˈweə(r)] 美 [əˈwer] adj.意识到的;知道的;觉察到的 XXXAware在spring里表示对XXX感知,实现XXXAware接口,并通过实现对应的set-XXX ...
- Spring扩展之五:Aware接口等
ApplicationContextAwareProcessor 1.介绍 ApplicationContextAwareProcessor是一个Spring内部工具,它实现了接口BeanPostPr ...
- spring中的aware接口
1.实现了相应的aware接口,这个类就获取了相应的资源. 2.spring中有很多aware接口,包括applicationContextAware接口,和BeanNameAware接口. 实现了这 ...
- spring学习六----------Bean的配置之Aware接口
© 版权声明:本文为博主原创文章,转载请注明出处 Aware Spring提供了一些以Aware结尾的接口,实现了Aware接口的bean在被初始化后,可以获取相应的资源 通过Aware接口,可以对S ...
- spring源码:Aware接口(li)
一.spring容器中的aware接口介绍 Spring中提供了各种Aware接口,比较常见的如BeanFactoryAware,BeanNameAware,ApplicationContextAwa ...
- Spring中Aware相关接口原理
Spring中提供一些Aware相关接口,像是BeanFactoryAware. ApplicationContextAware.ResourceLoaderAware.ServletContextA ...
随机推荐
- 如何用一个插件解决 Serverless 灰度发布难题?
简介: 我们可以发现相比使用控制台进行灰度发布,使用 FC-Canary 插件免去了用户手动创建版本.发布别名.关联触发器和管理自定义域名的麻烦,使用起来非常方便. 作者:长淇 导读 本文适合: 想了 ...
- [GPT] 用 document.querySelector('.xxx') 选择下级的第二个 div 要怎么写
要选择类名为 .xxx 的元素下的第二个子<div>元素,可以将 querySelectorAll()方法与CSS选择器一起使用. 以下是一个示例: const secondChild ...
- [Linux] 启动管理: 运行级别
Link:https://www.cnblogs.com/farwish/p/14983932.html
- WPF 自定义控件入门 Focusable 与焦点
自定义控件时,如果自定义的控件需要用来接收键盘消息或者是输入法的输入内容,那就需要关注到控件的焦点 默认情况下的自定义控件是没有带可获取焦点的功能的,例如编写一个继承 FrameworkElement ...
- Solution - AGC060C
Link 简要题意:称一个长为 \(2^n-1\) 的排列 \(P\) 像堆,如果 \(P_i \lt P_{2i}\),且 \(P_i \lt P_{2i+1}\).给定 \(a,b\),设 \(u ...
- Elasticsdump 数据导入/导出
目录 一.安装过程 安装NODE 通过npm安装elasticdump 二.数据导出 实操一 实操二 实操三 三.文件导入 一.安装过程 当前工具主要是用来对ES中的数据进行数据导入/导出,以及对数据 ...
- ubuntu安装 vmware workstation pro 15.1.1
BIOS开启虚拟化 如果没有就参考下面的连接地址设置 http://robotrs.lenovo.com.cn/ZmptY2NtYW5hZ2Vy/p4data/Rdata/Rfiles/726.htm ...
- Java工具类库大总结
1. Java自带工具方法 1.1 List集合拼接成以逗号分隔的字符串 // 如何把list集合拼接成以逗号分隔的字符串 a,b,c List<String> list = Arrays ...
- 为什么 AI 时代更应该 Learn in Public
TL;DR Learn in Public 强调将学习到的知识 分享到公共空间,相较于纯输入式的学习有诸多好处.AI 工具极大降低了信息检索.整理.概括的门槛,使得输入信息更容易,但对我们真正掌握知识 ...
- angular自定义属性指令
在angular中有三种类型的指令: 组件–拥有模板的指令: 结构性指令–通过添加和移除DOM元素改变DOM布局的指令; 属性型指令–改变元素.组件或其他指令的外观和行为的指令: 组件是这三种指令中最 ...