Spring源码-xxxAware实现类和BeanPostProcessor接口调用过程

xxxAware实现类作用

以ApplicationContextAware接口为例

ApplicationContextAware的作用是可以方便获取Spring容器ApplicationContext,从而可以获取容器内的Bean

java 复制代码
package org.springframework.context;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.Aware;

/**
public interface ApplicationContextAware extends Aware {

	/**
设置该对象运行的ApplicationContext。通常,这个调用将用于初始化对象。
<p>在填充普通bean属性之后调用,但在初始回调之前调用,
例如{@link org.springframework.beans.factory.InitializingBeanafterPropertiesSet()}
或自定义初始化方法。
在{@link ResourceLoaderAwaresetResourceLoader}, 
{@link ApplicationEventPublisherAwaresetApplicationEventPublisher}
和{@link MessageSourceAware}之后调用,如果适用的话。
@param applicationContext这个对象要使用的applicationContext对象
@在context初始化错误的情况下抛出
ApplicationContextException 
@如果被应用程序context方法抛出则抛出BeansException @参见org.springframework.beans.factory.BeanInitializationException
	 */
	void setApplicationContext(ApplicationContext applicationContext) throws BeansException;

}

下面这个例子就是ApplicationContextUtil 实现了ApplicationContextAware 这个接口,重写了setApplicationContext(ApplicationContext applicationContext)方法,在调用到这个方法的时候给类里的applicationContext 属性赋值,后续别的方法在拿到这个applicationContext进行操作,比如根据getBean方法获取Bean对象以及调用beanFactory.registerBeanDefinition(beanName, definition);方法进行添加BeanDefinition即bean的元数据信息。

java 复制代码
public class ApplicationContextUtil implements ApplicationContextAware {
 
  private static ApplicationContext applicationContext = null;
 
  @Override
  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    if (this.applicationContext == null) {
      this.applicationContext = applicationContext;
    }
  }
  
  //获取applicationContext
  public static ApplicationContext getApplicationContext() {
    return applicationContext;
  }
 
  //通过name获取 Bean.
  public static Object getBean(String name) {
    return getApplicationContext().getBean(name);
  }
 
  //通过class获取Bean.
  public static <T> T getBean(Class<T> clazz) {
    return getApplicationContext().getBean(clazz);
  }
  
  /**
     * 同步方法注册bean到ApplicationContext中
     *
     * @param beanName
     * @param clazz
     * @param original bean的属性值
     */
  public static synchronized void setBean(String beanName, Class<?> clazz, Map<String,Object> original) {
    checkApplicationContext();
    DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
    if(beanFactory.containsBean(beanName)){
      return;
    }
    //BeanDefinition beanDefinition = new RootBeanDefinition(clazz);
    GenericBeanDefinition definition = new GenericBeanDefinition();
    //类class
    definition.setBeanClass(clazz);
    //属性赋值
    definition.setPropertyValues(new MutablePropertyValues(original));
    //注册到spring上下文
    beanFactory.registerBeanDefinition(beanName, definition);
  }
  
}

上述是相关使用,为什么实现这个接口就会调用这个set方法,接下来根据spring源码,讲解xxxAware接口的前世今生。

不重要的步骤给出调用链路

java 复制代码
AnnotationConfigApplicationContext## AnnotationConfigApplicationContext(String... basePackages) 构造函数
AbstractApplicationContext##refresh()容器刷新
AbstractApplicationContext##prepareBeanFactory(ConfigurableListableBeanFactory beanFactory)beanFactory的准备工作,对各种属性进行填充

prepareBeanFactory准备工作

java 复制代码
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // 添加beanPostProcessor,ApplicationContextAwareProcessor此类用来完成某些Aware对象的注入
		beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
		// 设置要忽略自动装配的接口,很多同学理解不了为什么此处要对这些接口进行忽略,原因非常简单,这些接口的实现是由容器通过set方法进行注入的,
		// 所以在使用autowire进行注入的时候需要将这些接口进行忽略
		beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
		beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
		beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
		beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
	}

看下ApplicationContextAwareProcessor这个类:

java 复制代码
/**
	 * 接口beanPostProcessor规定的方法,会在bean创建时,实例化后,初始化前,对bean对象应用
	 * @param bean the new bean instance
	 * @param beanName the name of the bean
	 * @return
	 * @throws BeansException
	 */
	@Override
	@Nullable
	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>) () -> {
				// 检测bean上是否实现了某个aware接口,有的话进行相关的调用
				invokeAwareInterfaces(bean);
				return null;
			}, acc);
		}
		else {
			invokeAwareInterfaces(bean);
		}

		return bean;
	}
	
	

