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接口的更多相关文章

  1. 学习 Spring (五) Aware 接口

    Spring入门篇 学习笔记 Spring 中提供了一些以 Aware 结尾的接口,实现了 Aware 接口的 bean 在被初始化之后可以获取相应资源 通过 Aware 接口,可以对 Spring ...

  2. Spring 学习——Aware接口

    Aware 作用 Spring中提供了一些以Aware结尾的接口,实现了Aware接口的Bean在初始化后,可以通过一些接口获取相应的资源. 通过Aware接口,可以对Spring的资源进行一些操作( ...

  3. spring(五):spring中Aware接口的使用

    spring中自定义组件需要使用spring的底层组件时,可以通过自定义组件实现相关XxxAware接口,重写其中的方法进而实现 例如:自定义一个组件,该组件中需要使用ApplicationConte ...

  4. spring4.1.8扩展实战之二:Aware接口揭秘

    Aware.java是个没有定义任何方法的接口,拥有众多子接口,在spring源码中有多处都在使用这些子接口完成各种场景下的回调操作,当业务有需要时,我们只需创建类来实现相关接口,再声明为bean,就 ...

  5. spring扩展点之四:Spring Aware容器感知技术,BeanNameAware和BeanFactoryAware接口,springboot中的EnvironmentAware

    aware:英 [əˈweə(r)] 美 [əˈwer] adj.意识到的;知道的;觉察到的 XXXAware在spring里表示对XXX感知,实现XXXAware接口,并通过实现对应的set-XXX ...

  6. Spring扩展之五:Aware接口等

    ApplicationContextAwareProcessor 1.介绍 ApplicationContextAwareProcessor是一个Spring内部工具,它实现了接口BeanPostPr ...

  7. spring中的aware接口

    1.实现了相应的aware接口,这个类就获取了相应的资源. 2.spring中有很多aware接口,包括applicationContextAware接口,和BeanNameAware接口. 实现了这 ...

  8. spring学习六----------Bean的配置之Aware接口

    © 版权声明:本文为博主原创文章,转载请注明出处 Aware Spring提供了一些以Aware结尾的接口,实现了Aware接口的bean在被初始化后,可以获取相应的资源 通过Aware接口,可以对S ...

  9. spring源码:Aware接口(li)

    一.spring容器中的aware接口介绍 Spring中提供了各种Aware接口,比较常见的如BeanFactoryAware,BeanNameAware,ApplicationContextAwa ...

  10. Spring中Aware相关接口原理

    Spring中提供一些Aware相关接口,像是BeanFactoryAware. ApplicationContextAware.ResourceLoaderAware.ServletContextA ...

随机推荐

  1. 从 2018 年 Nacos 开源说起

    2018 年夏天 国内微服务开源 领域,迎来了一位新成员.此后,在构建微服务注册中心和配置中心的过程中,国内开发者多了一个可信赖的选项. Nacos 是阿里巴巴开源的一个更易于构建云原生应用的动态服务 ...

  2. Joint Consensus两阶段成员变更的单步实现

    ​简介: Raft提出的两阶段成员变更Joint Consensus是业界主流的成员变更方法,极大的推动了成员变更的工程应用.但Joint Consensus成员变更采用两阶段,一次变更需要提议两条日 ...

  3. [FAQ] Vmmem 内存占用高的问题 -Win10 -WLS2

    1按下Windows + R 键,输入 %UserProfile% 并运行进入用户文件夹 2新建文件 .wslconfig ,然后记事本编辑 3 填入以下内容并保存, memory为系统内存上限,这里 ...

  4. [Go] freecache 设置 SetGCPercent 的作用

    你需要对 freecache 有一个大致了解,freecache 的内存空间是预分配的. 假设你的程序占用了 50M 内存,那么开启 freecache 预分配 200M 空间,总共下来就是 250M ...

  5. Django之路由层、视图层、模板层介绍

    一.Django请求生命周期 1.路由层urls.py Django 1.11版本 URLConf官方文档 1.1 urls.py配置基本格式 from django.conf.urls import ...

  6. CF1097C Yuhao and a Parenthesis

    CF1097C Yuhao and a Parenthesis stl 乱搞做法,感觉比正解更直接. 每个字符串内部能匹配的尽可能匹配. 匹配完成后,检验剩余序列是否只含有 ( 或只含有 ) 或为空, ...

  7. sqli-labs-master 第一关

    Sql注入 基础知识: 一··系统函数; 1. version()--MySQL 版本 2. user()--数据库用户名 3. database()--数据库名 4. @@datadir--数据库路 ...

  8. 后宫酒店HaremHotel游戏Python游戏作弊方法游戏金币增加方法

    额,这个游戏嘛,内容就不说了, 顺便送给大家下载地址:https://store.zhaimaojun.cn/GameDetail/280 这个游戏刚开始起步其实比较困难,因为没钱啊,动不动就要花钱, ...

  9. 莫队算法(基础莫队)小结(也做markdown测试)

    莫队 基础莫队 本质是通过排序优化了普通尺取法的时间复杂度. 考虑如果某一列询问的右端点是递增的,那么我们更新答案的时候,右指针只会从左往右移动,那么i指针的移动次数是$O(n)$的. 当然,我们不可 ...

  10. ip地址、子网掩码、网关、dns简介

    IP地址IPADDR: IP地址是唯一的标识,是一段网络编码(二进制),由32位组成. IP 是 Internet Protocol(网际互连协议)的缩写,是 TCP/IP 体系中的网络层协议. IP ...