spring源码 第二个后置处理器方法的使用-推断构造函数

spring一个bean初始化以及销毁的流程中,有九个后置处理器需要执行,这篇博客主要记录第二个后置处理器推断构造函数的后置处理器的源码逻辑

第一个后置处理器的调用

在第一个后置处理器被调用之前,会进行一系列的判断

会先调用第一个后置处理器,判断是否返回了bean,如果返回了bean,且不为null,就直接调用第八个后置处理器,完成bean的代理,然后return了之后,就结束了一个bean的生命周期,也即:一个bean就初始化完成了
第一个后置处理器是:org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation,spring自带的后置处理器,几乎上都是返回的null

第八个后置处理器是:org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization

/**
 * @param beanName
 * @param mbd
 * @return
 * 这里面比较重要的变量:
 *  beforeInstantiationResolved:
 *  isSynthetic():判断当前bean是否是合成bean
 *   synthetic
 *    和spring中的合成类、合成方法、合成属性有关系
 *
 *  这里的意思是:在开始spring生命周期方法之前,先判断是否返回了bean对象,如果返回了,就不再调用bean的生命周期方法
 *   进行判断的前提是:当前bean不是合成类,并且当前spring容器中有InstantiationAwareBeanPostProcessor的实现类
 *   hasInstantiationAwareBeanPostProcessor是在refresh方法中,执行 registerBeanPostProcessors()方法的时候,
 *   会把bean的后置处理器添加到 beanFactory中,添加的时候,会判断当前bean是否是接口的实现类
 */
@Nullable
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) {
   
				bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
				if (bean != null) {
   
					bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
				}
			}
		}
		mbd.beforeInstantiationResolved = (bean != null);
	}
	return bean;
}

第二个后置处理器的调用

首先第二个后置处理器的调用是在这个方法中
这个方法中,主要完成了以下几个操作
1.对bean的访问权限进行判断
2.处理InstanceSupplier
3.处理factoryMethod
4.调用第二个后置处理器,我们姑且可以认为第二个后置处理器是对手动注入的推断,也就是@Autowired注解加在构造函数上的推断,推断出来哪些构造函数可以使用
这里推断出来的可能是一个,也可能是多个
5.如果推断出来有多个可用或者自动注入模型是3,autowire_construc,那就进行二次推断,也即根据:参数类型,推断出来一个最合适的
6.如果不满足第5个条件,就通过无参构造函数,完成bean的初始化
需要注意的是:这个方法只是完成了实例化,我所理解的实例化的意思是:生成一个对象,还没有完成对象的初始化方法回调、动态代理对象的生成等

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
   
	// Make sure bean class is actually resolved at this point.
	Class<?> beanClass = resolveBeanClass(mbd, beanName);

	//mpy 检测一个类的访问权限,spring默认情况下对于非public的类是允许访问的
	if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
   
		throw new BeanCreationException(mbd.getResourceDescription(), beanName,
				"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
	}

	/**
	 * 如果在bean对应的beanDefinition中,设置一个InstanceSupplier,那么,spring就不会调用后面推断构造函数的逻辑
	 */
	Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
	if (instanceSupplier != null) {
   
		return obtainFromSupplier(instanceSupplier, beanName);
	}

	/**
	 * mpy 如果工厂方法不为空,就通过工厂方法构建bean对象
	 * 需要了解什么是factoryMethod
	 *
	 * 如果我们是通过@Bean注解,来注入bean的话,在将bean对象转换成beanDefinition对象时,会设置一个factoryMethod
	 */
	if (mbd.getFactoryMethodName() != null)  {
   
		return instantiateUsingFactoryMethod(beanName, mbd, args);
	}

	// Shortcut when re-creating the same bean...
	/**
	 *
	 * 当多次构建同一个bean的时候,可以使用这个shortcut。
	 * 也就是说,如果第一次解析一个bean,推断出来,后面再来对bean进行推断的时候  就无需再次执行所有代码了
	 * 多次构建同一个bean的话,只有在原型模式下才会调用多次推断构造函数,因为单例方式只会有一个,所以
	 * 下面这个代码我觉得我们可以认为只有在原型模式下,才会走下面从mbd中获取resolvedConstructorOrFactoryMethod的逻辑
	 */
	boolean resolved = false;
	boolean autowireNecessary = false;
	if (args == null) {
   
		synchronized (mbd.constructorArgumentLock) {
   
			//如果bean是prototype,那么第二次获取bean的时候,会从这里来获取
			if (mbd.resolvedConstructorOrFactoryMethod != null) {
   
				resolved = true;
				autowireNecessary = mbd.constructorArgumentsResolved;
			}
		}
	}
	//如果要构造的bean是单实例的,resolved永远是 false
	if (resolved) {
   
		if (autowireNecessary) {
   
			//mpy  通过构造方法自动装配的方式构造bean对象
			return autowireConstructor(beanName, mbd, null, null);
		}
		else {
   
			//mpy 通过默认的无参构造方法构造bean对象
			return instantiateBean(beanName, mbd);
		}
	}

	// Candidate constructors for autowiring?
	/**
	 * mpy 实例化对象里面:第二次调用后置处理器  由后置处理器决定返回哪些构造函数(推断使用哪个构造方法)
	 *  当注入模型为0 的时候 就是autowireMode = 0;无论类中提供了多少个构造函数  这里返回的ctors都是0
	 *
	 *  autowireConstructor()方法确切的说,是从推断出来的构造函数中,选择出一个,判断到底要用哪个来初始化
	 *  	如果没有指定注入模型,推断出来返回了一个或者多个可用的构造函数,也会执行这个方法
	 *  	如果指定了注入模型,即使推断出来的是null(也即使用空参构造函数),也会执行这个方法
	 *
	 *  所以:
	 *  	determineConstructorsFromBeanPostProcessors:可以理解为手动装配的构造函数推断
	 *  	autowireConstructor:可以理解为自动装配的构造函数推断(这样说,也有歧义,如果注入模型是0,但是返回的ctors不是null,也会进到这个方法中)
	 *  因为:determineConstructorsFromBeanPostProcessors在执行之后,推断出来使用空参构造函数、或者使用带参构造函数,如果autowiredMode为3,在autowireConstructor还会推断一次
	 *  autowireConstructor方法中,无论ctors为null还是有值,都会再进行一次推断
	 *
	 *
	 *  根据源码来看,ctors会返回一个或者多个或者返回null的场景,
	 *  	返回一个:要么是加了@Autowired注解且require是true的构造函数 ; 或者是没有@Autowired注解,只有一个构造函数,且入参大于0
	 *  	返回多个是:多个@Autowired注解且require都是false的场景;会返回所有的@Autowired + 无参构造函数(无参构造函数存在就返回,不存在就不返回)
	 *  	返回null:没有@Autowired注解,且没有带参构造函数
	 * 判断条件中的args,一般情况下是null,至于mbd.hasConstructorArgumentValues()这个判断,我还没   * 有搞懂,所以暂时先跳过这个条件的判断
	 */
	Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
	if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
			mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
   
		return autowireConstructor(beanName, mbd, ctors, args);
	}

	// No special handling: simply use no-arg constructor.
	/**
	 * 使用默认的构造函数初始化
	 *
	 * 如果bean的autowireMode为0,且没有在构造方法指定@Autowired注解,表示不自动注入,那么,一定是会执行这里的方法的,也即:通过默认的
	 * 无参构造函数执行
	 */
	return instantiateBean(beanName, mbd);
}
无参构造函数的调用

