bean的生命周期分析(三)

二、全流程梳理

2.6 创建bean

2.6.1 createBean

@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
	if (logger.isDebugEnabled()) {
		logger.debug("Creating instance of bean '" + beanName + "'");
	}
	RootBeanDefinition mbdToUse = mbd;

	// Make sure bean class is actually resolved at this point, and
	// clone the bean definition in case of a dynamically resolved Class
	// which cannot be stored in the shared merged bean definition.
	// 解析bean 详见2.6.2
	Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
	if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
		mbdToUse = new RootBeanDefinition(mbd);
		mbdToUse.setBeanClass(resolvedClass);
	}

	// Prepare method overrides.
	try {
		// 提前标记下需要覆盖的方法。对于prepareMethodOverrides方法,前面我们在BeanDefinition注册到Spring容器时已经讲解过了,如果bean标签中配置了属性lookup-method以及属性replaced-method的值,这就意味着bean中的某些方法就需要被覆写了。原文链接:https://blog.csdn.net/qq_35873436/article/details/123536404
		// 详见2.6.3
		mbdToUse.prepareMethodOverrides();
	}
	catch (BeanDefinitionValidationException ex) {
		throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
				beanName, "Validation of method overrides failed", ex);
	}

	try {
		// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
		// 详见2.6.4
		Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
		if (bean != null) {
			return bean;
		}
	}
	catch (Throwable ex) {
		throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
				"BeanPostProcessor before instantiation of bean failed", ex);
	}

	// 详见下一篇博客,do开头,是要干实事了。
	Object beanInstance = doCreateBean(beanName, mbdToUse, args);
	if (logger.isDebugEnabled()) {
		logger.debug("Finished creating instance of bean '" + beanName + "'");
	}
	return beanInstance;
}

2.6.2 resolveBeanClass

protected Class<?> resolveBeanClass(final RootBeanDefinition mbd, String beanName, final Class<?>... typesToMatch)
			throws CannotLoadBeanClassException {
	try {
		// 是否存在bean类,是就直接返回。
		// 因为注册bean的时候该bean对应的类应当已经被类加载机制加载到jvm了,否则才进行下面的步骤
		if (mbd.hasBeanClass()) {
			return mbd.getBeanClass();
		}
		if (System.getSecurityManager() != null) {
			return AccessController.doPrivileged(new PrivilegedExceptionAction<Class<?>>() {
				@Override
				public Class<?> run() throws Exception {
					return doResolveBeanClass(mbd, typesToMatch);
				}
			}, getAccessControlContext());
		}
		else {
			// 做解析Bean类操作
			return doResolveBeanClass(mbd, typesToMatch);
		}
	}
	catch (PrivilegedActionException pae) {
		ClassNotFoundException ex = (ClassNotFoundException) pae.getException();
		throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
	}
	catch (ClassNotFoundException ex) {
		throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
	}
	catch (LinkageError ex) {
		throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
	}
}

下面是doResolveBeanClass的源码,由于bean的类没有加载到jvm,下面执行bean的类解析操作。

private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch)
			throws ClassNotFoundException {
	// 获取类加载器
	ClassLoader beanClassLoader = getBeanClassLoader();
	// 动态类加载器
	ClassLoader classLoaderToUse = beanClassLoader;
	if (!ObjectUtils.isEmpty(typesToMatch)) {
		// When just doing type checks (i.e. not creating an actual instance yet),
		// use the specified temporary class loader (e.g. in a weaving scenario).
		ClassLoader tempClassLoader = getTempClassLoader();
		if (tempClassLoader != null) {
			classLoaderToUse = tempClassLoader;
			if (tempClassLoader instanceof DecoratingClassLoader) {
				DecoratingClassLoader dcl = (DecoratingClassLoader) tempClassLoader;
				for (Class<?> typeToMatch : typesToMatch) {
					dcl.excludeClass(typeToMatch.getName());
				}
			}
		}
	}
	// 获取全类名
	String className = mbd.getBeanClassName();
	if (className != null) {
		Object evaluated = evaluateBeanDefinitionString(className, mbd);
		if (!className.equals(evaluated)) {
			// A dynamically resolved expression, supported as of 4.2...
			if (evaluated instanceof Class) {
				return (Class<?>) evaluated;
			}
			else if (evaluated instanceof String) {
				return ClassUtils.forName((String) evaluated, classLoaderToUse);
			}
			else {
				throw new IllegalStateException("Invalid class name expression result: " + evaluated);
			}
		}
		// When resolving against a temporary class loader, exit early in order
		// to avoid storing the resolved Class in the bean definition.
		if (classLoaderToUse != beanClassLoader) {
			// 内部 使用了 Class.forName() 去加载这个类
			return ClassUtils.forName(className, classLoaderToUse);
		}
	}
	// 如果连beanName都没有那就走下面的方法去解析
	return mbd.resolveBeanClass(beanClassLoader);
}
public Class<?> resolveBeanClass(ClassLoader classLoader) throws ClassNotFoundException {
	String className = getBeanClassName();
	if (className == null) {
		return null;
	}
	Class<?> resolvedClass = ClassUtils.forName(className, classLoader);
	this.beanClass = resolvedClass;
	return resolvedClass;
}

