spring扩展接口解析3--Aware系列接口

前言

Spring的核心思想之一就是IOC(控制反转),而IOC的实现方式DI(依赖注入),也就是说当某个bean需要依赖另一个bean时,就可以采用依赖注入的方式将依赖的bean自动注入到该bean中。但是如果一个bean依赖的对象并非是一个bean,此时通过容器的依赖注入显然就无法实现了,不过Spring容器提供了扩展接口,当某个bean对某个对象有兴趣或者是想要获取该对象时,比如想要获取Spring容器本身的资源,此时就可以采用Aware接口来获取。

一、Aware接口

Aware接口是Aware系列接口的顶级接口,当时Aware接口没有任何定义,仅仅是一个声明,也就是仅仅起到了一个标识的作用。实现了Aware接口的类就会被Spring容器所感知。而具体需要感知什么内容需要具体的子接口去定义。

比如说想要得到BeanFactory这个对象,此时就可以定义一个BeanFactoryAware接口实现Aware接口;想要得到ApplicationContext对象,就可以定义ApplicationContextAware接口,那么实现了对应接口的bean就可以获取到对应的对象。

每个Aware接口的子接口,内部都需要有一个set方法,将本身设置进去,这样实现了该接口的类就可以获取到该对象了

比如某个bean实现了BeanFactoryAware接口,BeanFactoryAware接口就会有一个setBeanFactroy(BeanFactroy beanFactory)方法,子类实现了之后,就可以得到beanFactory对象了。同理实现了XXXAware接口,就可以得到XXX这个对象。

二、Spring提供的常用的Aware接口

Spring提供了Aware接口的同时,也提供了很多自带的Aware子接口,主要是用于获取Spring容器本身的对象。如下图示:

可以看出Spring本身就已经提供了很多的Aware接口,需要使用到某个对象就可以实现对应的Aware接口即可

2.1、BeanFactoryAware接口(获取BeanFactory对象)

1 public interface BeanFactoryAware extends Aware {
2 
3     /**
4          * 设置BeanFactory属性
5      */
6     void setBeanFactory(BeanFactory beanFactory) throws BeansException;
7 
8 }

2.2、ApplicatioContextAware接口(获取ApplicationContext对象)

public interface ApplicationContextAware extends Aware {

    /**
     * 设置ApplicationContext属性
     */
    void setApplicationContext(ApplicationContext applicationContext) throws BeansException;

}

2.3、BeanNameAware接口(获取当前bean的beanName)

public interface BeanNameAware extends Aware {

    /**
     * 设置BeanName属性
     */
    void setBeanName(String name);

}

2.4、ApplicationEventPublisherAware接口(获取容器中事件发布器,可以用于发布事件)

public interface ApplicationEventPublisherAware extends Aware {

    /**
     * 设置事件发布器属性
     */
    void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher);

}

2.5、ResourceLoaderAware接口(获取资源加载器,用于获取外部资源文件)

public interface ResourceLoaderAware extends Aware {

    /**
     * 设置资源加载器属性
     */
    void setResourceLoader(ResourceLoader resourceLoader);

}

接口比较多就不再一一列举,可以看出每个Aware子接口都有一个共同点,就是都有一个set方法用于设置该类型对象的方法。

三、Aware接口使用

以Spring提供的Aware接口为例,自定义Bean分别实现Spring提供的Aware接口,测试案例如下:

 1 public class AwareBean implements BeanNameAware, BeanFactoryAware, ApplicationContextAware {
 2 
 3     private String beanName;
 4 
 5     private BeanFactory beanFactory;
 6 
 7     private ApplicationContext applicationContext;
 8 
 9     @Override
10     public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
11         this.beanFactory = beanFactory;
12     }
13 
14     @Override
15     public void setBeanName(String beanName) {
16         this.beanName = beanName;
17     }
18 
19     @Override
20     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
21         this.applicationContext = applicationContext;
22     }
23 
24     public void test(){
25         System.out.println("beanName:" + beanName);
26         System.out.println("从BeanFactory中获取当前bean " + beanFactory.getBean(AwareBean.class).equals(this));
27         System.out.println("从ApplicationContext中获取当前bean " + applicationContext.getBean(AwareBean.class).equals(this));
28     }
29 }

自定义AwareBean对象,分别实现了BeanNameAware、BeanFactoryAware和ApplicationContextAware接口,分别实现方法给内部属性赋值,调用test()方法测试结果如下:

