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 ...
随机推荐
- 性能提升40%!阿里云神龙大数据加速引擎获TPCx-BB世界排名第一
简介:神龙大数据加速引擎,针对大数据常用组件,如Spark.Hadoop.Alluxio等,结合阿里云神龙架构的特性,进行软硬一体化优化,形成独一无二的性能优势,最终,使复杂SQL查询场景性能相比社 ...
- Dubbo-Admin 正式支持 3.0 服务治理
简介:Dubbo 相信大家并不陌生,是一款微服务开发框架,它提供了 RPC 通信与微服务治理两大关键能力.大家在日常开发中更多使用的是 Dubbo 提供的 RPC 通信这一部分能力,而对其提供的服务 ...
- 前沿分享|阿里云资深技术专家 魏闯先:AnalyticDB PostgreSQL年度新版本发布
简介: 本篇内容为2021云栖大会-云原生数据仓库AnalyticDB技术与实践峰会分论坛中,阿里云资深技术专家 魏闯先关于"AnalyticDB PostgreSQL年度新版本发布&qu ...
- Ollama是什么,为什么这么好用
Ollama 是一个开源框架,专为在本地机器上便捷部署和运行大型语言模型(LLM)而设计. 以下是其主要特点和功能概述: 1. 简化部署:Ollama 目标在于简化在 Docker 容器中部署大型语言 ...
- LlamaIndex 起步教程(本地模型)
提示:确保您已先按照自定义安装步骤操作. 这是一个著名的"五行代码"起步示例,使用本地 LLM(大语言模型)和嵌入模型.我们将使用 BAAI/bge-small-en-v1.5 作 ...
- [FAQ] swagger-php @OA\JsonContent 与 @MediaType @OA\Schema 的用法
@OA\JsonContent 是对 @MediaType @OA\Schema 两者的封装,类似于 laravel 中 JsonResponse 对 Response 的封装. @OA\JsonCo ...
- 阿里面试Redis最常问的三个问题:缓存雪崩、击穿、穿透(带答案)
那提到Redis我相信各位在面试,或者实际开发过程中对缓存雪崩,穿透,击穿也不陌生吧,就算没遇到过但是你肯定听过,那三者到底有什么区别,我们又应该怎么去防止这样的情况发生呢,我们有请下一位受害者. 面 ...
- Oracle和达梦:相似度函数:UTL_MATCH
UTL_MATCH介绍: Oracle的UTL_MATCH包是一个提供字符串匹配和相似度计算功能的工具包.它包含了一系列函数,用于执行字符串比较.相似度计算和模式匹配等操作. UTL_MATCH包中的 ...
- MacOS安装和使用标注软件“labelImg”教程
原文发布于:https://blog.zhaoxuan.site/archives/16.html: 第一时间获取最新文章请关注博客个人站:https://blog.zhaoxuan.site. 简介 ...
- 解决小程序uni-app echars层级过高问题
使用 force-use-old-canvas="false" 使用微信小程序的cover-view会有很多问题,并且不一定生效,只需要在canvas的标签内添加 force-us ...