• 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的初始化方法

  • 相关阅读:
    Python3.x与Python2.x的区别
    Python3.x:打包为exe执行文件(window系统)
    Python3.x:常用基础语法
    关于yaha中文分词(将中文分词后,结合TfidfVectorizer变成向量)
    关于:cross_validation.scores
    list array解析(总算清楚一点了)
    pipeline(管道的连续应用)
    关于RandomizedSearchCV 和GridSearchCV(区别:参数个数的选择方式)
    VotingClassifier
    Python的zip函数
  • 原文地址:https://www.cnblogs.com/jackion5/p/13283232.html
Copyright © 2020-2023  润新知