1 前言

Aware是Spring提供的一个标记超接口,批示bean有资格通过回调款式的办法由Spring容器告诉特定的框架对象,以获取到容器中特有对象的实例的办法之一。理论的办法签名由各个子接口确定,但通常只蕴含一个承受单个参数的void返回办法。

2 Spring中9个Aware内置实现

|--Aware    |--BeanNameAware    |--BeanClassLoaderAware    |--BeanFactoryAware    |--EnvironmentAware    |--EmbeddedValueResolverAware    |--ResourceLoaderAware    |--ApplicationEventPublisherAware    |--MessageSourceAware    |--ApplicationContextAware

9个内置实现又分两类,前三个为间接调用,后6个通过ApplicationContextAwareProcessor后置处理器,间接回调

2.1 BeanNameAware

public interface BeanNameAware extends Aware {       /**        *设置创立此bean的bean工厂中的bean的名称。        *在一般bean属性填充之后但在        *初始化之前回调,如{@link InitializingBean#afterPropertiesSet()}        *或自定义初始化办法。        * @param name工厂中bean的名称。        *留神,此名称是工厂中应用的理论bean名称,这可能        *与最后指定的名称不同:特地是对于外部bean        * names,理论的bean名称能够通过增加        *“#…”后缀。应用{@link BeanFactoryUtils#originalBeanName(String)}        *办法提取原始bean名称(不带后缀),如果需要的话。        * /    void setBeanName(String name);}

实现BeanNameAware接口须要实现setBeanName()办法,这个办法只是简略的返回咱们以后的beanName,这个接口外表上的作用就是让实现这个接口的bean晓得本人在spring容器里的名字,而且官网的意思是这个接口更多的应用在spring的框架代码中,理论开发环境应该不倡议应用,因为spring认为bean的名字与bean的分割并不是很深,(确实,抛开spring API而言,咱们如果获取了该bean的名字,其实意义不是很大,咱们没有获取该bean的class,只有该bean的名字,咱们也无从下手,相同,因为bean的名称在spring容器中可能是该bean的惟一标识,也就是说再beanDefinitionMap中,key值就是这个name,spring能够依据这个key值获取该bean的所有个性)所以spring说这个不是非必要的依赖。

2.2 BeanClassLoaderAware

public interface BeanClassLoaderAware extends Aware {   /**    *提供bean {@link ClassLoader}类加载器的回调    *一个bean实例在属性的填充之后但在初始化回调之前调用    * {@link InitializingBean    * {@link InitializingBean#afterPropertiesSet()}    *办法或自定义初始化办法。    * @param类加载器领有的类加载器;可能是{@code null}在例如,必须应用默认的{@code ClassLoader}    * 获取的{@code ClassLoader}    * {@link org.springframework.util.ClassUtils#getDefaultClassLoader()}    * /   void setBeanClassLoader(ClassLoader classLoader);}

在bean属性填充之后初始化之前,提供类加制器的回调。让受管Bean自身晓得它是由哪一类装载器负责装载的。

2.3 BeanFactoryAware

public interface BeanFactoryAware extends Aware {   /**    * 为bean实例提供所属工厂的回调。    * 在一般bean属性填充之后调用但在初始化回调之前,如    * {@link InitializingBean#afterPropertiesSet()}或自定义初始化办法。    * @param beanFactory领有beanFactory(非空)。bean能够立刻调用工厂上的办法。    * @在初始化谬误时抛出BeansException    * @参见BeanInitializationException    * /   void setBeanFactory(BeanFactory beanFactory) throws BeansException;}

在bean属性填充之后初始化之前,提bean工厂的回调。实现 BeanFactoAware 接口的 bean 能够间接拜访 Spring 容器,被容器创立当前,它会领有一个指向 Spring 容器的援用,能够利用该bean依据传入参数动静获取被spring工厂加载的bean

2.4 EnvironmentAware

public interface EnvironmentAware extends Aware {   /**    * 设置该对象运行的{@code环境}。    */   void setEnvironment(Environment environment);}

