Spring学习2-Bean的加载过程(IOC实现原理)

之前基本理清了ClassPathXmlApplicationContext的继承层次,但一些重点方法和一些重要对象并未触及,本文继续调试和阅读spring源码,希望通过此次学习可以搞明白bean的加载和生成机制。调试的Main方法如下,很简单,实现了一个简单的Transaction对象,使用ClassPathXmlApplicationContext获取transaction对象,调用对象的transaction方法。

import com.thoughtworks.Transaction;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;

import java.io.IOException;

public class Main {

    public static void main(String[] args) throws IOException {
        ApplicationContext context = new ClassPathXmlApplicationContext("Application-context.xml");
        Transaction transaction = (Transaction)context.getBean("transaction");
        transaction.transaction();
    }
}

下面是Transaction对象定义,其中stMapper用到了mybatis,mybatis是比较流行的orm框架,之前也没使用过,由于项目中使用,模仿着写了一个,如果可以的话,顺便将mybatis与spring的整合代码一起看了。trasaction方法上我加上了@Transactional注解,这个注解实现从spring框架中支持了数据库事务,好处在于让程序员避免了在每次提交事务sql时写那些模板代码,通过与mybatis的整合,针对数据库的操作看起来会相当干净,仅仅加上一个注解,就可以轻松实现对事物的控制。这里加上@Transactional注解,是想了解下spring的实现机制,之前看了一点这块的代码,了解到spring的事务本质实际上还是AOP的方式实现(Spring AOP通过动态代理的方式实现,动态代理本质就是动态生成继承接口的类或者继承父类的子类,最终在动态生成的代理类中对用户方法进行拦截),spring实现了两种动态代理:jdk和cglib的,区别在于:jdk使用java自带的动态代理功能实现,但是只能支持代理继承于接口的具体类;cglib是为了能支持代理非继承接口的具体类(final类无法支持,因为通过继承父类实现),使用了直接生成字节码的方式返回class类型(据介绍还比较屌,想了解java字节码实现的,可以看看这块的源码,不够估计是native方法,那就得去看jvm虚拟机c语言源码了)。关于动态代理在Spring AOP的实现方式,后续会单列一章详细分析,此处仅简单叙述。

package com.thoughtworks;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Date;

@Component
public class Transaction {

    @Autowired
    private StMapper stMapper;

    @Transactional
    public void transaction() {
        System.out.println(stMapper.getStockCardId(119, 572));
        System.out.println(stMapper.getStockCardId(1, 1));
        System.out.println(stMapper.getCMMEntryHead());
    }
}

下面是StMapping的实现,该部分是mybatis跟spring整合的代码,虽然还没来得及细看源码,但是即使是猜,大概能想到mybatis也只能靠实现spring的某些插件类,最终注册到spring当中去实现mybatis的orm功能。如果本文篇幅够的话,可以把mybatis和spring的整合部分一起看了,不够的话后面再单列一章。

package com.thoughtworks;

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Options;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface StMapper {

    @Select("select * from tmp where a = #{a}")
    List getStudent(@Param("a") int a);

    @Select("select id from stock_cards where facilityid = ${facilityid} and productid = ${productid}")
    Integer getStockCardId(@Param("facilityid") Integer facilityid, @Param("productid") Integer productid);

    @Select("SELECT * FROM cmm_entries limit 1")
    CMMEntry getCMMEntryHead();
}

ApplicationContext的xml配置,数据库密码我写在default.properties中,由于涉及项目信息安全,配置文件就不放置了,配置文件就是简单key=value,每行一对配置,spring会自己去加载配置,然后替换配置中的占位符(比如${openlmis.jdbc.password}),这块我们也会在后面的源码中看到spring是如何替换这些占位符的。




    
    

    

    
        
            
        
    

    

    
        
        
        
        
    

    
        
        
    

    
        
        
        
    

    
        
    



首先,我们从上下文的初始化开始,传入配置文件名称,该配置文件路径放在工程的resource目录下(default.properties也放在resource下面):

ApplicationContext context = new ClassPathXmlApplicationContext("Application-context.xml");

ClassPathXmlApplicationContext首先调用自己的构造函数,将配置文件名称传入,随后继续内部调用另外一个参数更多的构造函数,我们这里parent为null,之前看到,ApplicationContext是具有层次性的,多个ApplicationContext可以构造层次关系。随后调用了最重要的方法refresh方法。

    public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
        this(new String[] {configLocation}, true, null);
    }

    public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
            throws BeansException {

        super(parent);
        setConfigLocations(configLocations);
        if (refresh) {
            refresh();
        }
    }   

refresh方法,该方法在AbstractApplicationContext中实现。synchronized (this.startupShutdownMonitor) 用于保证bean刷新的完整性。

    @Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                initMessageSource();

                // Initialize event multicaster for this context.
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                onRefresh();

                // Check for listener beans and register them.
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                finishRefresh();
            }

            catch (BeansException ex) {
                logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);

                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

                // Reset 'active' flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }
        }
    }

