Bean对IOC容器的感知
容器管理的Bean一般不需要了解容器的状态和直接使用容器,但在某些情况下,是需要在Bean、中直接对IOC容器进行操作的,这时候,就需要再Bean中设定对容器的感知。——?IOC容器提供了该功能——通过aware接口来完成的。
aware接口有以下这些:
- BeanNameAware,可以在Bean中得到它在IOC容器中的Bean实例名称。
- BeanFactoryAware,可以在Bean中得到Bean所在的IOC容器,从而直接在Bean中使用IOC容器的服务。
- ApplicationContextAware,在Bean中得到Bean所在的应用上下文,从而直接在Bean中使用应用上下文的服务。
- MessageSourceAware,在Bean中可以得到消息源。
- ApplicationEvenetPublisherAware,在Bean中可以得到ResourceLoader,从而在Bean中使用ResourceLoader加载外部对应的Resource资源。
在设置Bean的属性之后,调用初始化回调方法之前,Spring会调用aware接口中的setter方法。以ApplicationContextAware为例,分析对应的设计和实现。这个接口定义得很简单。
public interface ApplicationContextAware extends Aware {
/**
* Set the ApplicationContext that this object runs in.
* Normally this call will be used to initialize the object.
* <p>Invoked after population of normal bean properties but before an init callback such
* as {@link org.springframework.beans.factory.InitializingBean#afterPropertiesSet()}
* or a custom init-method. Invoked after {@link ResourceLoaderAware#setResourceLoader},
* {@link ApplicationEventPublisherAware#setApplicationEventPublisher} and
* {@link MessageSourceAware}, if applicable.
* @param applicationContext the ApplicationContext object to be used by this object
* @throws ApplicationContextException in case of context initialization errors
* @throws BeansException if thrown by application context methods
* @see org.springframework.beans.factory.BeanInitializationException
*/
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
它是一个回调函数,在Bean中通过实现这个函数,可以在容器回调该aware接口方法时使注入的applicationContext引用在Bean中保存下来,供Bean需要使用ApplicationContext的基本服务时使用。这个对setApplicationContext方法的回调是由容器自动完成的。可以看到,一个ApplicationContextAwareProcessor作为BeanPostProcessor的实现,对一系列的aware回调进行了调用,比如对ResourceLoaderAware接口的盗用,对ApplicationEventPublisherAware接口的调用,以及对MessageSourceAware和ApplicationContextAware的接口调用等。
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){
return bean;
}
AccessControlContext acc = null;
if (System.getSecurityManager() != null) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}
if (acc != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareInterfaces(bean);
return null;
}, acc);
}
else {
invokeAwareInterfaces(bean);
}
return bean;
}
作为依赖注入的一部分,postProcessBeforeInitialzation会在initilizeBean的实现过程中被调用,从而实现对aware接口的相关注入。