1 beanName:awareBean
2 从BeanFactory中获取当前bean true
3 从ApplicationContext中获取当前bean true

既然bean可以通过实现BeanFactoryAware和ApplicationContextAware接口的方式可以注入Spring容器,所以bean获取其他bean的方式就可以通过容器直接获取,而不需要通过依赖注入来实现了,比如以下案例:

 1 public class AwareBean implements ApplicationContextAware {
 2 
 3     private ApplicationContext applicationContext;
 4 
 5     private UserService userService;
 6     private OrderService orderService;
 7 
 8     @Override
 9     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
10         this.applicationContext = applicationContext;
11         this.orderService = applicationContext.getBean(OrderService.class);
12         this.userService = applicationContext.getBean(UserService.class);
13     }
14 
15     public void test(){
16         System.out.println(userService != null);
17         System.out.println(orderService != null);
18     }
19 }

AwareBean依赖UserService和OrderService,但是没有采用依赖注入的方式,而是直接通过从Spring容器ApplicationContext中获取来设置赋值。

四、Aware接口的实现原理解析

 当bean实现了Aware接口之后,由于实现了Aware接口的方法,所以bean在初始化的过程中就需要执行Aware接口的方法,准确的说是在bean填充属性之后,执行init方法之前。

具体执行的逻辑是在初始化bean的方法initializeBean方法中,由前面几篇文章可知,bean的初始化过程分成 createBeanInstance(创建bean) ->populateBean(属性注入) ->initializeBean(执行初始化方法) 三步

而Aware接口方法的执行就是在第三步initializeBean方法当中,源码如下:

 1 protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
 2         if (System.getSecurityManager() != null) {
 3             AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
 4                 /** 1、执行Aware接口的方法*/
 5                 invokeAwareMethods(beanName, bean);
 6                 return null;
 7             }, getAccessControlContext());
 8         }
 9         else {
10             /** 1、执行Aware接口的方法*/
11             invokeAwareMethods(beanName, bean);
12         }
13 
14         Object wrappedBean = bean;
15         if (mbd == null || !mbd.isSynthetic()) {
/** 2、执行bean的前置处理器方法*/
16 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); 17 } 18 19 try { 20 /** 3、执行初始化方法*/ 21 invokeInitMethods(beanName, wrappedBean, mbd); 22 } 23 catch (Throwable ex) { 24 throw new BeanCreationException( 25 (mbd != null ? mbd.getResourceDescription() : null), 26 beanName, "Invocation of init method failed", ex); 27 } 28 if (mbd == null || !mbd.isSynthetic()) {
/** 4、执行bean的后置处理器方法*/
29 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); 30 } 31 32 return wrappedBean; 33 }

从源码中可看出bean的初始化方法中会先执行Aware接口的方法,然后才会去执行bean的具体的初始化方法。所以执行Aware接口的方法具体逻辑都在 invokeAwareMethods方法中实现,源码如下:

 1 /** 执行 Aware接口的方法 */
 2     private void invokeAwareMethods(final String beanName, final Object bean) {
 3         /**判断bean实现了Aware接口*/
 4         if (bean instanceof Aware) {
 5             //1.如果实现了BeanNameAware接口,则执行setBeanName方法
 6             if (bean instanceof BeanNameAware) {
 7                 ((BeanNameAware) bean).setBeanName(beanName);
 8             }
 9             //2.如果实现了BeanClassLoaderAware接口,则执行setBeanClassLoader方法
10             if (bean instanceof BeanClassLoaderAware) {
11                 ClassLoader bcl = getBeanClassLoader();
12                 if (bcl != null) {
13                     ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
14                 }
15             }
16             //3.如果实现了BeanFactoryAware接口,则执行BeanFactoryAware接口方法
17             if (bean instanceof BeanFactoryAware) {
18                 ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
19             }
20         }
21     }

可以看出这里分别判断bean是否实现了对应的Aware子接口,如果实现了Aware子接口,就将Bean转换成对应Aware子接口的对象,然后直接执行对应的set方法,将需要传入的参数传入即可。

但是这个方法很明显只判断了BeanNameAware、BeanClassLoaderAware、BeanFactoryAware三个Aware接口,而Spring容器中还有很多的Aware接口的方法在这里并没有执行,那么其他的接口比如ApplicationContextAware等接口又是何时执行的呢?

此时如果熟悉Spring的后置处理器的同学可能已经想到了,在bean初始化之前,会执行bean的后置处理器的方法,而其他的Aware接口就是通过后置处理器来执行的。

