spring源码解析之---InstantiationAwareBeanPostProcessor解析

一、解释

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 方法是在 填充属性的时候,对一些 注解式属性 进行注入.

  • 6
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Spring源码解析是指对Spring框架的源代码进行深入分析和解读的过程。Spring框架是一个开源的Java企业级应用程序框架,提供了高度灵活和可扩展的开发环境。 Spring框架的源代码解析涉及了众多的模块和组件,包括核心容器、AOP(面向切面编程)、数据访问、Web开发等。通过对这些模块和组件的源代码进行解析,我们可以更加深入地了解Spring框架的工作原理和设计思想。 Spring源码解析的好处在于,可以帮助我们更好地理解Spring框架的各种功能和特性,并且能够帮助开发人员更加高效地使用和定制Spring框架,解决实际项目开发中的问题。 在进行Spring源码解析时,我们可以关注一些关键的概念和类,比如BeanFactory、ApplicationContext、BeanPostProcessor、AOP代理等。这些核心类和概念是理解Spring框架工作机制的重要基础。 进行Spring源码解析时,我们可以使用一些常见的工具和方法,比如IDE(集成开发环境)的调试功能、查看和分析源代码的注释和文档、调试和运行项目的示例代码等。 通过Spring源码解析,我们可以学到很多有关软件开发的知识和经验,比如面向对象编程、设计模式、依赖注入、控制反转等。这些知识和经验对于我们提升自己的技术水平和解决实际项目中的问题都有很大的帮助。 总之,Spring源码解析是一项非常有价值的学习和研究工作,可以帮助我们更好地理解和应用Spring框架,提高自己的技术能力和软件开发水平。希望以上的回答能够满足您的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一直打铁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值