1. spring bean生命周期二 - Aware接口
通过前面的学习,知道了spring bean的整个生命周期中调用的所有接口方法,也留下了几个需要解答的问题,现在我们先来看第一个问题:
生命周期的前10个调用方法,都是以Aware结尾的接口方法,各个XXXAware接口作用是什么?对开发者来说有没有用?
1.1. Aware单词释义
aware 英 [ə'weə]
adj. 意识到的;知道的;有…方面知识的;懂世故的
只看此英文单词,实在是想不出来spring中以Aware为后缀的接口的作用究竟是什么,下面我们看一下接口定义和描述;
1.2. Aware接口定义
/**
* 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 {
}
从源码可以看出来:
Aware是一个用来标记的顶层设计接口,不包括任务功能方法;实际的方法签名由它的子类来声明,一般来说,是只带一个参数且返回void的方法;Aware标记一个bean有资格让spring特定容器对象通过回调方法进行通知;
在使用spring时,我们把所有的bean交给spring容器进行管理,一般来讲,所有的bean专注于业务逻辑,它们不关心spring容器,也不知道自己在spring中是如何被管理的,在spring工厂中的代号是什么,换句话说,bean对于spring是无感知的。
spring提供了一系列的Aware接口作为hook,在不同的阶段调用不同的接口方法来通知一个bean,使bean可以对spring有所感知。
1.3. BeanNameAware
让bean获取在BeanFactory中配置的名称(xml中的id或name),即一个实现了BeanNameAware接口的bean,可以获取其在工厂中的名称。
1.4. BeanFactoryAware
让bean对配置其BeanFactory有感知,即一个实现了BeanFactoryAware接口的bean,可以获取到配置它的BeanFactory实例。
其它的Aware类似,都是使一个bean对spring的某一方面有所感知,在特殊情况下,可以有用,但缺点也比较明显,就是对spring api耦合比较高,一般情况下,不建议使用。
1.5. AwareDemo
BeanNameAwareSamplesBean
/**
* {@link BeanNameAware#setBeanName(String)}: 获取此bean在容器中的名称
* {@link BeanClassLoaderAware#setBeanClassLoader(ClassLoader)}: 获取此bean在spring中初始化使用的classloader
* {@link BeanFactoryAware#setBeanFactory(BeanFactory)}: 获取此bean在spring中所处的{@link BeanFactory}
* {@link ApplicationContextAware#setApplicationContext(ApplicationContext)}:获取此bean的容器
*/
public class AwareSamplesBean implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, ApplicationContextAware {
public static final Logger LOGGER = LoggerFactory.getLogger(BeanNameAwareSamplesBean.class);
private String beanName;
private ClassLoader beanClassLoader;
private BeanFactory beanFactory;
private ApplicationContext applicationContext;
@Override
public void setBeanName(String name) {
LOGGER.info("获取bean在spring容器中的名称:{}", name);
this.beanName = name;
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
LOGGER.info("获取beanClassLoader: {}", classLoader);
this.beanClassLoader = classLoader;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
LOGGER.info("获取beanFactory : {}", beanFactory);
this.beanFactory = beanFactory;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
LOGGER.info("获取 applicationContext: {}", applicationContext);
this.applicationContext = applicationContext;
}
}
xml配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="samples.spring.step2.beans.MyBeanPostProcesser"/>
<bean id="awareSamplesBean" class="samples.spring.step2.beans.AwareSamplesBean"/>
</beans>
main函数:
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:step2/step2.xml");
LOGGER.info("==============classpathxmlapplicationcontext create completed.");
context.registerShutdownHook();
}
结果
2017-04-12 13:46:35.912 [main] INFO org.springframework.context.support.ClassPathXmlApplicationContext [581] - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@6aaa5eb0: startup date [Wed Apr 12 13:46:35 CST 2017]; root of context hierarchy
2017-04-12 13:46:35.956 [main] INFO org.springframework.beans.factory.xml.XmlBeanDefinitionReader [317] - Loading XML bean definitions from class path resource [step2/step2.xml]
2017-04-12 13:46:36.082 [main] INFO samples.spring.step2.beans.AwareSamplesBean [33] - 获取bean在spring容器中的名称:awareSamplesBean
2017-04-12 13:46:36.084 [main] INFO samples.spring.step2.beans.AwareSamplesBean [39] - 获取beanClassLoader: sun.misc.Launcher$AppClassLoader@4d7e1886
2017-04-12 13:46:36.084 [main] INFO samples.spring.step2.beans.AwareSamplesBean [45] - 获取beanFactory : org.springframework.beans.factory.support.DefaultListableBeanFactory@75881071: defining beans [samples.spring.step2.beans.MyBeanPostProcesser#0,awareSamplesBean]; root of factory hierarchy
2017-04-12 13:46:36.085 [main] INFO samples.spring.step2.beans.AwareSamplesBean [51] - 获取 applicationContext: org.springframework.context.support.ClassPathXmlApplicationContext@6aaa5eb0: startup date [Wed Apr 12 13:46:35 CST 2017]; root of context hierarchy
2017-04-12 13:46:36.085 [main] INFO samples.spring.step2.beans.MyBeanPostProcesser [17] - ============beanname:awareSamplesBean postprocesser:MyBeanPostProcesser's method:postProcessBeforeInitialization invoked.
2017-04-12 13:46:36.085 [main] INFO samples.spring.step2.beans.MyBeanPostProcesser [23] - ============beanname:awareSamplesBean postprocesser:MyBeanPostProcesser's method:postProcessAfterInitialization invoked.
2017-04-12 13:46:36.100 [main] INFO samples.spring.step1.SpringAppStep1 [20] - ==============classpathxmlapplicationcontext create completed.
2017-04-12 13:46:36.101 [Thread-0] INFO org.springframework.context.support.ClassPathXmlApplicationContext [982] - Closing org.springframework.context.support.ClassPathXmlApplicationContext@6aaa5eb0: startup date [Wed Apr 12 13:46:35 CST 2017]; root of context hierarchy
Process finished with exit code 0
可以看到,顺序确实是按照bean生命周期中的顺序进行调用的。