Bean加载流程解析

prepareRefresh

prepareRefresh负责刷新前的准备工作,包括环境信息、配置路径信息的初始化。

obtainFreshBeanFactory

随后,会初始化一个重要对象--beanFactory,该beanFactory对象为ConfigurableListableBeanFactory类型。

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

查看obtainFreshBeanFactory方法,调用了AbstractApplicationContext中的两个抽象方法refreshBeanFactory和getBeanFactory,在AbstractApplicationContext中,多个涉及beanFactory的方法都是抽象方法,该beanFactory对象为ConfigurableListableBeanFactory。

    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        refreshBeanFactory();
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        if (logger.isDebugEnabled()) {
            logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
        }
        return beanFactory;
    }

AbstractApplicationContext的直接子类AbstractRefreshableApplicationContext实现了refreshBeanFactory和getBeanFactory的方法,getBeanFactory里面直接获取的beanFactory对象,而负责beanFactory对象初始化方法的实际上是refreshBeanFactory,在不涉及重建beanFactory的场景中,refreshBeanFactory方法不会触发if分支。其中createBeanFactory负责beanFactory的创建,该beanFactory类型为DefaultListableBeanFactory,这个类负责代理所有涉及beanFactory的动作,所以这个类相当重要。

    @Override
    protected final void refreshBeanFactory() throws BeansException {
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());
            customizeBeanFactory(beanFactory);
            loadBeanDefinitions(beanFactory);
            synchronized (this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }
    
    @Override
    public final ConfigurableListableBeanFactory getBeanFactory() {
        synchronized (this.beanFactoryMonitor) {
            if (this.beanFactory == null) {
                throw new IllegalStateException("BeanFactory not initialized or already closed - " +
                        "call 'refresh' before accessing beans via the ApplicationContext");
            }
            return this.beanFactory;
        }
    }

    protected DefaultListableBeanFactory createBeanFactory() {
        return new DefaultListableBeanFactory(getInternalParentBeanFactory());
    }

下图为DefaultListableBeanFactory的继承层次:

DefaultListableBeanFactory继承层次.png

之前已经介绍过的接口不再重复介绍,只介绍新遇到的接口和类型。
接口SingletonBeanRegistry,负责对单例进行注册,以及获取单例等跟单例等相关的方法。这说明beanFactory有专门处理单例对象的逻辑。

public interface SingletonBeanRegistry {

    void registerSingleton(String beanName, Object singletonObject);

    Object getSingleton(String beanName);

    boolean containsSingleton(String beanName);

    String[] getSingletonNames();

    int getSingletonCount();
}

接口AliasRegistry,负责别名注册相关的方法。这个接口说明beanFactory可以为bean注册别名,可以让用户通过别名访问bean的相关信息。SimpleAliasRegistry为AliasRegistry的具体类,不出意外,该类在后续肯定是协助DefaultListableBeanFactory代理执行AliasRegistry的这几个方法。

public interface AliasRegistry {

    void registerAlias(String name, String alias);

    void removeAlias(String alias);

    boolean isAlias(String beanName);

    String[] getAliases(String name);

}

接口BeanDefinitionRegistry,负责bean定义信息注册相关的方法。

public interface BeanDefinitionRegistry extends AliasRegistry {

    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException;

    void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

    BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

    boolean containsBeanDefinition(String beanName);

    String[] getBeanDefinitionNames();

    int getBeanDefinitionCount();

    boolean isBeanNameInUse(String beanName);

}

DefaultSingletonBeanRegistry,这是个具体类,继承自SimpleAliasRegistry和SingletonBeanRegistry。该类主要负责实现SingletonBeanRegistry接口中所有的方法。同时,它还实现了很多其他关于bean的方法,其中包括注册bean的依赖关系,还有bean的销毁方法,其中由于包含依赖,所以多个方法都是递归实现的。该类只负责管理和注册bean信息,同时也包含创建bean的功能。整体类功能非常具体且独立,所以阅读起来也很简单,由于该类方法较多,就不贴代码了。

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
    ...
}

接口ConfigurableBeanFactory,继承自HierarchicalBeanFactory, SingletonBeanRegistry,接口中主要是配置beanFactory信息的接口,同时因为继承自SingletonBeanRegistry,也包含该接口相关方法。

public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry

抽象类FactoryBeanRegistrySupport,继承自DefaultSingletonBeanRegistry。该抽象类没包含抽象方法,所以仅仅只是不能实例化。该类新增了几个方法未包含public方法,说明该类仅仅是为了给子类提供工具方法,新增方法主要是bean和beanFactory相关方法。

public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanRegistry

AbstractBeanFactory抽象类

