Spring源码(六)-创建Bean流程-createBean

简介: createBean 方法总体可以分为四个小方法。

createBean 方法总体可以分为四个小方法:

  • resolveBeanClass:加载 Class 对象
  • prepareMethodOverrides:对通过 XML 定义的 bean 中的lookup-methodreplace-method属性进行预处理
  • resolveBeforeInstantiation:实例化前应用后处理器
  • doCreateBean:创建 Bean

接下来就一个一个来看吧!

resolveBeanClass

首先调试进入AbstractAutowireCapableBeanFactory类的createBean

    @Override
    protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
            throws BeanCreationException {

        if (logger.isTraceEnabled()) {
            logger.trace("Creating instance of bean '" + beanName + "'");
        }
        RootBeanDefinition mbdToUse = mbd;

        // 使用类加载器根据 class 或者根据 className 来加载 Class
        Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
        }
      //省略代码...
}

进入AbstractBeanFactory类中的resolveBeanClass方法,注意typesToMatch的类型可能为FactoryBean.classtypesToMatch是一个可变参数。自己再DeBug的时候可以找找resolveBeanClass方法在哪些地方被调用。

@Nullable
    protected Class<?> resolveBeanClass(final RootBeanDefinition mbd, String beanName, final Class<?>... typesToMatch)
            throws CannotLoadBeanClassException {
        //BeanDefintion是在扫描的时候创建的,
        //但是AbstractBeanDefinition中存在一个beanClass属性
        try {
            // 如果beanClass是Class,就直接返回beanClass
            if (mbd.hasBeanClass()) {
                return mbd.getBeanClass();
            }
            //忽略
            if (System.getSecurityManager() != null) {
                return AccessController.doPrivileged((PrivilegedExceptionAction<Class<?>>) () ->
                    doResolveBeanClass(mbd, typesToMatch), getAccessControlContext());
            }
            else {
                // 加载AbstractBeanDefinition中beanClass中所指定的类名对应的类
                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 err) {
            throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), err);
        }
    }

进入 AbstractBeanFactory类中的doResolveBeanClass方法

@Nullable
    private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch)
            throws ClassNotFoundException {
        // 拿到类加载器
        ClassLoader beanClassLoader = getBeanClassLoader();
        ClassLoader dynamicLoader = beanClassLoader;
        boolean freshResolve = false;

        if (!ObjectUtils.isEmpty(typesToMatch)) {
            ClassLoader tempClassLoader = getTempClassLoader();
            if (tempClassLoader != null) {
                dynamicLoader = tempClassLoader;
                freshResolve = true;
                if (tempClassLoader instanceof DecoratingClassLoader) {
                    DecoratingClassLoader dcl = (DecoratingClassLoader) tempClassLoader;
                    for (Class<?> typeToMatch : typesToMatch) {
                        dcl.excludeClass(typeToMatch.getName());
                    }
                }
            }
        }

        // 获取BeanDefinition中所指定的beanClass属性的值,
        String className = mbd.getBeanClassName(); // 字符串 或者 #{xxx}
        if (className != null) {
            // className可以是Spring EL表达式,所以需要解析
            Object evaluated = evaluateBeanDefinitionString(className, mbd);
            // 如果 className 是Spring EL表达式,className 与 evaluated 会不相等的
            if (!className.equals(evaluated)) {
                // evaluated 类型是Class 直接返回
                if (evaluated instanceof Class) {
                    return (Class<?>) evaluated;
                }
                // evaluated 类型是String 将 freshResolve 的值设置为 true
                else if (evaluated instanceof String) {
                    className = (String) evaluated;
                    freshResolve = true;
                }
                else {
                    throw new IllegalStateException("Invalid class name expression result: " + evaluated);
                }
            }
            if (freshResolve) {
                if (dynamicLoader != null) {
                    try {
                        // 使用类加载器加载类
                        return dynamicLoader.loadClass(className);
                    }
                    catch (ClassNotFoundException ex) {
                        if (logger.isTraceEnabled()) {
                            logger.trace("Could not load class [" + className + "] from " + dynamicLoader + ": " + ex);
                        }
                    }
                }
                // 反射工具类加载Class对象
                return ClassUtils.forName(className, dynamicLoader);
            }
        }

        // 反射工具类加载Class对象
        return mbd.resolveBeanClass(beanClassLoader);
    }

resolveBeanClass 方法就是通过来判断 AbstractBeanDefinition 类中的 beanClass 属性,如果是 Class 就直接返回,如果不是就获取 beanClass 属性的值并将它转换为 Stirng 类型,然后对 className 做表达式解析。最后通过dynamicLoader.loadClass(className)加载 Class 对象,或者通过ClassUtils.forName(className, classLoader)加载 Class 对象。

