Spring这么初始化Bean实例对象
更新:HHH   时间:2023-1-7


这篇文章主要介绍了Spring这么初始化Bean实例对象的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇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;

}

关于“Spring这么初始化Bean实例对象”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“Spring这么初始化Bean实例对象”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注天达云行业资讯频道。

返回云计算教程...