1. 程式人生 > >Spring IOC學習心得之Bean對IOC容器的感知

Spring IOC學習心得之Bean對IOC容器的感知

容器管理的Bean一般不需要了解容器的狀態和直接使用Bean,但是在某些情況下,是需要在Bean中直接對IOC容器進行操作的,這時候,就需要在Bean中設定對容器的感知。Spring IOC也提供了該功能,它是通過特定的aware介面來完成的。aware介面有如下這些:

BeanNameAware:可以在Bean中得到它在IOC容器中的Bean的例項名稱

BeanFactoryAware:可以在Bean中得到Bean所在的IOC容器,從而直接在Bean中使用IOC容器的服務

ApplicationContextAware:可以在Bean中得到Bean所在的應用上下文,從而直接在Bean中使用應用上下文的服務

MessageSourceAware:在Bean中可以得到訊息源

ApplicationEventPublisherAware:在Bean中可以得到應用上下文的事件釋出器,從而可以在Bean中釋出應用上下文的事件

ResourceLoaderAware:在Bean中可以得到resourceloader,從而在Bean中使用ResourceLoader載入外部對應的Resource資源

要在自定義的Bean中獲取上述資源,只需要讓Bean實現對應的介面,並覆寫set方法,如下:

public class TestSpring implements ApplicationContextAware{
    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

這樣這個Bean實現了ApplicationContextAware介面,並覆寫setApplicationContext方法,就可以獲取到ApplicationContext物件。

這個setApplicationContext方法的回撥是容器自動完成的,容器呼叫該方法的時候,我們就可以將容器傳入的引數applicationContext儲存起來以供使用

setApplicationContext方法被容器的自動呼叫是在BeanPostProcessor介面的方法postProcessBeforeInitialization中完成的,實現是在ApplicationContextAwareProcessor類中,具體程式碼如下:

class ApplicationContextAwareProcessor implements BeanPostProcessor {

	private final ConfigurableApplicationContext applicationContext;

	private final StringValueResolver embeddedValueResolver;


	/**
	 * Create a new ApplicationContextAwareProcessor for the given context.
	 */
	public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
		this.applicationContext = applicationContext;
		this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
	}


	@Override
	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;
	}
//這裡就是容器自動呼叫set方法的地方,其實就是呼叫自定義的TestSpring類實現的setApplicationContext方法,這樣TestSpring類就獲取到了applicationContext
	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(this.embeddedValueResolver);
			}
			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);
			}
		}
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) {
		return bean;
	}

}