Spring源码分析(二)bean的创建过程

原创 吴就业 113 0 2018-10-30

本文为博主原创文章,未经博主允许不得转载。

本文链接:https://wujiuye.com/article/985b3a0ab47e4ddd8084fe31cb6e7e7e

作者:吴就业
链接:https://wujiuye.com/article/985b3a0ab47e4ddd8084fe31cb6e7e7e
来源:吴就业的网络日记
本文为博主原创文章,未经博主允许不得转载。

spring版本:4.3.18

上一篇有说到过BeanDefinition,主要关注的是其扩展接口AnnotateBeanDefinition和其子类AnnotateGenericBeanDefinition。本篇先超前介绍spring是如果通过BeanDefinition来创建一个bean的。

BeanDefinition的注册

AnnotationConfigApplicationContext是GenericApplicationContext的子类,所以是使用内置DefaultListableBeanFactory工厂类完成bean的注册和创建的。

public GenericApplicationContext() {
        this.beanFactory = new DefaultListableBeanFactory();
    }

使用AnnotationConfigApplicationContext的任一构造方法【AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory)除外】实例化AnnotationConfigApplicationContext都会调用其无参构造方法,最终父类的GenericApplicationContext都会被调用,在父类的构造方法中创建了DefaultListableBeanFactory实例,这就是AnnotationConfigApplicationContext使用的bean工厂。

@Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {
        ......
        //如果当前bean工厂中存在beanName对应的BeanDefinition,那么oldBeanDefinition不为空。
        BeanDefinition oldBeanDefinition;
        oldBeanDefinition = this.beanDefinitionMap.get(beanName);

        if (oldBeanDefinition != null) {
            ......
            //将新的替换旧的
            this.beanDefinitionMap.put(beanName, beanDefinition);
        }
        else {
            //private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(256));
            //alreadyCreated保存的是已经至少创建过一次的bean的名称
            //hasBeanCreationStarted就是判断alreadyCreated是否是空的,没有存储任何beanName。
            if (hasBeanCreationStarted()) {
                //保证线程安全
                synchronized (this.beanDefinitionMap) {
                    //beanDefinitionMap就是工厂用来保存描述bean的beanDefinition对象的。使用beanName作为beanDefinition
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    //将beanDefinitionNames指向新的beanName列表
                    this.beanDefinitionNames = updatedDefinitions;
                    if (this.manualSingletonNames.contains(beanName)) {
                        Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
                        updatedSingletons.remove(beanName);
                        //manualSingletonNames保存的是单例bean的名称     
                        this.manualSingletonNames = updatedSingletons;
                    }
                }
            }
            else {
                // 如果alreadyCreated为空,则说明仍在启动注册阶段
                this.beanDefinitionMap.put(beanName, beanDefinition);
                this.beanDefinitionNames.add(beanName);
                this.manualSingletonNames.remove(beanName);
            }
            this.frozenBeanDefinitionNames = null;
        }
        if (oldBeanDefinition != null || containsSingleton(beanName)) {
            resetBeanDefinition(beanName);
        }
    }

在下一篇介绍AnnotationConfigApplicationContext的启动流程会详细介绍何时调用这个registerBeanDefinition方法,被注解为bean的类何时被读取并创建BeanDefinition。

getBean的调用栈

调用AnnotationConfigApplicationContext的getBean方法最终会调用其内置bean工厂DefaultListableBeanFactory的getBean方法。

 UserBean userBean = (UserBean) applicationContext.getBean("userBean");
 userBean = applicationContext.getBean(UserBean.class);

AnnotationConfigApplicationContext并没有重写getBean方法,所以这里getBean调用的是其父类AbstractApplicationContext的getBean方法。

图片

前面说了,AnnotationConfigApplicationContext是应用上下文,它管理bean的生命周期,但是它并不是真正的bean工厂。AbstractApplicationContext类中的getBeanFactory方法获取到的就是AnnotationConfigApplicationContext的内置 bean工厂DefaultListableBeanFactory。

@Override
public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;

发现在AnnotationConfigApplicationContext的父类GenericApplicationContext重写了该方法。

