乐趣区

关于spring:SpringIoc容器之Aware-京东云技术团队

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 工厂的回调。实现 BeanFactoηAware 接口的 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 中内置接口的作用,以及它们可能获取到的不同上下文信息。

作者:京东批发 曾登均

起源:京东云开发者社区

退出移动版