美文网首页
spring 源码之 Bean 的加载(一)

spring 源码之 Bean 的加载(一)

作者: Theodore的技术站 | 来源:发表于2019-02-27 21:29 被阅读3次

    直接切入正题,搞懂 Bean 的加载 spring 源码就差不多了,万卷不离其宗。

    AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(XXX.class);
             app.getBean(YYY.class);
    

    直接通过 AnnotationConfigApplicationContext 就到达入口。这个 app 可以 get bean 所以 bean 在第一行就创建好了。

        public AnnotationConfigApplicationContext(Class... annotatedClasses) {
            this();
            this.register(annotatedClasses);
            this.refresh();
        }
    

    refresh()
    这个就是整个Spring Bean加载的核心了,它是ClassPathXmlApplicationContext的父类AbstractApplicationContext的一个方法,顾名思义,用于刷新整个Spring上下文信息,定义了整个Spring上下文加载的流程。

    public void refresh() throws BeansException, IllegalStateException {
            // 对象锁
            synchronized(this.startupShutdownMonitor) {
                //准备刷新上下文 (设置激活标志位)
                this.prepareRefresh();
                //获取刷新Spring上下文的Bean工厂
                ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
                //准备 bean 工厂
                this.prepareBeanFactory(beanFactory);
    
                try {
                    //允许 beanFactory 的 后置处理器
                    this.postProcessBeanFactory(beanFactory);
                    //调用工厂处理器注册bean
                    this.invokeBeanFactoryPostProcessors(beanFactory);
                    //注册 bean 后置处理器
                    this.registerBeanPostProcessors(beanFactory);
                    //初始消息资源
                    this.initMessageSource();
                    //初始 event 多路广播
                    this.initApplicationEventMulticaster();
                    //初始一些特殊的 bean
                    this.onRefresh();
                    //注册监听器
                    this.registerListeners();
                    // 这里完成bean 的初始化(非懒加载)
                    this.finishBeanFactoryInitialization(beanFactory);  
                    // 发布相关事件
                    this.finishRefresh();
                } catch (BeansException var9) {
                    if (this.logger.isWarnEnabled()) {
                        this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                    }
                    //删除 bean
                    this.destroyBeans();
                    //取消 refresh
                    this.cancelRefresh(var9);
                    throw var9;
                } finally {
                    // reset 激活标志位
                    this.resetCommonCaches();
                }
    
            }
        }
    

    1、方法是加锁的,这么做的原因是避免多线程同时刷新Spring上下文。

    2、尽管加锁可以看到是针对整个方法体的,但是没有在方法前加 synchronized 关键字,而使用了对象锁 startUpShutdownMonitor,这样做有两个好处:

    (1)refresh()方法和close()方法都使用了 startUpShutdownMonitor 对象锁加锁,这就保证了在调用 refresh() 方法的时候无法调用 close() 方法,反之亦然,避免了冲突。

    (2)另外一个好处不在这个方法中体现,但是提一下,使用对象锁可以减小了同步的范围,只对不能并发的代码块进行加锁,提高了整体代码运行的效率。

    finishBeanFactoryInitialization(beanFactory) 主要完成 bean 的加载。

        protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
            if (beanFactory.containsBean("conversionService") && beanFactory.isTypeMatch("conversionService", ConversionService.class)) {
                beanFactory.setConversionService((ConversionService)beanFactory.getBean("conversionService", ConversionService.class));
            }
    
            if (!beanFactory.hasEmbeddedValueResolver()) {
                beanFactory.addEmbeddedValueResolver(new StringValueResolver() {
                    public String resolveStringValue(String strVal) {
                        return AbstractApplicationContext.this.getEnvironment().resolvePlaceholders(strVal);
                    }
                });
            }
    
            String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
            String[] var3 = weaverAwareNames;
            int var4 = weaverAwareNames.length;
    
            for(int var5 = 0; var5 < var4; ++var5) {
                String weaverAwareName = var3[var5];
                this.getBean(weaverAwareName);
            }
    
            beanFactory.setTempClassLoader((ClassLoader)null);
            beanFactory.freezeConfiguration();
            beanFactory.preInstantiateSingletons();
        }
    

    preInstantiateSingletons 方法是初始化单例 bean 的方法:

        public void preInstantiateSingletons() throws BeansException {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Pre-instantiating singletons in " + this);
            }
    
            List<String> beanNames = new ArrayList(this.beanDefinitionNames);
            Iterator var2 = beanNames.iterator();
    
            while(true) {
                while(true) {
                    String beanName;
                    RootBeanDefinition bd;
                    do {
                        do {
                            do {
                                if (!var2.hasNext()) {
                                    var2 = beanNames.iterator();
    
                                    while(var2.hasNext()) {
                                        beanName = (String)var2.next();
                                        Object singletonInstance = this.getSingleton(beanName);
                                        if (singletonInstance instanceof SmartInitializingSingleton) {
                                            final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton)singletonInstance;
                                            if (System.getSecurityManager() != null) {
                                                AccessController.doPrivileged(new PrivilegedAction<Object>() {
                                                    public Object run() {
                                                        smartSingleton.afterSingletonsInstantiated();
                                                        return null;
                                                    }
                                                }, this.getAccessControlContext());
                                            } else {
                                                smartSingleton.afterSingletonsInstantiated();
                                            }
                                        }
                                    }
    
                                    return;
                                }
    
                                beanName = (String)var2.next();
                                bd = this.getMergedLocalBeanDefinition(beanName);
                            } while(bd.isAbstract());
                        } while(!bd.isSingleton());
                    } while(bd.isLazyInit());
    
                    if (this.isFactoryBean(beanName)) {
                        final FactoryBean<?> factory = (FactoryBean)this.getBean("&" + beanName);
                        boolean isEagerInit;
                        if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                            isEagerInit = (Boolean)AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
                                public Boolean run() {
                                    return ((SmartFactoryBean)factory).isEagerInit();
                                }
                            }, this.getAccessControlContext());
                        } else {
                            isEagerInit = factory instanceof SmartFactoryBean && ((SmartFactoryBean)factory).isEagerInit();
                        }
    
                        if (isEagerInit) {
                            this.getBean(beanName);
                        }
                    } else {
                        this.getBean(beanName);
                    }
                }
            }
        }
    

    这里先解释一下getMergedLocalBeanDefinition方法的含义,因为这个方法会常常看到。Bean定义公共的抽象类是AbstractBeanDefinition,普通的Bean在Spring加载Bean定义的时候,实例化出来的是GenericBeanDefinition,而Spring上下文包括实例化所有Bean用的AbstractBeanDefinition是RootBeanDefinition,这时候就使用getMergedLocalBeanDefinition方法做了一次转化,将非RootBeanDefinition转换为RootBeanDefinition以供后续操作。

    第1行~第10行的代码是根据beanName拿到RootBeanDefinition。由于此方法实例化的是所有非懒加载的单例Bean,因此要实例化Bean,必须满足11行的三个定义:

    (1)不是抽象的

    (2)必须是单例的

    (3)必须是非懒加载的

    接着简单看一下第12行~第29行的代码,这段代码主要做的是一件事情:首先判断一下Bean是否FactoryBean的实现,接着判断Bean是否SmartFactoryBean的实现,假如Bean是SmartFactoryBean的实现并且eagerInit(这个单词字面意思是渴望加载,找不到一个好的词语去翻译,意思就是定义了这个Bean需要立即加载的意思)的话,会立即实例化这个Bean。Java开发人员不需要关注这段代码,因为SmartFactoryBean基本不会用到,我翻译一下Spring官网对于SmartFactoryBean的定义描述:

    -FactoryBean接口的扩展接口。接口实现并不表示是否总是返回单独的实例对象,比如FactoryBean.isSingleton()实现返回false的情况并不清晰地表示每次返回的都是单独的实例对象。

    -不实现这个扩展接口的简单FactoryBean的实现,FactoryBean.isSingleton()实现返回false总是简单地告诉我们每次返回的都是单独的实例对象,暴露出来的对象只能够通过命令访问。

    -注意:这个接口是一个有特殊用途的接口,主要用于框架内部使用与Spring相关。通常,应用提供的FactoryBean接口实现应当只需要实现简单的FactoryBean接口即可,新方法应当加入到扩展接口中去

    获取Bean对象实例,都是通过getBean方法,跟进去看 doGetBean 方法。真正干事儿的基本上都是 do 开头的方法。

    protected <T> T doGetBean(String name, Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException {
            '//提取对应的 beanName'
            final String beanName = this.transformedBeanName(name);
            '// 检查缓存中或者实例工厂中是否有对应的实例
            // 这里是为了解决单例 bean 下的循环依赖 
            //spring 创建 bean 的原则是不等 bean 创建完就将 创建 bean 的 ObjectFactory 提早曝光。
            //也就是将 ObjectFactory 加入到缓存中'
            Object sharedInstance = this.getSingleton(beanName);
            Object bean;
            
            if (sharedInstance != null && args == null) {
                if (this.logger.isDebugEnabled()) {
                    if (this.isSingletonCurrentlyInCreation(beanName)) {
                        this.logger.debug("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference");
                    } else {
                        this.logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
                    }
                }
                '// 返回对应的实例,有时候存在诸如 BeanFactory 的情况并不是直接返回实例本身而是返回指定方法返回的实例(这里应该是用了代理)'
                bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
            } else {
                '// 只有单例情况下才会解决循环依赖'
                if (this.isPrototypeCurrentlyInCreation(beanName)) {
                    throw new BeanCurrentlyInCreationException(beanName);
                }
    
                BeanFactory parentBeanFactory = this.getParentBeanFactory();
               ' // 如果 beanDefinitionMap 中也就是在所有已经加载的类中不包括 beanName 则尝试从 parentBeanFactory 中检测'
                if (parentBeanFactory != null && !this.containsBeanDefinition(beanName)) {
                    String nameToLookup = this.originalBeanName(name);
                    '// 递归到 BeanFactory 中寻找'
                    if (args != null) {
                        return parentBeanFactory.getBean(nameToLookup, args);
                    }
    
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                }
                '// 如果不是仅仅做类型检查则是创建 bean 这里要记录'
                if (!typeCheckOnly) {
                    this.markBeanAsCreated(beanName);
                }
    
                try {
                    '// 将存储 XML 配置文件的 GernericBeanDefiniton 转换为 RootBeanDefinitionm, 如果指定 BeanName 是子 Bean 的同时会合并父类的相关属性'
                    final RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
                    this.checkMergedBeanDefinition(mbd, beanName, args);
                    String[] dependsOn = mbd.getDependsOn();
                    String[] var11;
                    '// 若存在依赖则需要递归实例化依赖的 bean'
                    if (dependsOn != null) {
                        var11 = dependsOn;
                        int var12 = dependsOn.length;
                        
                        for(int var13 = 0; var13 < var12; ++var13) {
                            String dep = var11[var13];
                            if (this.isDependent(beanName, dep)) {
                                throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                            }
                            '// 缓存依赖调用'
                            this.registerDependentBean(dep, beanName);
    
                            try {
                                this.getBean(dep);
                            } catch (NoSuchBeanDefinitionException var24) {
                                throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", var24);
                            }
                        }
                    }
                    '// 实例化依赖的 bean 后便可以实例化 mbd本身了'
                    if (mbd.isSingleton()) {
                        sharedInstance = this.getSingleton(beanName, new ObjectFactory<Object>() {
                            public Object getObject() throws BeansException {
                                try {
                                    return AbstractBeanFactory.this.createBean(beanName, mbd, args);
                                } catch (BeansException var2) {
                                    AbstractBeanFactory.this.destroySingleton(beanName);
                                    throw var2;
                                }
                            }
                        });
                        bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                    '// 原型模式的创建'
                    } else if (mbd.isPrototype()) {
                        var11 = null;
    
                        Object prototypeInstance;
                        try {
                            this.beforePrototypeCreation(beanName);
                            prototypeInstance = this.createBean(beanName, mbd, args);
                        } finally {
                            this.afterPrototypeCreation(beanName);
                        }
    
                        bean = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                    } else {
                        '// 指定的 scope 上实例化 bean'
                        String scopeName = mbd.getScope();
                        Scope scope = (Scope)this.scopes.get(scopeName);
                        if (scope == null) {
                            throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                        }
    
                        try {
                            Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
                                public Object getObject() throws BeansException {
                                    AbstractBeanFactory.this.beforePrototypeCreation(beanName);
    
                                    Object var1;
                                    try {
                                        var1 = AbstractBeanFactory.this.createBean(beanName, mbd, args);
                                    } finally {
                                        AbstractBeanFactory.this.afterPrototypeCreation(beanName);
                                    }
    
                                    return var1;
                                }
                            });
                            bean = this.getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                        } catch (IllegalStateException var23) {
                            throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton", var23);
                        }
                    }
                } catch (BeansException var26) {
                    this.cleanupAfterBeanCreationFailure(beanName);
                    throw var26;
                }
            }
            '// 检查需要的类型是否符合 bean 的实际类型'
            if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
                try {
                    return this.getTypeConverter().convertIfNecessary(bean, requiredType);
                } catch (TypeMismatchException var25) {
                    if (this.logger.isDebugEnabled()) {
                        this.logger.debug("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'", var25);
                    }
    
                    throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
                }
            } else {
                return bean;
            }
        }
    

    加载过程中所涉及的步骤如下:
    1.转换对应 beanName
    这里传入的参数可能是别名,也可能是 FactoryBean,所以需要进行一系列的解析。
    -去除 FactoryBean 的修饰符,如果 name 是 “&aa”,那么去除 & 使 name 为 “aa”。
    -去指定的 alias 所表示的最终 beanName,例如别名 A 指向名称为 B 的 bean 则返回 B。

    2.尝试从缓存中加载单例
    单例在 Spring 的同一容器内只会被创建一次,后续再获取 bean,就直接从单例缓存中获取了。这里只是尝试加载,首先尝试从缓存中加载,如果加载不成功则再次尝试从 singletonFactories 中加载。为了避免循环依赖,Spring 的原则是不等 bean 创建完成就会将创建 bean 的 ObjectFactory 提早曝光加入到缓存中。

    1. bean 的实例化
      如果从缓存中得到了 bean 的原始状态,则需要对 bean 进行实例化。缓存中只是最原始的 bean 状态,并不一定是想要的。假如我们要对工厂 bean 进行处理,这里其实是工厂 bean 的初始状态,但是我们真正需要的是工厂 bean 中定义的 factory-method 方法中返回的 bean,而 getObjectForBeanInstance 就是完成这个工作的。

    4.原型模式的依赖检查
    只有单例情况下才会尝试解决循环依赖,原型模式下只会抛出异常

    5.检测 parentBeanFactory
    parentBeanFactory != null && !this.containsBeanDefinition(beanName) 加载的 XML 配置文件中不包含 beanName 所对应的配置 就只能到 parentBeanFactory 去尝试下了,然后再去递归的调用 getBean 方法。

    6.将存储 XML 配置文件的 GernericBeanDefinition 转换为 RootBeanDefinition

    7.寻找依赖
    bean 初始化过程中很可能用到某些属性,而某些属性可能是动态配置的,并且配置成依赖于其他的 bean, 那么这个时候就有必要先加载依赖的 bean,所以,在 spring 加载循序中,在初始化 bean 的时候会首先初始化这个 bean 所对应的依赖。

    8.针对不用的 scope 进行 bean 的创建。
    singleton prototype request 等。

    9.类型转换
    将返回的 bean 转换为 requiredType 所指定的类型。

    相关文章

      网友评论

          本文标题:spring 源码之 Bean 的加载(一)

          本文链接:https://www.haomeiwen.com/subject/rydgyqtx.html