2.6.3 prepareMethodOverrides

  • mbdToUse.prepareMethodOverrides();
    作用是:提前标记下需要覆盖的方法。对于prepareMethodOverrides方法,如果bean标签中配置了属性lookup-method以及属性replaced-method的值,这就意味着bean中的某些方法就需要被覆写了。
  • 举个例子:
    在这里插入图片描述
    在这里插入图片描述
    可以看到User3继承BaseUser,而且实现了抽象方法getUser,同时也重写了方法say。
    我们把User3 配置到xml上面:
    在这里插入图片描述
    在xml中我们将抽象类BaseUser配置上去,同时也给它添加了子标签lookup-method,在lookup-method标签中,指定了抽象方法getUser的实现,以User3中的为准,也就是说,后面在调用BaseUser的getUser方法时,实际上是动态调用User3中的getUser方法。
  • 至于replaced-method这里就不赘述了。
  • 总之,这个方法主要做了这些事情:Spring首先会在bean中找到属性lookup-method以及属性replace-method配置的方法,然后才能覆盖它们对不对?但是,Spring在寻找方法时会担心,万一这些方法还有其他重载的方法该怎么办呢?所以,Spring在寻找方法时,就会根据参数或其他手段去重载方法中匹配寻找,比如一个bean中某个需要覆盖的方法,同时存在多个重载方法,这个寻找匹配的过程是比较耗时的,所以,Spring为了加快在bean中寻找目标方法的速度,我们来看下Spring都做了什么事情:
    在这里插入图片描述
    在prepareMethodOverrides方法中,通过ClassUtils中getMethodCountForName方法,判断bean中相同名称的方法数量,同一个名称的方法就一个,那就证明该方法根本就没有重载方法了。此时,Spring就会提前通过代码mo.setOverloaded(false),设置该方法不需要去重载方法中寻找,到时候要覆盖这个方法时,直接根据方法名称到bean中寻找即可,避免了在重载方法中寻找匹配方法的性能损耗。

2.6.4 resolveBeforeInstantiation

  • 方法上的注释表明,方法会给后置处理器一个机会来返回目标bean实例的代理对象。也就是返回一个代理对象来代替我们将要创建的的目标bean。
  • 当resolveBeforeInstantiation返回不为null的bean后,createBean会直接返回。也就是说,后续的实例化、属性赋值与初始化阶段都不会进行。所以说,这一步,将会给BeanPostProcessor一个返回代理而不是目前bean的机会
  • 默认情况下,BeanDefinition中的属性beforeInstantiationResolved 为null,并且,我们最开始也没有注册任何相关的后处理器,所以方法hasInstantiationAwareBeanPostProcessors返回结果也是false,所以方法resolveBeforeInstantiation直接就returen 返回了。但是为了研究这个方法,我们深入进入,看看里面是怎么返回代理对象的。
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;
}
2.6.4.1 applyBeanPostProcessorsBeforeInstantiation

看到applyBeanPostProcessorsBeforeInstantiation方法

protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
    // 获取注册好的beanPostProcessors
	for (BeanPostProcessor bp : getBeanPostProcessors()) {
		// 如果后置处理器是InstantiationAwareBeanPostProcessor类型的实例
		if (bp instanceof InstantiationAwareBeanPostProcessor) {
			InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
			// 执行后置处理器的前置处理方法。
			Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
			if (result != null) {
				return result;
			}
		}
	}
	return null;
}