AbstractBeanFactory抽象类继承自FactoryBeanRegistrySupport,ConfigurableBeanFactory。该类主要实现了BeanFactory接口中的方法,HierarchicalBeanFactory接口中的方法,以及ConfigurableBeanFactory接口中的方法。最后,该类提供了三个抽象方法交给子类实现。

public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory 

BeanFactory接口方法实现

AbstractBeanFactory抽象类实现了beanFactory的方法,用来获取bean的getBean方法以及一些与bean状态和类型相关的方法。比较重要的有getBean方法,getBean方法实际调用的是doGetBean方法,因为bean之间可能存在依赖,所以doGetBean方法中生成bean的时候是递归进行的,真正生成bean对象的是createBean方法,该方法为抽象方法,由子类负责实现。

protected  T doGetBean(
            final String name, final Class 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);
            }

            try {
                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) {
                        if (isDependent(beanName, dependsOnBean)) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "Circular depends-on relationship between '" + beanName + "' and '" + dependsOnBean + "'");
                        }
                        registerDependentBean(dependsOnBean, beanName);
                        getBean(dependsOnBean);
                    }
                }

                // Create bean instance.
                if (mbd.isSingleton()) {
                    sharedInstance = getSingleton(beanName, new ObjectFactory() {
                        @Override
                        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() {
                            @Override
                            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);
                    }
                }
            }
            catch (BeansException ex) {
                cleanupAfterBeanCreationFailure(beanName);
                throw 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;
    }
 
 

ConfigurableBeanFactory接口实现

该接口实现主要包含配置化beanFactory接口的实现。

AbstractBeanFactory的抽象方法

protected abstract boolean containsBeanDefinition(String beanName);

protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;

protected abstract Object createBean(String beanName, RootBeanDefinition mbd, Object[] args)
            throws BeanCreationException;
AbstractAutowireCapableBeanFactory抽象类

该抽象类继承自AbstractBeanFactory和AutowireCapableBeanFactory,实现了AbstractBeanFactory的抽象方法creatBean,并且实现了继承自AutowireCapableBeanFactory的接口,提供了bean的创建,属性填充,自动装配等功能。

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
        implements AutowireCapableBeanFactory 

了解了DefaultListableBeanFactory的继承层次后,可以知道DefaultListableBeanFactory负责的功能:bean信息的注册、bean的获取、bean的创建,同时,也支持了自动装配等功能,同时还实现了插件BeanPostProcessor,初步来看,这个beanPostProcessor可以用户实现注入到该框架当中增强spring的功能,还有一些其他功能并未细看,等到用到时候再详细解读。

至此,DefaultListableBeanFactory已经大致了解清楚。

createBeanFactory调用结束后,loadBeanDefinitions(beanFactory)是更重要的方法,因为创建出来的beanFactory对象还并未真正进行xml配置解析和信息的填充。

    @Override
    protected final void refreshBeanFactory() throws BeansException {
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());
            customizeBeanFactory(beanFactory);
            loadBeanDefinitions(beanFactory);
            synchronized (this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }

loadBeanDefinitions方法在AbstractXmlApplicationContext中继承后实现,该方法进一步调用XmlBeanDefinitionReader来解析bean信息,解析后填充到beanFactory对象中,由于该方法内部调用较为复杂,涉及相当多的对象,需要单列一章介绍。

    @Override
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        // Create a new XmlBeanDefinitionReader for the given BeanFactory.
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

        // Configure the bean definition reader with this context's
        // resource loading environment.
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

        // Allow a subclass to provide custom initialization of the reader,
        // then proceed with actually loading the bean definitions.
        initBeanDefinitionReader(beanDefinitionReader);
        loadBeanDefinitions(beanDefinitionReader);
    }

bean定义信息加载完成后,obtainFreshBeanFactory方法执行完成。

prepareBeanFactory(beanFactory)

beanFactory对象在此方法中,设置了多个属性。

    protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // Tell the internal bean factory to use the context's class loader etc.
        beanFactory.setBeanClassLoader(getClassLoader());
        beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
        beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

        // Configure the bean factory with context callbacks.
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
        beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
        beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
        beanFactory.ignoreDependencyInterface(EnvironmentAware.class);

        // BeanFactory interface not registered as resolvable type in a plain factory.
        // MessageSource registered (and found for autowiring) as a bean.
        beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
        beanFactory.registerResolvableDependency(ResourceLoader.class, this);
        beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
        beanFactory.registerResolvableDependency(ApplicationContext.class, this);

        // Detect a LoadTimeWeaver and prepare for weaving, if found.
        if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            // Set a temporary ClassLoader for type matching.
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }

        // Register default environment beans.
        if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
            beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
        }
        if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
            beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
        }
        if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
            beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
        }
    }

postProcessBeanFactory(beanFactory)

空方法,需要子类继承实现才能生效。

未完待续。

你可能感兴趣的:(Spring学习2-Bean的加载过程(IOC实现原理))