「这是我参与11月更文挑战的第17天,活动详情查看:2021最后一次更文挑战」
1.前言
本文主要讲解 protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException 方法。 这个方法的作用就是:创建bean实列,填充bean实例,执行该bean的 后置处理器(post-processors)
2. createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
接下来我们跟着源码看看详细过程
这里首先定义一个 mbdToUse 变量用作mbd 的副本
2.1 resolveBeanClass(mbd, beanName);
这个方法主要作用是:解析beanName 对应的类型 并返回。如:com.lcx.serviece.TestServiceImpl
1.首先判断 mbd.beanClass 是否属于 Class,若属于则直接返回 mbd.beanClass.
2.判断当前系统安全策略管理器是否为null,若不为null,则给里面代码一个特权,绕过权限检查。
3.这里的核心主要是调用 doResolveBeanClass(mbd, typesToMatch)
2.1.1 doResolveBeanClass(mbd, typesToMatch)
private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch)
throws ClassNotFoundException {
// 获取当前容器的类加载器
ClassLoader beanClassLoader = getBeanClassLoader();
// 创建一份副本
ClassLoader dynamicLoader = beanClassLoader;
// 表示mdb的配置的bean类名需要重新被dynameicLoader加载的标记,默认不需要
boolean freshResolve = false;
//当传过来的 类型 typesToMatch 不为null时
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) {
//临时类型加载器 不为null 时,把它赋给 dynamicLoader
dynamicLoader = tempClassLoader;
freshResolve = true;
//如果tempClassLoader 是 DecoratingClassLoader 的基类
if (tempClassLoader instanceof DecoratingClassLoader) {
// 类型转换 把tempClassLoader 转成DecoratingClassLoader(装饰类加载器)
DecoratingClassLoader dcl = (DecoratingClassLoader) tempClassLoader;
// 在dcl中排除 typesToMatch中包含的类型
for (Class<?> typeToMatch : typesToMatch) {
dcl.excludeClass(typeToMatch.getName());
}
}
}
}
// 返回当前bean 的 类名 ,源代码见图2.1
String className = mbd.getBeanClassName();
if (className != null) {
// 评估BeanDefinition 中包含的className,如果className 是可解析的表达式,会对其解析,否则直接返回 源码见图 2.2
Object evaluated = evaluateBeanDefinitionString(className, mbd);
// 如果它两不一样则说明 className 是可解析的字符串。
if (!className.equals(evaluated)) {
// A dynamically resolved expression, supported as of 4.2...
// 如果解析后的 evaluated 是 Class类型的实例
if (evaluated instanceof Class) {
// 则可以直接返回
return (Class<?>) evaluated;
}
else if (evaluated instanceof String) {
// 如果它是String 类型,则把它赋给 className
className = (String) evaluated;
freshResolve = true;
}
else {
throw new IllegalStateException("Invalid class name expression result: " + evaluated);
}
}
// 当freshResolve == true 表示它需要被 dynamicLoader 重新加载时 进入
if (freshResolve) {
// When resolving against a temporary class loader, exit early in order
// to avoid storing the resolved Class in the bean definition.
if (dynamicLoader != null) {
try {
// 返回类加载器,重新加载后的对象 源码见图 2.3
return dynamicLoader.loadClass(className);
}
catch (ClassNotFoundException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Could not load class [" + className + "] from " + dynamicLoader + ": " + ex);
}
}
}
// dynamicLoader 加载失败,则会调用 下面这个方法重新加载
return ClassUtils.forName(className, dynamicLoader);
}
}
// Resolve regularly, caching the result in the BeanDefinition...
// 定期解析,将结果缓存在 BeanDefinition 中
// 这里也是通过 beanClassLoader 解析 该BeanDefinition 中 定义的 class,最后将结果保存在 beanClass中,下次可通过getBeanClass() 方法直接获取
return mbd.resolveBeanClass(beanClassLoader);
}
图2.1:
这里看见它会先直接取出 当前bean 对应的 beanDefinition 的 beanClass,如果它是一个 Class 的实例,则调用它的getName() 方法返回,否则直接把它转成字符串 返回。这里如果 beanClass 为null 后续调用 mbd.resolveBeanClass(beanClassLoader) 就会把结果缓存到 beanClass 中去。
图2.2:
这里面主要讲的 SPEL 表达式的解析,具体内容我给它单独放了一篇文章,感兴趣的可以看看。
图2.3:这里主要就是加载这个类(双亲委派机制)
- 首先它会检查这个类有没有加载,如果没有加载,它会获取父类加载器,当父类加载器不为null时,调用父类加载器的加载方法,若父类加载器为null,则获取系统类加载器,来加载该类。如果还是没有加载到则一层层向下加载。
- 加载完成后 如果需要解析该类,则解析一下 返回 这里比较重要后续有时间的话,可以再详细讲讲 类加载器。
ClassUtils.forName(className, dynamicLoader) : 这个方法主要是Spring 用来替换 Class.forName()的方法,主要作用也是加载类,后面有时间我会在详细的讲下。
2.2
这里主要判断,当上一步解析的 resolvedClass 不为null,且 mbd的beanClass 不是Class 类型,且它的beanClass 不为null。
就会克隆一份 mbd 的副本,取代mbd后续的操作,设置mbdToUse的beanClass.
2.3 mbdToUse.prepareMethodOverrides()
这个方法的主要作用就是验证 准备方法重写,源码如下:
- 首先检查 当前 beanDefinition 的 methodOverrides 是不是null
- 若不为null,取出当前 methodOverrides 中所有的 methodOverride 遍历调用 prepareMethodOverride() 方法。
- prepareMethodOverride(),源码如下:
- 首先统计指定类中匹配该方法名称的方法个数,包括非public方法,因为已经进来了,所以它匹配的方法数不可能为0,当它为0时 抛出异常,当它为1时,说明它是重写的方法,不可能包含重载,这里将覆盖标记为未重载,以避免arg类型检查的开销。
- getMethodCountForName 方法:
- 现获取 clazz 的所有方法,拿着他们的名字和 methodName 对比 如果相同则 count++;
- 获取clazz 所实现的所有接口,遍历每一个接口,递归调用当前方法, count = count+递归的返回值
- 获取 clazz 的父类,接着递归调用当前方法,count = count+递归的返回值
- 返回count
2.4 resolveBeforeInstantiation(beanName, mbdToUse)
这里它的作用就是:让BeanPostProcessors有机会返回一个代理而不是目标bean实例。 如果能拿到代理对象就直接返回,否则就调用下面的 doCreateBean(beanName, mbdToUse, args)
- 首先判断 是否被解析过了 默认false
- mbd.isSynthetic(): 返回当前bean definition 是否是合成的
- hasInstantiationAwareBeanPostProcessors(): 返回此工厂是否拥有实例化WareBeanPostProcessor
- determineTargetType方法:确定 bean definition 定义的目标类型 源码如下:
- 如果targetType 不为 null 时 调用 applyBeanPostProcessorsBeforeInstantiation(targetType, beanName) 获取 bean,若bean 不为null 接着调用 applyBeanPostProcessorsAfterInitialization(bean, beanName)。
- 如果bean 不为null 说明 他已经被解析过了,mbd.beforeInstantiationResolved 置为 true。直接返回result。
1. applyBeanPostProcessorsBeforeInstantiation(targetType, beanName)
- 拿到当前容器的 beanPostProcessors 进行遍历。
- 判断 如果该 BeanPostProcessor 是 InstantiationAwareBeanPostProcessor 的实例,则调用postProcessBeforeInstantiation 方法。
- postProcessBeforeInstantiation 方法:用于在 Bean 实例化之前调用。如果该方法返回的值不为空的话,则直接将该对象作为创建的 bean 返回给 spring 容器。
2. applyBeanPostProcessorsAfterInitialization(bean, beanName)
- 先拿到当前容器的 beanPostProcessors 进行遍历
- 遍历执行它们的 postProcessAfterInitialization 方法。若返回值为null 直接返回result,否则把 生成的 current 赋给 result.
- postProcessAfterInitialization 方法:在bean 实例化后调用,通常用于给bean设置属性信息,如果返回值不为null,一直往后调用 BeanPostProcessor#postProcessAfterInitialization ,一旦返回null,则直接返回 result
2.5 doCreateBean(beanName, mbdToUse, args);
执行了前面四步,仍旧没有返回,就会调用这个方法,它的主要作用:真正创建指定bean的代码,不过在这之前,它需要完成预创建处理 比如:检查{@code postProcessBeforeInstantiation}回调。 这个方法设计到创建bean的具体细节,本篇文章讲不完,后续我会单独来讲。