茅塞顿开:Spring Aware原理解析

问题

为什么被Spring管理的类。只要实现了Aware接口。Spring就会自动把对应的对象注入进来。这个bean如果想要使用直接使用就可以了。如下: Spring会自动把ApplicationContext注入到AwareTest这个bean里面。

public class AwareTest implements ApplicationContextAware {public ApplicationContext applicationContext;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}public void checkAware(){if(applicationContext != null){System.out.println("ApplicationContext inject success");}}
}

源码解析:

1. 我们都知道在AbstractApplicationContext里面真正的启动ApplicationContext的函数是refresh()方法。具体的方法如下

public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing.prepareRefresh();// Tell the subclass to refresh the internal bean factory.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();}}}

2. 可以看到有一个prepareBeanFactory的方法,我们再往里面看一下这个方法里面究竟有什么。可以发现给BeanFactory添加了一个BeanPostProcessor。名字是ApplicationContextAwareProcessor 

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {// Tell the internal bean factory to use the context's class loader etc.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);... 多余的代码不贴出来了}

3. BeanPostProcessor这个接口我们都很熟悉了。我们看一下这个里面PostProcessBeforeInitialization()函数。传入bean和beanName。最后是调用了invokeAwareInterfaces(bean)这个函数。如果bean 是aware类的子类。那么就调用bean的set方法将ApplicationContext塞到bean里面。然后业务代码在需要使用ApplicationContext的时候就可以直接使用了。因为已经被set进来了。
 

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((PrivilegedAction) () -> {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(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);}}} 

4. 我们再来看一下。Spring是什么时候调用了BeanPostProcessor的postProcessBeforeInitialization函数的。在AbstractAutowireCapableBeanFactory的initializeBean方法里面 , 在调用InvokeInitMethods的方法之前。先执行了applyBeanPost

ProcessorBeforeInitialization的方法。这个方法里面就是将所有的BeanPostProcessor的的postProcessBeforeInitialization()都执行一遍。包括之前创建的ApplicationContextAwareProcessor。于是ApplicationContextAwareProcessor这个时刻就将ApplicationContext注入到我们的Bean里面了。

	protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction) () -> {invokeAwareMethods(beanName, bean);return null;}, getAccessControlContext());}else {invokeAwareMethods(beanName, bean);}Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}try {invokeInitMethods(beanName, wrappedBean, mbd);}catch (Throwable ex) {throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null),beanName, "Invocation of init method failed", ex);}if (mbd == null || !mbd.isSynthetic()) {wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean;} 

上面是跟着源码走了一遍。我看完之后的理解就是。Spring在整个设计上对于这种松耦合和可插拔真是做了非常多的工作。可以说Spring 本身的ioc的代码并不复杂。大量的代码工作都是为了方便开发者自己去拓展Spring的边界。让开发者可以更好的去控制和管理bean这个对象。Spring的代码建议多读几遍。虽然每一遍读起来都很痛苦。但是每一次读都会有新的感受。
 


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章