prepareMethodOverrides

对通过XML定义的bean中的lookup-method和replace-method属性进行预处理

    try {
            // 对通过XML定义的bean中的lookup-method和replace-method方法进行预处理
            // 对于@Lookup注解标注的方法不在这里进行处理
            mbdToUse.prepareMethodOverrides();
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
                    beanName, "Validation of method overrides failed", ex);
        }

进入AbstractBeanDefinition类的prepareMethodOverrides方法

public void prepareMethodOverrides() throws BeanDefinitionValidationException {
        // Check that lookup methods exist and determine their overloaded status.
        //检查是否存在查找方法,并确定其重载状态。
        if (hasMethodOverrides()) {
            getMethodOverrides().getOverrides().forEach(this::prepareMethodOverride);
        }
    }

进入AbstractBeanDefinition类的prepareMethodOverride方法

protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
        // 获取对应本类、父类、父接口中对应方法的个数
        int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
        if (count == 0) {
            throw new BeanDefinitionValidationException(
                    "Invalid method override: no method with name '" + mo.getMethodName() +
                    "' on class [" + getBeanClassName() + "]");
        }
        else if (count == 1) {
            //标记 overloaded 暂未被被盖 避免参数类型检查的开销
            mo.setOverloaded(false);
        }
    }

该方法主要针对lookup-methodreplace-method做预处理,现在这两个属性用得比较少了。如果对这两个属性有兴趣,可以在 Spring 的官网进行查看: 点我前往
也可以移步前往: Spring源码(二—2)-lookup-method、replaced-method元素

resolveBeforeInstantiation

    try {
            // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
            // 1、实例化前
            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);
        }

注意上面方法中有个if判断块,当经过前置处理后返回的结果如果不为空,那么会直接略过后续 bean 的创建而直接返回结果。当前 Bean 的创建流程结束,不会再往下执行 doCreateBean 函数。

进入 AbstractAutowireCapableBeanFactory类的resolveBeforeInstantiation方法

@Nullable
    protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
        Object bean = null;
        // beforeInstantiationResolved的值只会为null或true
        if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
            if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
                // 返回 Class 对象
                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;
    }

上述重点逻辑为如果实例化前方法返回的对象不为 null,则执行初始化后方法,并将经过初始后流程的Bean对象返回。

我们先来进入 AbstractAutowireCapableBeanFactory类的determineTargetType方法,该方法就是将 Class 对象加载出来。

    @Nullable
    protected Class<?> determineTargetType(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) {
        // 获取resolvedTargetType属性,也相当于缓存,
        Class<?> targetType = mbd.getTargetType();
        if (targetType == null) {
            // 如果BeanDefinition中设置了factoryMethodName,那么就通过factoryMethodName来判断类型,
            // 否则获取AbstractBeanDefinition中的beanClass
            targetType = (mbd.getFactoryMethodName() != null ?
                    getTypeForFactoryMethod(beanName, mbd, typesToMatch) :
                    resolveBeanClass(mbd, beanName, typesToMatch));
            if (ObjectUtils.isEmpty(typesToMatch) || getTempClassLoader() == null) {
                // 将解析出来的类型记录到resolvedTargetType中
                mbd.resolvedTargetType = targetType;
            }
        }
        
        return targetType;
    }

AbstractAutowireCapableBeanFactory类的applyBeanPostProcessorsBeforeInstantiation实例化前方法

    @Nullable
    protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                // 执行 postProcessBeforeInstantiation 方法,也就是 实例化前
                Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
                if (result != null) {
                    return result;
                }
            }
        }
        return null;
    }

注意:上述方法的方法名 applyBeanPostProcessors BeforeInstantiationBeforeInstantiation实例化前。首先获得所有的 BeanPostProcessor ,然后循环遍历判断是否实现了InstantiationAwareBeanPostProcessor,然后执行 postProcessBeforeInstantiation实例化前方法。如果 postProcessBeforeInstantiation方法返回了对象,也就是不返回 null,就执行 applyBeanPostProcessorsAfterInitialization初始化后方法。

AbstractAutowireCapableBeanFactory类的applyBeanPostProcessorsAfterInitialization初始化后方法

@Override
    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
            throws BeansException {

        Object result = existingBean;
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            // 执行postProcessAfterInitialization方法,也就是初始化后
            Object current = processor.postProcessAfterInitialization(result, beanName);
            if (current == null) {
                return result;
            }
            result = current;
        }
        return result;
    }