现在还是回到上面的initializeBean方法之后,在执行了BeanFactory的默认invokeAwareMethods方法之后,会先执行bean的前置处理器方法,然后执行invokeInitMethods方法执行初始化逻辑,最后再执行bean的后置处理器方法,执行bean的后置逻辑。

所以可以得知bean初始化时会分别执行前置处理器和后置处理器方法,而会执行Aware接口的处理器是ApplicationContextAwareProcesser,此处理器是在初始化ApplicationContext时加入的

执行ApplicationContext初始化方法时会执行refresh()方法,而refresh方法中第三步就是预处理BeanFactory方法prepareBeanFactory(beanFactory)方法,代码如下:

 1 protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
 2         // Tell the internal bean factory to use the context's class loader etc.
 3         beanFactory.setBeanClassLoader(getClassLoader());
 4         beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
 5         beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
 6 
 7         /** 创建ApplicationContextAwareProcessor对象,加入到BeanFactory的处理器中*/
 8         beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
 9         beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
10         beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
11         beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
12         beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
13         beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
14         beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
15 
16         /** 剩下代码省略*/
17     }

在预处理BeanFactory时,会初始化ApplicationContextAwareProcessor对象,调用BeanFactory的addBeanPostProcessor方法阿静该处理器加入到BeanFactory中。而在初始化bean的时候,会遍历BeanFactory中的所有BeanPostProcessor,依次执行前置和后置方法。所以这里执行Aware接口的方法就需要在ApplicationContextAwareProcessor中查看,该类的源码如下:

 1 class ApplicationContextAwareProcessor implements BeanPostProcessor {
 2 
 3         private final ConfigurableApplicationContext applicationContext;
 4 
 5         private final StringValueResolver embeddedValueResolver;
 6 
 7 
 8         /**
 9          * Create a new ApplicationContextAwareProcessor for the given context.
10          */
11         public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
12             this.applicationContext = applicationContext;
13             this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
14         }
15 
16 
17         @Override
18         @Nullable
19         /** 在bean的初始化之前执行 */
20         public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
21             if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
22                     bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
23                     bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){
24                 return bean;
25             }
26 
27             AccessControlContext acc = null;
28 
29             if (System.getSecurityManager() != null) {
30                 acc = this.applicationContext.getBeanFactory().getAccessControlContext();
31             }
32 
33             if (acc != null) {
34                 AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
35                     /**执行Aware接口方法*/
36                     invokeAwareInterfaces(bean);
37                     return null;
38                 }, acc);
39             }
40             else {
41                 /** 执行Aware接口方法 */
42                 invokeAwareInterfaces(bean);
43             }
44 
45             return bean;
46         }
47 
48         /** 回调执行各种类型Aware接口的方法*/
49         private void invokeAwareInterfaces(Object bean) {
50             //1.执行EnvironmentAware接口方法
51             if (bean instanceof EnvironmentAware) {
52                 ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
53             }
54             //2.执行EmbeddeValueResolverAware接口方法
55             if (bean instanceof EmbeddedValueResolverAware) {
56                 ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
57             }
58             //3.执行ResourceLoaderAware接口方法
59             if (bean instanceof ResourceLoaderAware) {
60                 ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
61             }
62             //4.执行ApplicationEventPublisherAware接口方法
63             if (bean instanceof ApplicationEventPublisherAware) {
64                 ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
65             }
66             //5.执行MessageSourceAware接口方法
67             if (bean instanceof MessageSourceAware) {
68                 ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
69             }
70             //6.执行ApplicationContextAware接口方法
71             if (bean instanceof ApplicationContextAware) {
72                 ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
73             }
74         }
75     }

可以看出在ApplicationContextAwareProcessor中的执行Aware接口的逻辑和BeanFactory初始化bean时的invokeAwareMethods方法逻辑基本差不多,都是依次判断bean是否实现了Aware的各个子接口,实现了对应的接口就将bean转换成对应接口的对象,然后直接执行对应的set方法,而这一步是在invokeAwareMethods方法执行之后,bean的init方法执行之前操作的

总结:

1、bean在初始化方法initializeBean方法中执行逻辑为先执行invokeAwareMethods执行BeanFactory提供的Aware子接口

2、然后遍历执行BeanFactory的后置处理器方法,其中ApplicationContextAwareProcessor处理器会执行ApplicationContext提供的Aware子接口方法

3、执行完Aware子接口方法之后,才会继续执行bean的初始化方法

原文地址:https://www.cnblogs.com/jackion5/p/13283232.html