【GenericApplicationContext类】
    @Override
    public final ConfigurableListableBeanFactory getBeanFactory() {
        return this.beanFactory;
    }

this.beanFactory就是DefaultListableBeanFactory。

private final DefaultListableBeanFactory beanFactory;

图片

最终getBean调用的是DefaultListableBeanFactory的getBean方法。

DefaultListableBeanFactory类实现BeanFactory的其它父类未实现的getBean方法。

图片

DefaultListableBeanFactory的父父类AbstractBeanFactory类实现了BeanFactory接口的三个getBean方法。

图片

doGetBean方法

前面的所有getBean方法最终都是调用AbstractBeanFactory类的doGetBean方法的。doGetBean方法比较长,已经在源码中给出了注释。为了好看我将日记相关的代码去掉了。

【AbstractBeanFactory类】
protected <T> T doGetBean(
            final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
            throws BeansException {

        //根据传递进来的参数name获取beanName,
        //一般情况下name就是beanName,如果是要获取BeanFactory对象的话,name是包含'&'字符的,所以需要先去掉'&'。
        //最后调用canonicalName方法(确定原始名称,将别名解析为规范名称。)
        final String beanName = transformedBeanName(name);
        Object bean;

        // 检查手动注册的单例缓存。
        Object sharedInstance = getSingleton(beanName);
        if (sharedInstance != null && args == null) {
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        }

        else {
            // isPrototypeCurrentlyInCreation返回指定的原型bean是否当前正在创建。如何当前正在创建则抛出BeanCurrentlyInCreationException异常。应该是避免多线程调用的。
            if (isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }

            // 获取父bean工厂,检查父bean工厂中是否存在这个bean。
            BeanFactory parentBeanFactory = getParentBeanFactory();
            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                //originalBeanName方法确定原始bean名称,将本地定义的别名解析为规范名称。如果name包含‘&’符号,则originalBeanName返回的name也包含&符号
                String nameToLookup = originalBeanName(name);
                if (args != null) {
                    return (T) parentBeanFactory.getBean(nameToLookup, args);
                }
                else {
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                }
            }

            if (!typeCheckOnly) {
                markBeanAsCreated(beanName);
            }

            try {
                final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                checkMergedBeanDefinition(mbd, beanName, args);

                // 确保初始化当前bean所依赖的bean已经创建。
                String[] dependsOn = mbd.getDependsOn();
                if (dependsOn != null) {
                    for (String dep : dependsOn) {
                        if (isDependent(beanName, dep)) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                        }
                        //registerDependentBean为给定的bean注册依赖bean(在给定的bean被销毁之前被销毁)。
                        //这个方法和isDependent方法是配合使用确保依赖死循环的。
                        registerDependentBean(dep, beanName);
                        try {
                            //调用getBean方法让依赖的bean创建(如果没创建才会创建),最终还是调用doGetBean方法。
                            //如果依赖的bean又依赖其它bean那就先确保依赖的bean的依赖bean先创建,递归。
                            //所以前面的registerDependentBean方法和isDependent方法是解决无限递归调用的。
                            getBean(dep);
                        }
                        catch (NoSuchBeanDefinitionException ex) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                        }
                    }
                }

                // 从这里开始创建bean实例

                //如果BeanDefinition中描述这个bean是单例的
                if (mbd.isSingleton()) {
                    //ObjectFactory,将bean的创建过程交给ObjectFactory完成。所以bean的创建是由对象工厂ObjectFactory创建的。
                    sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
                        @Override
                        public Object getObject() throws BeansException {
                            try {
//调用AbstractBeanFactory的createBean方法最终是调用其子类AbstractAutowireCapableBeanFactory的createBean方法创建bean。
                                return createBean(beanName, mbd, args);
                            }
                            catch (BeansException ex) {
                                //异常则销毁这个bean
                                destroySingleton(beanName);
                                throw ex;
                            }
                        }
                    });

                    //获取给定bean实例的对象,对于FactoryBean,可能是bean实例本身,
                    //也可能是它创建的对象,由beanName是否包含'&'符合决定。
                    //如果该bean是一个FactoryBean且name没有'&'符号,那么就是调用该bean的getObject方法获取目标对象,
                    //如果该bean的is单例方法返回true那么目标对象将会被factoryBeanObjectCache所缓存。
                    //更多具体的就需要自己看源码了。
                    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }

                else if (mbd.isPrototype()) {
                    // 不是单例,不用判断工厂中是否存在这个bean,直接创建一个新的实例。
                    Object prototypeInstance = null;
                    try {
                        beforePrototypeCreation(beanName);
                        // 与前面如果是单例的时候ObjectFactory的getObject方法中调用的createBean方法是同一个方法,不重复描述了。
                        prototypeInstance = createBean(beanName, mbd, args);
                    }
                    finally {
                        //before、after这些就是调用些通知了,具体是啥自己去看源码。
                        afterPrototypeCreation(beanName);
                    }
                    //跟isSingleton的情况下注释相同
                    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                }

                else {
                    String scopeName = mbd.getScope();
                    final Scope scope = this.scopes.get(scopeName);
                    if (scope == null) {
                        throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                    }
                    try {
                        //其它如scope="request"的时候
                        Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
                            @Override
                            public Object getObject() throws BeansException {
                                beforePrototypeCreation(beanName);
                                try {
                                    //还是调用createBean方法创建对象
                                    return createBean(beanName, mbd, args);
                                }
                                finally {
                                    afterPrototypeCreation(beanName);
                                }
                            }
                        });
                        //跟isSingleton的情况下注释相同
                        bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                    }
                    catch (IllegalStateException ex) {
                        ......
                    }
                }
            }
            catch (BeansException ex) {
                cleanupAfterBeanCreationFailure(beanName);
                throw ex;
            }
        }

        // 如果getBean同时传入了requiredType和beanName
        //则需要检查所需的类型是否与实际bean实例的类型匹配。
        if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
            try {
                return getTypeConverter().convertIfNecessary(bean, requiredType);
            }
            catch (TypeMismatchException ex) {
                ...
            }
        }
        //将bean强转为我们需要的目标类型返回
        return (T) bean;
    }