也要注意该方法的方法名 applyBeanPostProcessorsAfterInitializationAfterInitialization初始化后。获取到所有的 BeanPostProcessor,然后循环每个BeanPostProcessorpostProcessAfterInitialization初始化后方法。如果postProcessAfterInitialization初始化后方法的返回值为 null就直接结束循环,进行返回。比如我有三个 BeanPostProcessor ,A、B、C,在执行A BeanPostProcessor 的时候,A的postProcessAfterInitialization方法返回了null,B、C两个BeanPostProcessor 不会再执行。AOP 也在此进行执行。

如果对于 BeanPostProcessor不熟悉的伙伴可以移步前往:Spring源码-BeanPostProcessor

doCreateBean

程序执行了 resolveBeforeInstantiation函数之后,如果返回的结果为 null,就需要执行 doCreateBean函数进行创建 Bean。

try {
            // 创建bean   Spring自带的创建bean的方法
            Object beanInstance = doCreateBean(beanName, mbdToUse, args);
            if (logger.isTraceEnabled()) {
                logger.trace("Finished creating instance of bean '" + beanName + "'");
            }
            return beanInstance;
        }

doCreateBean 函数的篇幅太长,将拆分几篇文章进行阅读。

  • 如你对本文有疑问或本文有错误之处,欢迎评论留言指出。如觉得本文对你有所帮助,欢迎点赞和关注。
相关文章
|
3天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
15 2
|
19天前
|
数据采集 监控 前端开发
二级公立医院绩效考核系统源码,B/S架构,前后端分别基于Spring Boot和Avue框架
医院绩效管理系统通过与HIS系统的无缝对接,实现数据网络化采集、评价结果透明化管理及奖金分配自动化生成。系统涵盖科室和个人绩效考核、医疗质量考核、数据采集、绩效工资核算、收支核算、工作量统计、单项奖惩等功能,提升绩效评估的全面性、准确性和公正性。技术栈采用B/S架构,前后端分别基于Spring Boot和Avue框架。
|
10天前
|
缓存 Java Spring
实战指南:四种调整 Spring Bean 初始化顺序的方案
本文探讨了如何调整 Spring Boot 中 Bean 的初始化顺序,以满足业务需求。文章通过四种方案进行了详细分析: 1. **方案一 (@Order)**:通过 `@Order` 注解设置 Bean 的初始化顺序,但发现 `@PostConstruct` 会影响顺序。 2. **方案二 (SmartInitializingSingleton)**:在所有单例 Bean 初始化后执行额外的初始化工作,但无法精确控制特定 Bean 的顺序。 3. **方案三 (@DependsOn)**:通过 `@DependsOn` 注解指定 Bean 之间的依赖关系,成功实现顺序控制,但耦合性较高。
实战指南:四种调整 Spring Bean 初始化顺序的方案
|
9天前
|
前端开发 Java 开发者
Spring生态学习路径与源码深度探讨
【11月更文挑战第13天】Spring框架作为Java企业级开发中的核心框架,其丰富的生态系统和强大的功能吸引了无数开发者的关注。学习Spring生态不仅仅是掌握Spring Framework本身,更需要深入理解其周边组件和工具,以及源码的底层实现逻辑。本文将从Spring生态的学习路径入手,详细探讨如何系统地学习Spring,并深入解析各个重点的底层实现逻辑。
35 9
|
28天前
|
Java 测试技术 Windows
咦!Spring容器里为什么没有我需要的Bean?
【10月更文挑战第11天】项目经理给小菜分配了一个紧急需求,小菜迅速搭建了一个SpringBoot项目并完成了开发。然而,启动测试时发现接口404,原因是控制器包不在默认扫描路径下。通过配置`@ComponentScan`的`basePackages`字段,解决了问题。总结:`@SpringBootApplication`默认只扫描当前包下的组件,需要扫描其他包时需配置`@ComponentScan`。
|
1月前
|
Java Spring
Spring底层架构源码解析(三)
Spring底层架构源码解析(三)
108 5
|
2月前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。
|
1月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
162 2
|
8天前
|
缓存 IDE Java
SpringBoot入门(7)- 配置热部署devtools工具
SpringBoot入门(7)- 配置热部署devtools工具
20 2
 SpringBoot入门(7)- 配置热部署devtools工具
|
4天前
|
存储 运维 安全
Spring运维之boot项目多环境(yaml 多文件 proerties)及分组管理与开发控制
通过以上措施,可以保证Spring Boot项目的配置管理在专业水准上,并且易于维护和管理,符合搜索引擎收录标准。
15 2