设置该对象运行的。所有注册到 Spring容器内的 bean,只有该bean 实现了 EnvironmentAware接口,并且进行重写了setEnvironment办法的状况下,那么在工程启动时就能够获取得 application.properties 的配置文件配置的属性值,这样就不必咱们将魔法值写到代码外面了。

2.5 EmbeddedValueResolverAware

public interface EmbeddedValueResolverAware extends Aware {   /**    * 设置StringValueResolver用于解析嵌入的定义值。    */   void setEmbeddedValueResolver(StringValueResolver resolver);}

在基于Spring获取properties文件属性值的时候,个别应用@Value的形式注入配置文件属性值,然而@Value必须要在Spring的Bean生命周期治理下能力应用,比方类被@Controller、@Service、@Component等注解标注。如有的抽象类中,基于Spring解析@Value的形式,应用EmbeddedValueResolverAware解析配置文件来实现。

2.6 ResourceLoaderAware

public interface ResourceLoaderAware extends Aware {   /**    *设置该对象运行的ResourceLoader。这可能是一个ResourcePatternResolver,它能够被查看    *通过{@code instanceof ResourcePatternResolver}。另请参阅    * {@code ResourcePatternUtils。getResourcePatternResolver}办法。    * <p>在填充一般bean属性之后但在init回调之前调用    *像InitializingBean的{@code afterPropertiesSet}或自定义初始化办法。    *在ApplicationContextAware的{@code setApplicationContext}之前调用。    * @param resourceLoader该对象应用的resourceLoader对象    * @ @ springframework.core. io.support.resourcepatternresolver    * @ @ resourcepatternutils #获取resourcepatternresolver    * /   void setResourceLoader(ResourceLoader resourceLoader);}

ResourceLoaderAware 是非凡的标记接口,它心愿领有一个 ResourceLoader 援用的对象。当实现了 ResourceLoaderAware接口的类部署到application context(比方受Spring治理的bean)中时,它会被application context辨认为 ResourceLoaderAware。 接着application context会调用setResourceLoader(ResourceLoader)办法,并把本身作为参数传入该办法(记住,所有Spring里的application context都实现了ResourceLoader接口)。

既然 ApplicationContext 就是ResourceLoader,那么该bean就能够实现 ApplicationContextAware接口并间接应用所提供的application context来载入资源,然而通常更适宜应用特定的满足所有须要的 ResourceLoader 实现。 这样一来,代码只须要依赖于能够看作辅助接口的资源载入接口,而不必依赖于整个Spring ApplicationContext 接口。

2.7 ApplicationEventPublisherAware

public interface ApplicationEventPublisherAware extends Aware {   /**    *设置该对象运行的ApplicationEventPublisher。    * <p>在一般bean属性填充之后但在init之前调用像InitializingBean的afterPropertiesSet或自定义初始化办法。    *在ApplicationContextAware的setApplicationContext之前调用。    *该对象应用的事件发布者    * /   void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher);}

ApplicationEventPublisherAware 是由 Spring 提供的用于为 Service 注入 ApplicationEventPublisher 事件公布器的接口,应用这个接口,咱们本人的 Service 就领有了公布事件的能力。

2.8 MessageSourceAware

public interface MessageSourceAware extends Aware {   /**    *设置该对象运行的MessageSource。    * <p>在一般bean属性填充之后但在init之前调用像InitializingBean的afterPropertiesSet或自定义初始化办法。    *在ApplicationContextAware的setApplicationContext之前调用。    * @param messageSource音讯源    * /   void setMessageSource(MessageSource messageSource);}

取得message source这样能够取得文本信息,应用场景如为了国际化。

2.9 ApplicationContextAware

public interface ApplicationContextAware extends Aware {   /**    *设置该对象运行的ApplicationContext。通常这个调用将用于初始化对象。    * <p>在一般bean属性填充之后但在init回调之前调用    *作为{@link org.springframework.beans.factory.InitializingBean#afterPropertiesSet()}    *或自定义初始化办法。在{@link ResourceLoaderAware#setResourceLoader}之后调用,    * {@link ApplicationEventPublisherAware#setApplicationEventPublisher}和    * {@link MessageSourceAware},如果实用。    * @param applicationContext该对象将应用的applicationContext对象    * @在上下文初始化谬误时抛出ApplicationContextException如果由应用程序上下文办法抛出,则抛出BeansException    * @see org.springframework.beans.factory.BeanInitializationException    * /   void setApplicationContext(ApplicationContext applicationContext) throws BeansException;}

ApplicationContextAware的作用是能够不便获取Spring容器ApplicationContext,从而能够获取容器内的Bean。ApplicationContextAware接口只有一个办法,如果实现了这个办法,那么Spring创立这个实现类的时候就会主动执行这个办法,把ApplicationContext注入到这个类中,也就是说,spring 在启动的时候就须要实例化这个 class(如果是懒加载就是你须要用到的时候实例化),在实例化这个 class 的时候,发现它蕴含这个 ApplicationContextAware 接口的话,sping 就会调用这个对象的 setApplicationContext 办法,把 applicationContext Set 进去了。

3 Spring中调用机会

Aware接口由Spring在AbstractAutowireCapableBeanFactory.initializeBean(beanName, bean,mbd)办法中通过调用invokeAwareMethods(beanName, bean)办法和applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName)触发Aware办法的调用

3.1 invokeAwareMethods

private void invokeAwareMethods(final String beanName, final Object bean) {   if (bean instanceof Aware) {      if (bean instanceof BeanNameAware) {         ((BeanNameAware) bean).setBeanName(beanName);      }      if (bean instanceof BeanClassLoaderAware) {         ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());      }      if (bean instanceof BeanFactoryAware) {         ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);      }   }}

判断并间接回调

3.2 applyBeanPostProcessorsBeforeInitialization

public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)      throws BeansException {   Object result = existingBean;   for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {      result = beanProcessor.postProcessBeforeInitialization(result, beanName);      if (result == null) {         return result;      }   }   return result;}

通过ApplicationContextAwareProcessor.postProcessBeforeInitialization(Object bean, String beanName)间接调用,并在办法invokeAwareInterfaces中进行回调。

public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {   AccessControlContext acc = null;   if (System.getSecurityManager() != null &&         (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||               bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||               bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {      acc = this.applicationContext.getBeanFactory().getAccessControlContext();   }   if (acc != null) {      AccessController.doPrivileged(new PrivilegedAction<Object>() {         @Override         public Object run() {            invokeAwareInterfaces(bean);            return null;         }      }, acc);   }   else {      invokeAwareInterfaces(bean);   }   return bean;}private void invokeAwareInterfaces(Object bean) {   if (bean instanceof Aware) {      if (bean instanceof EnvironmentAware) {         ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());      }      if (bean instanceof EmbeddedValueResolverAware) {         ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(               new EmbeddedValueResolver(this.applicationContext.getBeanFactory()));      }      if (bean instanceof ResourceLoaderAware) {         ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);      }      if (bean instanceof ApplicationEventPublisherAware) {         ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);      }      if (bean instanceof MessageSourceAware) {         ((MessageSourceAware) bean).setMessageSource(this.applicationContext);      }      if (bean instanceof ApplicationContextAware) {         ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);      }   }}

4 总结

通过下面的剖析,能够晓得Spring生命周期中的初始化办法里,在真正执行初始化办法之前,别离通过invokeAwareMethods办法和后置处理器ApplicationContextAwareProcessor来触发Aware的调用,那么,Spring为什么要应用两种形式而不应用其中之一呢?

通过本章咱们理解了9中内置接口的作用,以及它们可能获取到的不同上下文信息。

作者:京东批发 曾登均

起源:京东云开发者社区