本文内容如有错误、不足之处,欢迎技术爱好者们一同探讨,在本文下面讨论区留言,感谢。
简述
Spring Aware Interfaces允许 Bean 了解Spring Framework 的内部工作原理。通过Spring Aware接口,Bean 可以访问Spring上下文或Spring Bean生命周期事件。
Spring Bean 可能需要访问框架对象,例如 ApplicationContext,BeanFactory 和 ResourceLoader。为了获得访问权限,Bean 可以实现 Spring 框架的许多 Aware 接口。
当 Bean 实现 Aware 接口时,Spring 框架通过回调样式方法将特定的框架对象注入 Bean 。Spring 注入的对象取决于 Bean 实现的接口。例如,如果 Bean 实现了 ApplicationContextAware 接口,Spring 将向其中注入一个 ApplicationContext 对象。
Spring 框架是低侵入性,因此 Spring Bean 对 Spring 容器的感知是无感的,但是在实际实现过程中,需要部分 Spring Bean 对 Spring 容器内部环境有感并且可以调用部分资源来完成自身特定功能的实现。因此有了 Aware 接口,aware 翻译:已感知的,意识到的。
Aware 接口是标记超级接口,用于标记 Bean 有资格通过回调拦截方法由 Spring 容器通知特定对象。直接或间接实现了这个接口的类,Spring 容器可以通知的能力。
原理
Aware 接口是个标记接口,实现 Aware 接口的类通过 Spring 容器回调的方式进行赋值。
标记
Aware 接口是3.1版本出现的,实现 Aware 接口的类比较多。
package org.springframework.beans.factory;
/**
* Marker superinterface indicating that a bean is eligible to be
* notified by the Spring container of a particular framework object
* through a callback-style method. Actual method signature is
* determined by individual subinterfaces, but should typically
* consist of just one void-returning method that accepts a single
* argument.
*
* <p>Note that merely implementing {@link Aware} provides no default
* functionality. Rather, processing must be done explicitly, for example
* in a {@link org.springframework.beans.factory.config.BeanPostProcessor BeanPostProcessor}.
* Refer to {@link org.springframework.context.support.ApplicationContextAwareProcessor}
* and {@link org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory}
* for examples of processing {@code *Aware} interface callbacks.
*
* @author Chris Beams
* @since 3.1
*/
public interface Aware {
}
回调
AbstractAutowireCapableBeanFactory#initializeBean
AbstractAutowireCapableBeanFactory 类中初始化Bean的代码逻辑
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
AbstractAutowireCapableBeanFactory#invokeAwareMethods
拦截 Bean,对 Bean 进行类型校验,并通过回调 Aware 相应方法进行填充对应组件或信息。
private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
例子
使用 BeanNameAware 作为例子进行分析,BeanNameAware 使对象知道容器中定义的 Bean 名称。
定义MyBeanName
public class MyBeanName implements BeanNameAware {
@Override
public void setBeanName(String beanName) {
System.out.println(beanName);
}
}
该 beanName 属性表示在 Spring 容器中注册该 bean ID 。
注册Config Bean
在 Spring 配置类中注册这种类型的 bean :
@Configuration
public class Config {
@Bean(name = "myCustomBeanName")
public MyBeanName getMyBeanName() {
return new MyBeanName();
}
}
使用 @Bean(name=“myCustomBeanName”) 给 MyBeanName 类分配名称。
启动应用程序
启动应用程序上下文并从中获取 bean :
AnnotationConfigApplicationContext context
= new AnnotationConfigApplicationContext(Config.class);
MyBeanName myBeanName = context.getBean(MyBeanName.class);
例子结论
setBeanName 方法将输出myCustomBeanName,原因是在上面的原理中对 Bean 初始化已经分析了,getBean 时会调用 AbstractAutowireCapableBeanFactory#invokeAwareMethods 方法进行回调。
如果在 @Bean 参数中删除 name=" " 代码,则在这种情况下,将 getMyBeanName 方法名称分配给 bean。因此输出将是 getMyBeanName 。
BeanNameAware 的典型用例可能是获取 bean 的名称用来进行记录或追踪。
注意
在大多数情况下,除非需要它们,否则应避免使用任何Aware接口,因为实现这些接口会将代码耦合到Spring框架,从而颠倒了整个控制反转概念。在理想的情况下,开发人员设计的应用程序根本不应该意识到该对象是由ApplicationContext管理或与任何框架对象绑定在一起的。
常用Aware
序号 | 类名 | 作用 |
---|---|---|
0 | BeanNameAware | 感知BeanName |
1 | ApplicationContextAware | 感知应用上下文 |
2 | EnvironmentAware | 感知Spring容器环境 |
3 | BeanFactoryAware | 感知BeanFactory |
自定义Aware
第一步:定义自定义接口
/**
* ActiveProfilesAware 接口会将活动配置文件设置到实现此接口的 Bean 中。
*/
public interface ActiveProfilesAware extends Aware {
void setActiveProfiles(List<String> activeProfiles);
}
第二步:实现 ActiveProfilesAware 的 bean
@Component
public class PersonService implements ActiveProfilesAware {
private List<String> activeProfiles;
@Override
public void setActiveProfiles(List<String> activeProfiles) {
this.activeProfiles = activeProfiles;
}
}
第三步:通过 BeanPostProcessor#postProcessBeforeInitialization 来处理实现 ActiveProfilesAware 的 bean
@Component
public class ActiveProfilesPostProcessor implements BeanPostProcessor {
private final Environment environment;
@Autowired
public ActiveProfilesPostProcessor(Environment environment) {
this.environment = environment;
}
@Nullable
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof ActiveProfilesAware) {
List<String> activeProfiles = Arrays.stream(environment.getActiveProfiles()).collect(Collectors.toList());
((ActiveProfilesAware) bean).setActiveProfiles(activeProfiles);
return bean;
}
return bean;
}
}
设置完成后,Spring 将在实现 ActiveProfilesAware 的 bean 上调用 setActiveProfiles() 方法 。
结论
本文研究了 Spring 的 Aware 接口的设计初衷,以及如何实现自己的 Aware 接口。
参考资料
Using Spring Aware Interfaces(使用Spring Aware接口)
spring源码学习之Aware分析
Spring Aware接口解析
BeanNameAware and BeanFactoryAware Interfaces in Spring(Spring中的BeanNameAware和BeanFactoryAware接口)
Quick Guide to Spring Aware Interfaces(Spring Aware接口快速指南)