Aware是感知、意识的意识,Aware是标记性接口,其实现子类能感知容器相关的对象。常用的Aware接口有BeanFactoryAware和ApplicationContextAware,分别可以让实现者感知所属的BeanFactory和ApplicatonContext。
Aware感知Application与BeanFactory
目录结构如下:
首先定义Aware标记类接口,实现该接口能感知容器类接口。
public interface Aware {}
接着我们定义ApplicationContextAware和BeanFactoryAware两个接口,用来感知ApplicationContext和BeanFactory。
public interface BeanFactoryAware extends Aware {
void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}
public interface BeanFactoryAware extends Aware {
void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}
创建测试Service,HelloService,然后分别实现这两个对应的接口。通过这种方式实现了感知ApplicationContext和BeanFactory的能力。
public class HelloService implements ApplicationContextAware, BeanFactoryAware {
private ApplicationContext applicationContext;
private BeanFactory beanFactory;
public String sayHello() {
System.out.println("hello");
return "hello";
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public ApplicationContext getApplicationContext() {
return applicationContext;
}
public BeanFactory getBeanFactory() {
return beanFactory;
}
}
测试类:测试无异常。
public class AwareInterfaceTest {
@Test
public void test() throws Exception {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");
HelloService helloService = applicationContext.getBean("helloService", HelloService.class);
assertThat(helloService.getApplicationContext()).isNotNull();
assertThat(helloService.getBeanFactory()).isNotNull();
}
}
具体实现:
那么是如何实现通过继承这两个接口就可以感知到对应的属性呢。其实具体的实现细节还是在bean的生命周期内去完成。
我们先来看BeanFactory的感知,首先来到initializeBean方法,也就是Bean的初始化方法。可以看到代码的前4行,比较简单,通过instanceof关键字去判断,然后将BeanFactory设置进去。
protected Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition) {
//感知BeanFactory
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(this);
}
//执行BeanPostProcessor的前置处理
Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);
try {
invokeInitMethods(beanName, wrappedBean, beanDefinition);
} catch (Throwable ex) {
throw new BeansException("Invocation of init method of bean[" + beanName + "] failed", ex);
}
//执行BeanPostProcessor的后置处理
wrappedBean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
return wrappedBean;
}
而ApplicationContext的实现,其实是通过BeanPostProcessor来实现的。我们来到AbstractApplicationContext的核心refresh()方法。
对比上一节的内容,我们可以发现,这节里面refresh方法多了一行,也就是添加ApplicationContextAwareProcessor,通过这种方式,使继承自ApplicationContextAware的bean能感知。
@Override
public void refresh() throws BeansException {
//创建BeanFactory,并加载BeanDefinition
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
//添加ApplicationContextAwareProcessor,让继承自ApplicationContextAware的bean能感知bean
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
//在bean实例化之前,执行BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);
//BeanPostProcessor需要提前与其他bean实例化之前注册
registerBeanPostProcessors(beanFactory);
//提前实例化单例bean
beanFactory.preInstantiateSingletons();
}
来看下ApplicationContextAwareProcessor是干什么的家伙。可以看到就是继承了BeanPostProcessor接口,然后实现了postProcess方法,在bean实例化后,通过BeanPostProcessor前置处理后置处理,将ApplicationContext设置进去,一点也不神秘对吧。
在这节还有一个变化就是改用dom4j解析xml文件。也就是XmlBeanDefinitionReader的变化,前面关于资源加载讲解的很详细了,这里不再赘述。
public class ApplicationContextAwareProcessor implements BeanPostProcessor {
private final ApplicationContext applicationContext;
public ApplicationContextAwareProcessor(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(applicationContext);
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}