一、解释
InstantiationAwareBeanPostProcessor 是 BeanPostProcessor 的子接口,它添加了实例化之前的回调,以及在实例化之后但设置了显式属性或发生自动装配之前的回调。
这里 首先要区分两个概念,一个是 Instantiation ,一个是 Initialization ,
Instantiation :实例化 ,就是创建Bean 的过程(比如调用构造函数) ,
Initialization :初始化, 就是对Bean 进行赋值(比如调用setter 方法),配置属性的过程.
这里的 InstantiationAwareBeanPostProcessor 就是这个Instantiation 阶段。BeanPostProcessor 就是Initialization 阶段,也可以 从两个接口 里面的 方法 可以看出,BeanPostProcessor 里面的方法是 xxxxBeforeInitialization,
xxxAfterInitialization.
1.1、方法
InstantiationAwareBeanPostProcessor 本身就3个方法,
postProcessAfterInstantiation,postProcessBeforeInstantiation 这两个方法 都比较好理解,就是在实例化之前和之后 进行的一系列操作. 我们需要了解 这两个方法 在 启动时,是在具体哪里运行的(下面有分析),便于我们后续的扩展.
postProcessProperties 这个方法 , 主要是后缀处理通过注解注入属性的, 其实里面还有一个 被抛弃的方法 postProcessPropertyValues 和这个是一样的。postProcessProperties 这个方法还是比较重要的,主要就是处理 通过注解注入属性的一系列操作, 下面也会想想分析的。
//实例化之后的处理
default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return true;
}
//实例化之前的处理
@Nullable
default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
return null;
}
//修改属性值
@Nullable
default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
throws BeansException {
return null;
}
二、demo
2.1 创建一个类继承 InstantiationAwareBeanPostProcessor
主要实现postProcessBeforeInstantiation 这个方法,用于在创建之前的操作 ,和postProcessAfterInitialization 这个方法,用于初始化之后的操作,后面源码会提到这两个方法
public class MyselfIBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
System.out.print("beanName:" + beanName + "执行..postProcessAfterInstantiation");
return true;
}
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if (beanClass == BeanTest.class) {
System.out.println("beanName:" + beanName + "执行..postProcessBeforeInstantiation 方法");
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(beanClass);
enhancer.setCallback(new BeanTestMethodInterceptor());
BeanTest beanTest = (BeanTest) enhancer.create();
return beanTest;
}
return null;
}
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
throws BeansException {
System.out.println("beanName: postProcessProperties 执行..postProcessProperties");
return pvs;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("执行 postProcessAfterInitialization...");
return bean;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("执行..postProcessBeforeInitialization ...");
return bean;
}
}
2.2 创建 一个 BeanTestMethodInterceptor
实现 MethodInterceptor ,对方法进行拦截
public class BeanTestMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
if(method.getName().equalsIgnoreCase("getName")){
System.out.println("调用 getName 方法 ");
}
else if(method.getName().equalsIgnoreCase("setName")){
objects = new Object[]{"被替换掉啦"};
}
Object object = methodProxy.invokeSuper(o, objects);
return object;
}
}
2.2 创建一个BeanTest 类
public class BeanTest {
private String name;
public BeanTest() {
System.out.println("执行构造函数");
}
public BeanTest(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
2.4 创建一个XML文件
在resource下面 创建一个文件applicationContext-Instantion.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="mselfIBeanPostProcessor"
class="com.self.test1.MyselfIBeanPostProcessor"/>
<bean id="bean" class="com.self.test1.BeanTest" />
</beans>
写个Main 方法,测试一下:
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext-Instantion.xml");
BeanTest bean = ctx.getBean("bean", BeanTest.class) ;
bean.setName("原始值");
String name = bean.getName();
System.out.println(name);
}
结果如下: 可以看到 执行了 postProcessBeforeInstantiation 和 postProcessAfterInitialization 这两个方法
beanName:bean执行..postProcessBeforeInstantiation 方法
执行构造函数
执行 postProcessAfterInitialization...
调用 getName 方法
被替换掉啦
三、源码解析
3.1 postProcessAfterInstantiation,postProcessBeforeInstantiation
InstantiationAwareBeanPostProcessor 的方法 postProcessBeforeInstantiation ,从名字就可以看出 在创建Bean 时候调用(而且是 创建之前),具体源码可以定位到 AbstractAutowireCapableBeanFactory#createBean 的 方法里面,部分源码如下,其实逻辑相对简单:
有一个点需要 注意;如果有了代理类,就不走下面的逻辑了,直接返回
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
// 这里便是 提前 给 BeanPostProcessors 返回一个代理类 ,这里便是调用的地方了
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
// 这里也是 关键,如果 bean 不为空,说明有了代理类,就不用走下面的
// doCreateBean 方法了
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
try {
// 如果上面没有代理 类,那就走这里的创建分支
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
// A previously detected exception with proper bean creation context already,
// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
throw ex;
}
具体的resolveBeforeInstantiation 如下:
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// Make sure bean class is actually resolved at this point.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
// 从这里也可以看出 先运行的applyBeanPostProcessorsBeforeInstantiation 方法
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
// 如果不为空,有代理类,那就再运行初始化之后的操作
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
// 进到这里,已经完全OK了,这里就是运行的InstantiationAwareBeanPostProcessor 类的
//postProcessBeforeInstantiation 方法
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
if (result != null) {
return result;
}
}
}
return null;
}
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
// 这里 也是设计得比较好的,这里运行的是 所有的 BeanPostProcessor 的postProcessAfterInitialization 方法
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
3.2 postProcessProperties(重要)
主要分析这个方法, 个人感觉这个方法比 上面两个方法 重(fu)要(za)
3.2.1 postProcessProperties 运行时机
postProcessProperties 方法 运行的 时机 ,主要是 在 填充属性的时候, 就是 AbstractAutowireCapableBeanFactory#populateBean 这个里面 调用的, 主要是在填充属性之前 再进行相关的操作.
InstantiationAwareBeanPostProcessor # postProcessProperties 方法被实现的了也比较多, 这里主要讲两个 :
- CommonAnnotationBeanPostProcessor : 主要 注册带有 @Resource 注解的 属性
- AutowiredAnnotationBeanPostProcessor : 主要解决 带有 @Autowired,@Value,@Lookup,@Inject 注解的属性
3.2.2 CommonAnnotationBeanPostProcessor # postProcessProperties
首先 我们 可以看到,CommonAnnotationBeanPostProcessor 有一个 static 静态块,将需要解析的注解 都先加载进来
接下来主要分析 postProcessProperties 方法
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
/**
这里主要的逻辑 就是 找到 对应的带有注解的Metadata ,然后注入进去
主要逻辑在下面
*/
InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
}
return pvs;
}
分析 findResourceMetadata 类
private InjectionMetadata findResourceMetadata(String beanName, final Class<?> clazz, @Nullable PropertyValues pvs) {
// 用 beanName 作为 缓存的Key ,没有beanName 使用 类名
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// 首先从 缓存里面获取,是否已经存在
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
// needsRefresh 其实就是判断 是否为null ,为null 就重新创建, 这里是一个 double-check
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
// 如果不为null ,先清除一下
if (metadata != null) {
metadata.clear(pvs);
}
// 这里开始创建,并放入缓存,详细在下面分析
metadata = buildResourceMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
分析 buildResourceMetadata 类 ,虽然这个方法代码比较长,其实逻辑 特别简单
就是 对 字段,方法 遍历,看是否带有 @WebServiceRef, @Resource,@EJB 注解 ,如果带有 就对 对应的注解 进行解析, 然后 再就放入list
这里涉及一个 桥接 方法 , 详细见 Spring源码解析之- BridgeMethodResolver详解
private InjectionMetadata buildResourceMetadata(final Class<?> clazz) {
// 这里过滤一下 spring 自己内部类, 像以 java. 开头的, java. 开头的一般都是 jdk自己的 类.
if (!AnnotationUtils.isCandidateClass(clazz, resourceAnnotationTypes)) {
return InjectionMetadata.EMPTY;
}
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
// 首先这里是一个循环, 主要是可能当前类 有继承的情况,需要 迭代对 父类也进行处理
do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
/**
这里 首先是对字段 进行处理
调用了ReflectionUtils, 就是 通过回调 方法,进行 校验判断
如果 field 上面有 @WebServiceRef, @Resource,@EJB 注解 ,就放入list
注意的是,不能放在 静态字段上面,不然报错
*/
ReflectionUtils.doWithLocalFields(targetClass, field -> {
if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@WebServiceRef annotation is not supported on static fields");
}
currElements.add(new WebServiceRefElement(field, field, null));
}
else if (ejbClass != null && field.isAnnotationPresent(ejbClass)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@EJB annotation is not supported on static fields");
}
currElements.add(new EjbRefElement(field, field, null));
}
else if (field.isAnnotationPresent(Resource.class)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static fields");
}
if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
currElements.add(new ResourceElement(field, field, null));
}
}
});
/**
这里 是对方法 进行处理
调用了ReflectionUtils, 就是 通过回调 方法,进行 校验判断
如果 方法 上面有 @WebServiceRef, @Resource,@EJB 注解 ,就放入list
@WebServiceRef 不能修饰static方法 , 方法只能有一个 参数,一般就是 setter 方法,就是一个参数
*/
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (webServiceRefClass != null && bridgedMethod.isAnnotationPresent(webServiceRefClass)) {
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@WebServiceRef annotation is not supported on static methods");
}
if (method.getParameterCount() != 1) {
throw new IllegalStateException("@WebServiceRef annotation requires a single-arg method: " + method);
}
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new WebServiceRefElement(method, bridgedMethod, pd));
}
else if (ejbClass != null && bridgedMethod.isAnnotationPresent(ejbClass)) {
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@EJB annotation is not supported on static methods");
}
if (method.getParameterCount() != 1) {
throw new IllegalStateException("@EJB annotation requires a single-arg method: " + method);
}
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new EjbRefElement(method, bridgedMethod, pd));
}
else if (bridgedMethod.isAnnotationPresent(Resource.class)) {
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static methods");
}
Class<?>[] paramTypes = method.getParameterTypes();
if (paramTypes.length != 1) {
throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method);
}
if (!this.ignoredResourceTypes.contains(paramTypes[0].getName())) {
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new ResourceElement(method, bridgedMethod, pd));
}
}
}
});
/**
这里要注意了, 这里是 后面的插在前面,每次插入都是从 index =0 开始插入
**/
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return InjectionMetadata.forElements(elements, clazz);
}
接下来 InjectionMetadata 的inject 方法 ,这里主要是获取 里面的 InjectedElement 列表 ,然后开始挨个注入
这里 主要是 @Resoure 注解,所以 具体的注解逻辑在ResourceElement ,这里主要逻辑在getResourceToInject 下面 详细分析
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection<InjectedElement> checkedElements = this.checkedElements;
Collection<InjectedElement> elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
// 获取对应的InjectedElement 列表,然后挨个注入
for (InjectedElement element : elementsToIterate) {
if (logger.isTraceEnabled()) {
logger.trace("Processing injected element of bean '" + beanName + "': " + element);
}
element.inject(target, beanName, pvs);
}
}
}
这里就是 最后的开始注入了,首先判断是否 是懒加载, 如果是 给出一个代理, 如果不是, 通过getResource 获取,里面也是调用 BeanFactory.getBean 的一个过程.
@Override
protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) :
getResource(this, requestingBeanName));
}
3.2.3 AutowiredAnnotationBeanPostProcessor # postProcessProperties
上面分析了 CommonAnnotationBeanPostProcessor #postProcessProperties 主要是对 @Resource 注解进行 属性注入,
而 AutowiredAnnotationBeanPostProcessor #postProcessProperties 主要是对 @Autowired, @Value ,@Inject 等注解处理
具体的逻辑 和上面差不都 ,这里就不展开介绍了.
四、总结
InstantiationAwareBeanPostProcessor 主要是 在实例化前后作一些增强性的操作,是在 AbstractAutowireCapableBeanFactory#createBean 里面创建之前被触发调用的 , 而 postProcessProperties 方法是在 填充属性的时候,对一些 注解式属性 进行注入.