我们先说最后一行代码instantiateBean(beanName, mbd);这个方法比较简单,就是在第一次推断出来可用的构造函数为null,且自动注入模型不是3的时候,上面注释中我有对后面两个判断条件说明,所以就不再解释

org.springframework.beans.factory.support.SimpleInstantiationStrategy#instantiate(org.springframework.beans.factory.support.RootBeanDefinition, java.lang.String, org.springframework.beans.factory.BeanFactory)

@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
   
	// Don't override the class with CGLIB if no overrides.
	//检测bean中是否配置了lookup-method或replace-method 如果配置了,就需要用CGLIB来构建对象
	if (!bd.hasMethodOverrides()) {
   
		Constructor<?> constructorToUse;
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当然可以,以下是一个简单的例子: ```java import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; public class MyBeanPostProcessor implements BeanPostProcessor { public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("Before initialization of bean " + beanName); return bean; } public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("After initialization of bean " + beanName); return bean; } } ``` 在这个例子中,我们定义了一个名为 MyBeanPostProcessor 的类,它实现了 BeanPostProcessor 接口。这个接口有两个方法:postProcessBeforeInitialization 和 postProcessAfterInitialization,它们分别在 bean 初始化之前和之后被调用。 我们可以在这两个方法中添加我们自己的逻辑,比如在 postProcessBeforeInitialization 中打印出 bean 的名称,或者在 postProcessAfterInitialization 中对 bean 进行一些修改。 要在 Spring使用这个后置处理器,我们需要在配置文件中将它声明为一个 bean: ```xml <bean id="myBeanPostProcessor" class="com.example.MyBeanPostProcessor"/> ``` 然后,我们可以将它应用到我们需要处理的 bean 上: ```xml <bean id="myBean" class="com.example.MyBean" init-method="init"> <property name="name" value="John"/> <property name="age" value="30"/> <property name="address" value="123 Main St."/> <property name="phone" value="555-1234"/> <property name="email" value="john@example.com"/> <property name="salary" value="50000"/> <property name="bonus" value="10000"/> <property name="taxes" value="15000"/> <property name="netSalary" value="45000"/> </bean> <bean class="org.springframework.beans.factory.config.PropertyOverrideConfigurer"> <property name="propertyOverrides"> <props> <prop key="myBean.salary">60000</prop> <prop key="myBean.bonus">12000</prop> <prop key="myBean.taxes">18000</prop> <prop key="myBean.netSalary">54000</prop> </props> </property> </bean> ``` 在这个例子中,我们定义了一个名为 myBean 的 bean,并将它的属性值设置为一些默认值。然后,我们使用 PropertyOverrideConfigurer 将一些属性值覆盖为新的值。 当我们运行这个应用程序时,我们会看到 MyBeanPostProcessor 的两个方法被调用了两次,分别在 myBean 初始化之前和之后。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值