1. 程式人生 > 其它 >談談Spring的ApplicationContextAware介面

談談Spring的ApplicationContextAware介面

談談Spring的ApplicationContextAware介面

現象:

​ 我們寫一個類,實現ApplicationContextAware介面,類上再加一個@Component後,執行專案,你會發現在我們實現的setApplicationContext會傳進來Spring的ApplicationContext。

@Component
public class TestMyBeanPostProcess implements ApplicationContextAware {
	
	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		/* 此處將會傳進來ApplicationContext */
	}
}

為什麼?

對於應用方面,我們只需要知道實現此介面再@Component即可,但我相信你還是比較喜歡知道Spring具體怎麼做的。

原始碼檢視

首先:

// 建立AnnotationConfigApplicationContext,傳入AppConfig.class配置類
new AnnotationConfigApplicationContext(AppConfig.class);
// AppConfig.class中程式碼如下:
@Configuration
@ComponentScan("com.dh")
public class AppConfig {
}

進入到AnnotationConfigApplicationContext的建構函式中:

	/**
	 * Create a new AnnotationConfigApplicationContext, deriving bean definitions
	 * from the given annotated classes and automatically refreshing the context.
	 * @param annotatedClasses one or more annotated classes,
	 * e.g. {@link Configuration @Configuration} classes
	 */
	public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
		this();
		register(annotatedClasses);
		refresh();
	}
// 這裡面第一行程式碼this():
	public AnnotationConfigApplicationContext() {
		this.reader = new AnnotatedBeanDefinitionReader(this);
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}
// 這裡乾的事情我們忽略不計,就是設定一個reader和scanner,分別對應這兩個類:AnnotatedBeanDefinitionReader reader;ClassPathBeanDefinitionScanner scanner;這兩個類做的什麼事情也不要去多想,這不是這次的重點(涉及到Spring的Bean資訊掃描和讀取)。
// 再看下一行register(annotatedClasses);
// 這裡面實際上做的事情就是將我們傳入的AppConfig.class解析資訊,包括帶的註解等其他資訊,然後封裝到BeanDefinition中然後存入到beanNameList和BeanDefinitionList中。

重要的第三行“refresh()”呼叫的方法:

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.,準備提前工作
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.,獲取BeanFactory
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.本次的重點程式碼
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				onRefresh();

				// Check for listener beans and register them.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}

prepareBeanFactory()為重點的程式碼:

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		// Tell the internal bean factory to use the context's class loader etc.
		// 設定classLoader以及其他一些物件
		beanFactory.setBeanClassLoader(getClassLoader());
		beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
		beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

		// Configure the bean factory with context callbacks.
		// 
		beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
		beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
		beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
		beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
		beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

		// BeanFactory interface not registered as resolvable type in a plain factory.
		// MessageSource registered (and found for autowiring) as a bean.
		beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
		beanFactory.registerResolvableDependency(ResourceLoader.class, this);
		beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
		beanFactory.registerResolvableDependency(ApplicationContext.class, this);

		// Register early post-processor for detecting inner beans as ApplicationListeners.
		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

		// Detect a LoadTimeWeaver and prepare for weaving, if found.
		if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			// Set a temporary ClassLoader for type matching.
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}

		// Register default environment beans.
		if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
			beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
			beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
			beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
		}
	}
// 注意看這一行:beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)):

從這一行程式碼很簡單,但不簡單的是ApplicationContextAwareProcessor和BeanPostProcessor。

BeanPostProcessor:

​ 是一個可以讓我們干預Bean例項化的介面,當我們實現此介面並重寫裡面的postProcessBeforeInitialization、postProcessAfterInitialization方法的後,每個Bean例項化完成後都會呼叫這兩個方法,那麼當有多個類實現了BeanPostProcessor的時候,如果想指定BeanPostProcessor被呼叫的順序的話,需要實現此介面:PriorityOrdered,此介面的返回值越小執行的順序越靠前。BeanPostProcessor此擴充套件介面可以使我們干預Bean的例項化過程,例如實現AOP等功能,例如我們注入一個A類,裡面有一個a方法,然後我們實現BeanPostProcessor介面的類當中postProcessBeforeInitialization方法裡面會傳入這個例項化後的A類,我們在這方法裡面使用任意動態代理方法來對其進行代理,再將代理後得到的類return回去,此時Spring容器中的A類就是我們返回的已經代理過後的類,這樣就實現了AOP的操作,當然其他的大部分功能都可以使用BeanPostProcessor來進行實現,Spring預設提供了50個以上的BeanPostProcessor,其中包含引數校驗、aop的功能。總結一下:BeanPostProcessor是Spring給我們提供的擴充套件介面,此擴充套件介面可以讓我們干預Bean的例項化過程已達到某些功能,當然擴充套件點肯定不止BeanPostProcessor一個,還有大約4個左右,例如BeanFactoryPostProcessor等。

ApplicationContextAwareProcessor:

/**
 * 此PostProcessor中包含很多回調方法,例如拿到Application,拿到Environment,然後通過介面的方法設定回去

 */
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
	@Nullable
	public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
		AccessControlContext acc = null;
		/* 在這裡判斷當前的bean是否實現我們需要操作的介面,如果有的話,那麼設定acc */
		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((PrivilegedAction<Object>) () -> {
				invokeAwareInterfaces(bean);
				return null;
			}, acc);
		}
		else {
			/* 如果acc不為空,則去挨個判斷實現的介面,然後去其進行回撥 */
			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(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;
	}

}

​ 進入到這個類裡面來以後會發現,它實現了BeanPostProcessor介面,並重寫了我們上面提到的兩個方法:postProcessBeforeInitialization,postProcessAfterInitialization。重點看postProcessBeforeInitialization,在這裡面先是一堆判斷,這些判斷我們不關心,看invokeAwareInterfaces(bean),這一行方法呼叫。

​ 在這個方法裡面判斷當前類是否實現了EnvironmentAware介面,如果實現了則強轉後將Environmentset過去,後續if中都是相同的道理,只是介面不同,此時我們就能發現最後裡面就是我們文章標題裡面寫的ApplicationContextAware介面,那麼看到這裡你是不是有點明白了。對,就是你想的那樣。