在这个类postProcessBeforeInitialization(Object bean, String beanName)这个方法内部会调用invokeAwareInterfaces(Object bean) 这个方法,判断bean的类型是属于哪一个xxxAware接口然后执行对应的setXXX()方法,至此和前边实现ApplicationContextAware接口重写setApplicationContext()方法串起来了,在哪里调用setApplicationContext方法完成。

java 复制代码
/**
	 * 如果某个bean实现了某个aware接口,给指定的bean设置相应的属性值
	 *
	 * @param bean
	 */
	private void invokeAwareInterfaces(Object bean) {
		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);
		}
	}

还有一个问题,ApplicationContextAwareProcessor这个类的postProcessBeforeInitialization(Object bean, String beanName) 方法什么时候在哪里进行调用呢?这个类实现了BeanPostProcessor这个接口

java 复制代码
/**
 * bean的后置处理器接口,在依赖注入的初始化方法前后进行调用
 */
public interface BeanPostProcessor {

	/**
	 * 初始化方法调用前要进行的处理逻辑
	 */
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	/**
	 * 在初始化方法指定后要进行的处理逻辑
	 */
	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

}

接下来看实现了BeanPostProcessor 这个接口的实现类在哪里会被触发调用里面的postProcessBeforeInitialization方法!!!!

通过看调用链路,下面是整个过程是在完成实例化,属性填充,执行初始化的时候在initializeBean方法调用 applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);

applyBeanPostProcessorsBeforeInitialization细节,对实现BeanPostProcessor 的类进行调用postProcessBeforeInitialization这个方法,这里会调用到ApplicationContextAwareProcessor的postProcessBeforeInitialization方法来对invokeAwareInterfaces实现Aware接口的类进行set操作

java 复制代码
	public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
			throws BeansException {

		//初始化返回结果为existingBean
		Object result = existingBean;
		//遍历 该工厂创建的bean的BeanPostProcessors列表
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			// postProcessBeforeInitialization:在任何Bean初始化回调之前(如初始化Bean的afterPropertiesSet或自定义的init方法)
			// 将此BeanPostProcessor 应用到给定的新Bean实例。Bean已经填充了属性值。返回的Bean实例可能时原始Bean的包装器。
			// 默认实现按原样返回给定的 Bean
			Object current = processor.postProcessBeforeInitialization(result, beanName);
			// 如果 current为null
			if (current == null) {
				//直接返回result,中断其后续的BeanPostProcessor处理
				return result;
			}
			//让result引用processor的返回结果,使其经过所有BeanPostProcess对象的后置处理的层层包装
			result = current;
		}
		//返回经过所有BeanPostProcess对象的后置处理的层层包装后的result
		return result;
	}

同时,在完成实例化,属性填充,执行初始化的时候在initializeBean方法调用 applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);将BeanPostProcessors应用到给定的现有Bean实例,调用它们的postProcessAfterInitialization方法。

java 复制代码
@Override
	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {

		//初始化结果对象为result,默认引用existingBean
		Object result = existingBean;
		//遍历该工厂创建的bean的BeanPostProcessors列表
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			//回调BeanPostProcessor#postProcessAfterInitialization来对现有的bean实例进行包装
			Object current = processor.postProcessAfterInitialization(result, beanName);
			//一般processor对不感兴趣的bean会回调直接返回result,使其能继续回调后续的BeanPostProcessor;
			// 但有些processor会返回null来中断其后续的BeanPostProcessor
			// 如果current为null
			if (current == null) {
				//直接返回result,中断其后续的BeanPostProcessor处理
				return result;
			}
			//让result引用processor的返回结果,使其经过所有BeanPostProcess对象的后置处理的层层包装
			result = current;
		}
		//返回经过所有BeanPostProcess对象的后置处理的层层包装后的result
		return result;
	}

至此,BeanPostProcessor接口的调用以及实现xxxAware的类的调用使用处理过程讲解结束

java 复制代码
    初始化方法调用前要进行的处理逻辑
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
	在初始化方法指定后要进行的处理逻辑
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
相关推荐
一只叫煤球的猫9 小时前
写代码很6,面试秒变菜鸟?不卖课,面试官视角走心探讨
前端·后端·面试
bobz96510 小时前
tcp/ip 中的多路复用
后端
bobz96510 小时前
tls ingress 简单记录
后端
皮皮林55111 小时前
IDEA 源码阅读利器,你居然还不会?
java·intellij idea
你的人类朋友11 小时前
什么是OpenSSL
后端·安全·程序员
bobz96511 小时前
mcp 直接操作浏览器
后端
前端小张同学13 小时前
服务器部署 gitlab 占用空间太大怎么办,优化思路。
后端
databook14 小时前
Manim实现闪光轨迹特效
后端·python·动效
武子康14 小时前
大数据-98 Spark 从 DStream 到 Structured Streaming:Spark 实时计算的演进
大数据·后端·spark
该用户已不存在15 小时前
6个值得收藏的.NET ORM 框架
前端·后端·.net