createBean方法

从doGetBean方法的源码中可以看到,无论bean的scope是单例还是其它,最终都是调用createBean方法创建实际的bean,只不过如果是单例的会被bean工厂缓存下次调用doGetBean就从缓存中获取到了就不需要再次调用createBean方法创建bean了。单例缓存实例上就是保存在一个map对象中。

【DefaultSingletonBeanRegistry类】
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);

至于单例是在什么时候被缓存的,可以回头看下doGetBean方法,在mbd.isSingleton的情况下,调用了getSingleton(beanName, new ObjectFactory

#后端

声明:公众号、CSDN、掘金的曾用名:“Java艺术”,因此您可能看到一些早期的文章的图片有“Java艺术”的水印。

文章推荐

ConcurrentHashMap是如何实现线程安全的

ConcurrentHashMap 在1.7中 实现线程安全是通过锁住Segment对象的。而在1.8 中则是针对首个节点(table[hash(key)]取得的链接或红黑树的首个节点)进行加锁操作。

Spring源码分析ioc容器总结篇

这篇文章是对前面几篇文章做一个小节,本篇不写一行代码,单纯的文字总结。

Spring源码分析(四)bean工厂初始化阶段

继续介绍AnnotationConfigApplicationContext工作流程,本篇介绍refresh方法,即bean工厂的初始化阶段。读完本篇你会了解到bean是什么时候被全部扫描成BeanDefinition注入到工厂中的。还有一些后置处理器的职责。

Spring源码分析(一)理解一些类及接口

本篇主要介绍一些重要的接口及类,下一篇介绍bean的创建过程,接着介绍AnnotationConfigApplicationContext的初始化流程,最后一篇通过源码总结bean的生命周期。

Spring源码分析(三)registerBean方法分析

介绍AnnotationConfigApplicationContext工作流程,本篇先介绍registerBean方法内部执行流程分析。

Java的class文件结构解读

相信你也很好奇.java文件编译后的.class文件结构?我也很好奇,所以来了就一起挖一挖这个坑吧。这是我读《深入理解java虚拟机》这本书的第六章“类文件结构”之后写的,目的是为了帮助大家更好的理解这一章的内容。