Spring Aware 介绍

简介: 读完这篇文章你将会收获到• Aware 的使用和介绍• BeanFactoryAware 的触发时机• ApplicationContextAware 的触发时机以及它通过扩展 BeanPostProcessor 来实现

读完这篇文章你将会收获到

  • Aware 的使用和介绍
  • BeanFactoryAware 的触发时机
  • ApplicationContextAware 的触发时机以及它通过扩展  BeanPostProcessor 来实现


我们在  getBean 流程中曾经谈到过  Spring 回调  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) {
    ClassLoader bcl = getBeanClassLoader();
    if (bcl != null) {
     ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
    }
   }
   if (bean instanceof BeanFactoryAware) {
    ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
   }
  }
 }
复制代码


我们今天就来聊一下  Aware 接口

public interface Aware {
}
复制代码


一个空的接口、啥都没有、看注释说它只是一个标志性的接口、实现该接口的  bean 会被  Spring 以回调的方式进行通知、告诉你某个阶段某件事情发生了


BeanNameAware


public interface BeanNameAware extends Aware {
    void setBeanName(String name);
}
复制代码


这个我们举两个有意思的例子,一个是内部 bean 、一个是 factoryBean

<bean id="customer" class="com.demo.aware.Customer">
   <constructor-arg name="person">
      <bean class="com.demo.aware.Person">
         <property name="name" value="coderLi"/>
         <property name="address" value="china"/>
         <property name="age" value="666"/>
      </bean>
   </constructor-arg>
</bean>
<bean id="cat" class="com.demo.aware.CatFactory"/>
复制代码


具体的类就不贴了、没啥逻辑、CatFactory 就实现了 Spring 提供的 FactoryBean 接口。然后我们在 PersonCatFactory 中实现了接口 BeanNameAware 、并打印其参数 name

Resource resource = new ClassPathResource("aware/coderLi.xml");
DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
xmlBeanDefinitionReader.loadBeanDefinitions(resource);
defaultListableBeanFactory.getBean("customer");
defaultListableBeanFactory.getBean("cat");
复制代码


打印的结果就是:

bean Name aware [bean Name is] :com.demo.aware.Person#71a794e5
bean Name aware [bean Name is] :cat
复制代码


我们打断点在它们 getBean 之后,针对下面图片的结果你是否有疑惑呢


第一个是内部 beanPerson 对象不在 Spring 的容器中、但是它却触发了 Aware 接口的回调 , 第二个是第一级缓存和 beanFactory 缓存中 key 都是 cat

第一个问题其实很简单、主要是构建 Customer 的构造函数的参数 Person 的时候、在 BeanDefinitionValueResolver#resolveInnerBean 中直接调用了 createBean 方法、然后就到了 doCreateBean 、之后就回调 Aware 接口、但是没用放到 Spring 容器中


第二个问题、其实两者的 key 一样是完全没有问题的、往前翻我分析 getBean 流程的文章可以知道。这里就不重复了


其他


至于 BeanClassLoaderAwareBeanFactoryAware 就不演示代码了、挺简单的使用。

Spring 里面比较常见的 Aware 接口


我们看到很多像 ApplicationContextAware 或者 EnvironmentAwareAware 接口、并没有在 invokeAwareMethods 中被调用到、因为其实这些都是在使用 ApplicationContext 的时候才会被触发的、具体是在哪里被触发调用呢?


我们可以看到 ApplicationContextAwareProcessor#invokeAwareInterfaces

中就写了这么一段代码

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 实现了 BeanPostProcessor 的、


那这样子的话就是在 doCreateBean 的时候、通过 initializeBean 进行回调了


那这个 ApplicationContextAwareProcessor 什么时候添加到 Spring 中啊


而这个方法则是在 refresh 方法中被调用了,而 refresh 的调用就不用介绍了把

public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
 this(new String[] {configLocation}, true, null);
}
public ClassPathXmlApplicationContext(
      String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
      throws BeansException {
   super(parent);
   setConfigLocations(configLocations);
   if (refresh) {
      refresh();
   }
}
复制代码


其实 Spring 挺有意思的、将这个 ApplicationContextAwareProcessor 作为其第一个 BeanPostProcessor 接口、那么就能保证 Aware 接口被先回调、然后才到用户的 BeanPostProcessor  实现类



目录
相关文章
|
6月前
|
传感器 Java API
Spring揭秘:Aware接口应用场景及实现原理!
Aware接口赋予了Bean更多自感知的能力,通过实现不同的Aware接口,Bean可以轻松地获取到Spring容器中的其他资源引用,像ApplicationContext、BeanFactory等。 这样不仅增强了Bean的功能,还提高了代码的可维护性和扩展性,从而让Spring的IoC容器变得更加强大和灵活。
267 0
Spring揭秘:Aware接口应用场景及实现原理!
|
6月前
|
Java Spring 容器
深入Spring原理-4.Aware接口、初始化和销毁执行顺序、Scope域
深入Spring原理-4.Aware接口、初始化和销毁执行顺序、Scope域
131 0
|
3月前
|
设计模式 自然语言处理 Java
简单了解下Spring中的各种Aware接口实现依赖注入
在Spring框架中,Aware接口是一组用于提供特定资源或环境信息的回调接口。这些接口被设计用来允许Bean获取对Spring容器或其他相关资源的引用,并在需要时进行适当的处理。
33 2
|
3月前
|
自然语言处理 Java 开发者
简单了解下Spring中的各种Aware接口实现依赖注入
【8月更文挑战第21天】在Spring框架中,Aware接口系列是一种特殊的机制,它允许Bean在初始化过程中获取到Spring容器或容器中的特定资源,从而实现了更加灵活和强大的依赖注入方式。本文将围绕Spring中的各种Aware接口,详细探讨它们如何帮助开发者在工作和学习中更好地实现依赖注入。
95 0
|
Java Spring 容器
深入理解Spring IOC之扩展篇(四)、Aware接口
深入理解Spring IOC之扩展篇(四)、Aware接口
146 0
|
设计模式 Java Spring
Spring Aware接口详解
若 Spring 检测到 bean 实现了 Aware 接口,则会为其注入相应的依赖。所以通过让bean 实现 Aware 接口,则能在 bean 中获得相应的 Spring 容器资源。
216 0
|
Java 程序员 网络安全
spring4.1.8扩展实战之二:Aware接口揭秘
Aware.java是个没有定义任何方法的接口,拥有众多子接口,在spring源码中有多处都在使用这些子接口完成各种场景下的回调操作,当业务有需要时,我们只需创建类来实现相关接口,再声明为bean,就可以被spring容器主动回调
274 0
spring4.1.8扩展实战之二:Aware接口揭秘
|
安全 Java Spring
Spring Aware 到底是什么?
Spring Aware 到底是什么?
Spring Aware 到底是什么?
|
Java Maven Spring
【Spring】Spring高级话题-Spring Aware
【Spring】Spring高级话题-Spring Aware
204 0
【Spring】Spring高级话题-Spring Aware