Spring 源码分析 : 非懒加载的单例 Bean 初始化过程 ( 上 ) ( 1 )

代码入口

 

上文《 Spring源码分析 : Bean加载流程概览 》,比较详细地分析了Spring上下文加载的代码入口,并且在AbstractApplicationContext的refresh方法中,点出了finishBeanFactoryInitialization方法完成了对于所有非懒加载的Bean的初始化。

 

finishBeanFactoryInitialization方法中调用了DefaultListableBeanFactory的preInstantiateSingletons方法,本文针对preInstantiateSingletons进行分析,解读一下Spring是如何初始化Bean实例对象出来的。

 

DefaultListableBeanFactory的preInstantiateSingletons方法

 

DefaultListableBeanFactory的preInstantiateSingletons方法,顾名思义,初始化所有的单例Bean,看一下方法的定义:

 

public void preInstantiateSingletons() throws BeansException {

    if (this.logger.isInfoEnabled()) {

        this.logger.info("Pre-instantiating singletons in " + this);

    }

    synchronized (this.beanDefinitionMap) {

        // Iterate over a copy to allow for init methods which in turn register new bean definitions.

        // While this may not be part of the regular factory bootstrap, it does otherwise work fine.

        List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);

        for (String beanName : beanNames) {

            RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);

            if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {

                if (isFactoryBean(beanName)) {

                    final FactoryBean factory = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName);

                    boolean isEagerInit;

                    if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {

                        isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {

                            public Boolean run() {

                                return ((SmartFactoryBean) factory).isEagerInit();

                            }

                        }, getAccessControlContext());

                    }

                    else {

                        isEagerInit = (factory instanceof SmartFactoryBean &&

                                ((SmartFactoryBean) factory).isEagerInit());

                    }

                    if (isEagerInit) {

                        getBean(beanName);

                    }

                }

                else {

                    getBean(beanName);

                }

            }

        }

    }

}

 

前面的代码比较简单,根据beanName拿到BeanDefinition(即Bean的定义)。由于此方法实例化的是所有非懒加载的单例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:

 

package org.xrq.action;

 

import org.springframework.beans.factory.BeanClassLoaderAware;

import org.springframework.beans.factory.BeanNameAware;

import org.springframework.beans.factory.InitializingBean;

 

public class MultiFunctionBean implements InitializingBean, BeanNameAware, BeanClassLoaderAware {

 

    private int    propertyA;

 

    private int    propertyB;

 

    public int getPropertyA() {

        return propertyA;

    }

 

    public void setPropertyA(int propertyA) {

        this.propertyA = propertyA;

    }

 

    public int getPropertyB() {

        return propertyB;

    }

 

    public void setPropertyB(int propertyB) {

        this.propertyB = propertyB;

    }

 

    public void initMethod() {

        System.out.println("Enter MultiFunctionBean.initMethod()");

    }

 

    @Override

    public void setBeanClassLoader(ClassLoader classLoader) {

        System.out.println("Enter MultiFunctionBean.setBeanClassLoader(ClassLoader classLoader)");

    }

 

    @Override

    public void setBeanName(String name) {

        System.out.println("Enter MultiFunctionBean.setBeanName(String name)");

    }

 

    @Override

    public void afterPropertiesSet() throws Exception {

        System.out.println("Enter MultiFunctionBean.afterPropertiesSet()");

    }

 

    @Override

    public String toString() {

        return "MultiFunctionBean [propertyA=" + propertyA + ", propertyB=" + propertyB + "]";

    }

 

}

 

定义对应的spring.xml:

 

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://www.springframework.org/schema/beans

 

http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

 

    <bean id="multiFunctionBean" class="org.xrq.action.MultiFunctionBean" init-method="initMethod" />

 

</beans>

 

利用这个MultiFunctionBean,我们可以用来探究Spring加载Bean的多种机制。

 

doGetBean方法构造Bean流程

 

上面把getBean之外的代码都分析了一下,看代码就可以知道,获取Bean对象实例,都是通过getBean方法,getBean方法最终调用的是DefaultListableBeanFactory的父类AbstractBeanFactory类的doGetBean方法,因此这部分重点分析一下doGetBean方法是如何构造出一个单例的Bean的。

 

看一下doGetBean方法的代码实现,比较长:

 

