zoukankan      html  css  js  c++  java
  • 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的初始化方法

  • 相关阅读:
    Representation Data in OpenCascade BRep
    Render OpenCascade Geometry Surfaces in OpenSceneGraph
    Render OpenCascade Geometry Curves in OpenSceneGraph
    OpenCascade Shape Representation in OpenSceneGraph
    Geometry Surface of OpenCascade BRep
    Geometry Curve of OpenCascade BRep
    Tyvj2017清北冬令营入学测试
    Spfa算法模板
    洛谷1016 旅行家的预算
    洛谷1290 欧几里得的游戏
  • 原文地址:https://www.cnblogs.com/jackion5/p/13283232.html
Copyright © 2011-2022 走看看