目录
二、全流程梳理
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逻辑。)