protected <T> T doGetBean(

        final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)

        throws BeansException {

 

    final String beanName = transformedBeanName(name);

    Object bean;

 

    // Eagerly check singleton cache for manually registered singletons.

    Object sharedInstance = getSingleton(beanName);

    if (sharedInstance != null && args == null) {

        if (logger.isDebugEnabled()) {

            if (isSingletonCurrentlyInCreation(beanName)) {

                logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +

                        "' that is not fully initialized yet - a consequence of a circular reference");

            }

            else {

                logger.debug("Returning cached instance of singleton bean '" + beanName + "'");

            }

        }

        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);

    }

 

    else {

        // Fail if we're already creating this bean instance:

        // We're assumably within a circular reference.

        if (isPrototypeCurrentlyInCreation(beanName)) {

            throw new BeanCurrentlyInCreationException(beanName);

        }

 

        // Check if bean definition exists in this factory.

        BeanFactory parentBeanFactory = getParentBeanFactory();

        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {

            // Not found -> check parent.

            String nameToLookup = originalBeanName(name);

            if (args != null) {

                // Delegation to parent with explicit args.

                return (T) parentBeanFactory.getBean(nameToLookup, args);

            }

            else {

                // No args -> delegate to standard getBean method.

                return parentBeanFactory.getBean(nameToLookup, requiredType);

            }

        }

 

        if (!typeCheckOnly) {

            markBeanAsCreated(beanName);

        }

 

        final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);

        checkMergedBeanDefinition(mbd, beanName, args);

 

        // Guarantee initialization of beans that the current bean depends on.

        String[] dependsOn = mbd.getDependsOn();

        if (dependsOn != null) {

            for (String dependsOnBean : dependsOn) {

                getBean(dependsOnBean);

                registerDependentBean(dependsOnBean, beanName);

            }

        }

 

        // Create bean instance.

        if (mbd.isSingleton()) {

            sharedInstance = getSingleton(beanName, new ObjectFactory() {

                public Object getObject() throws BeansException {

                    try {

                        return createBean(beanName, mbd, args);

                    }

                    catch (BeansException ex) {

                        // Explicitly remove instance from singleton cache: It might have been put there

                        // eagerly by the creation process, to allow for circular reference resolution.

                        // Also remove any beans that received a temporary reference to the bean.

                        destroySingleton(beanName);

                        throw ex;

                    }

                }

            });

            bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);

        }

 

        else if (mbd.isPrototype()) {

            // It's a prototype -> create a new instance.

            Object prototypeInstance = null;

            try {

                beforePrototypeCreation(beanName);

                prototypeInstance = createBean(beanName, mbd, args);

            }

            finally {

                afterPrototypeCreation(beanName);

            }

            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 '" + scopeName + "'");

            }

            try {

                Object scopedInstance = scope.get(beanName, new ObjectFactory() {

                    public Object getObject() throws BeansException {

                            beforePrototypeCreation(beanName);

                        try {

                            return createBean(beanName, mbd, args);

                        }

                        finally {

                            afterPrototypeCreation(beanName);

                        }

                    }

                });

                bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);

            }

            catch (IllegalStateException ex) {

                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",

                        ex);

            }

        }

    }

 

    // Check if required type matches the type of the actual bean instance.

    if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {

        try {

            return getTypeConverter().convertIfNecessary(bean, requiredType);

        }

        catch (TypeMismatchException ex) {

            if (logger.isDebugEnabled()) {

                logger.debug("Failed to convert bean '" + name + "' to required type [" +

                        ClassUtils.getQualifiedName(requiredType) + "]", ex);

            }

            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());

        }

    }

    return (T) bean;

}

 

首先第9行~第21行的代码,第9行的代码就不进去看了,简单说一下:首先检查一下本地的单例缓存是否已经加载过Bean,没有的话再检查earlySingleton缓存是否已经加载过Bean(又是early,不好找到词语翻译),没有的话执行后面的逻辑。

 

接着第26行~第50行,这里执行的都是一些基本的检查和简单的操作,包括bean是否是prototype的(prototype的Bean当前创建会抛出异常)、是否抽象的、将beanName加入alreadyCreated这个Set中等。

 

接着第53行~第59行,我们经常在bean标签中看到depends-on这个属性,就是通过这段保证了depends-on依赖的Bean会优先于当前Bean被加载。

 

来源:五月的仓颉,

www.cnblogs.com/xrq730/p/6361578.html

转载于:https://my.oschina.net/u/3100313/blog/888579

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值