通过名称InstantiationAwareBeanPostProcessor 我们可以知道这是一个能够感知到bean实例化的后置处理器,那这个InstantiationAwareBeanPostProcessor又是什么呢?我们看一下:
在这里插入图片描述

  • 这个InstantiationAwareBeanPostProcessor继承了接口BeanPostProcessor,所以InstantiationAwareBeanPostProcessor从本质上来说也是一个bean的后处理器。
  • 而且,InstantiationAwareBeanPostProcessor 在BeanPostProcessor接口基础之上又新增好几个方法。其中,方法postProcessBeforeInstantiation 和 postProcessAfterInstantiation,主要在bean实例化之前和之后,添加一些自定义实例化bean的逻辑,而postProcessProperties 方法主要是为bean的实例化提供一些属性信息。
  • 总的来说,这个BeanPostProcessor是定义初始化bean的操作,而InstantiationAwareBeanPostProcessor是在定义实例化bean的操作,实例化可以理解为是从0 到1 创建一个bean 出来,而初始化可以理解为为bean填充属性赋值等过程。
  • 我们回到之前看到位置:
// 执行后置处理器的前置处理方法。
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);

因为我们是处于bean实例化之前,此时Spring就会调用bean实例化之前的前置处理方法postProcessorBeforeInstantiation,一旦这个方法实例化bean 成功了,Spring 就会直接返回实例化好的bean,而不会走Spring默认实例化bean的逻辑了。所以我们可以完全自定义InstantiationAwareBeanPostProcessor的实现类,在方法postProcessorBeforeInstantiation中定义bean实例化逻辑,这样的话,Spring就会按照我们定义好的逻辑来实例化bean了

  • 所以记住这里,我们可以实现InstantiationAwareBeanPostProcessor接口的postProcessBeforeInstantiation方法来自定义前置逻辑
2.6.4.2 applyBeanPostProcessorsAfterInstantiation
  • 再看下后置处理器的后置方法
    在这里插入图片描述
  • 如果通过前置处理方法applyBeanPostProcessorsBeforeInstantiation得到bean的实例不为空。此时就会调用applyBeanPostProcessorsAfterInitialization。我们到方法applyBeanPostProcessorsAfterInitialization中看下:
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
		throws BeansException {

	Object result = existingBean;
	// 遍历所有后置处理器,执行后置处理器的后置方法
	for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
		result = beanProcessor.postProcessAfterInitialization(result, beanName);
		if (result == null) {
			return result;
		}
	}
	return result;
}

可以看到,逻辑很简单。默认情况下是没有注册后处理器InstantiationAwareBeanPostProcessor的,所以这个逻辑暂时是不会执行的。(现在走的都不是官方的bean逻辑,而是用户自定义的bean实例化逻辑,如果用户参与改造bean了,那么这里才会执行,反之默认情况下一个普通的bean,用户没有改造,那么这些定制逻辑是都不走的,走的是官方默认的bean逻辑。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Spring的Bean生命周期是由Spring容器负责管理的,主要包括以下阶段: 1. 实例化:Spring容器根据配置信息或注解,创建Bean的实例。这一过程一般通过Java反射机制实现。 2. 属性注入:Spring容器将依赖注入到Bean的属性中,可以通过构造函数、Setter方法或者字段注入来实现。 3. 初始化:在Bean实例创建完成后,Spring容器会调用一系列的初始化回调方法。常见的初始化回调方法有`@PostConstruct`注解、`InitializingBean`接口的`afterPropertiesSet()`方法以及自定义的初始化方法。 4. 使用:Bean实例被使用,执行业务逻辑。 5. 销毁:当Bean不再被使用时,Spring容器会调用一系列的销毁回调方法。常见的销毁回调方法有`@PreDestroy`注解、`DisposableBean`接口的`destroy()`方法以及自定义的销毁方法。 下面是一个简化的示例代码,展示了Bean生命周期的常用方法: ```java public class MyBean implements InitializingBean, DisposableBean { private String name; public MyBean() { System.out.println("Bean实例化"); } public void setName(String name) { this.name = name; } @Override public void afterPropertiesSet() throws Exception { System.out.println("初始化回调方法"); } public void doSomething() { System.out.println("执行业务逻辑:" + name); } @Override public void destroy() throws Exception { System.out.println("销毁回调方法"); } } ``` 此外,Spring还提供了更细粒度的扩展点,如BeanPostProcessor接口和BeanFactoryPostProcessor接口,可以在Bean的实例化和初始化过程中进行自定义处理。 以上是一个简单的概述,实际的源码分析涉及到Spring框架的很多细节,包括BeanDefinition、BeanFactory、ApplicationContext等。你可以参考Spring源码来深入了解Bean生命周期的实现细节。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

CtrlZ1

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

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

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

打赏作者

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

抵扣说明:

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

余额充值