Spring Aware 介绍

这次一定?

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

  • 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之后,针对下面图片的结果你是否有疑惑呢

第一个是内部 bean``````Person对象不在 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实现类

这次一定?

群聊

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值