7、Mini-spring Aware接口

98 阅读2分钟

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;
   }
}

Bean生命周期

image.png