spring1.0初探之容器初始化过程解析

上一篇我们说到了spring1.0的基本配置使用,特别需要注意的是spring1.0的bean.xml文件是没有名称空间的,只有文档的定义信息。

那么本篇,我们来看一下spring1.0版本的容器是如何初始化的,bean是怎么创建出来的,篇幅较长,请大家耐心阅读,如果有什么错误的地方,欢迎大家指正。

无论是spring1.0还是spring5.0,其核心思想都离不开容器的初始化,bean的注入,后置处理器的使用等等功能,那么spring后面的版本提供了很多复杂的功能,这对我们阅读源码有一定的影响,而spring1.0所提供的功能比较简单,阅读起来也比较方便。

好了,话不多说,我们先来看看上一篇里面,创建容器的的方法

public class MySpringTest01 {

    private ClassPathXmlApplicationContext applicationContext;

    @Before
    public void getContext(){
        //容器初始化
        applicationContext = new ClassPathXmlApplicationContext("bean01.xml");
    }

    @Test
    public void test1(){
        Person person1 = (Person) applicationContext.getBean("person");
        System.out.println("person1:" + person1);
        Person person2 = (Person) applicationContext.getBean("person");
        System.out.println("person2:" + person2);
        System.out.println(person1 == person2);
    }
}

下面我们来看一下ClassPathXmlApplicationContext这个类里面干了什么事情

public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
    private String[] configLocations;
    //这个就是我们上一步创建对象时调用的方法,传入了一个bean.xml地址的参数
    public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
        //将bean.xml文件地址保存在configLocations里面
        this.configLocations = new String[]{configLocation};
        //调用刷新容器方法
        this.refresh();
    }

    public ClassPathXmlApplicationContext(String[] configLocations) throws BeansException {
        this.configLocations = configLocations;
        this.refresh();
    }

    public ClassPathXmlApplicationContext(String[] configLocations, ApplicationContext parent) throws BeansException {
        super(parent);
        this.configLocations = configLocations;
        this.refresh();
    }

    protected String[] getConfigLocations() {
        return this.configLocations;
    }
}

我们先看下ClassPathXmlApplicationContext这个类的继承关系

spring1.0初探之容器初始化过程解析_第1张图片

可以看到ClassPathXmlApplicationContext是继承自AbstractXmlApplicationContext的,而AbstractXmlApplicationContext又继承自AbstractApplicationContext

我们看下每个父类中的方法

 spring1.0初探之容器初始化过程解析_第2张图片

 spring1.0初探之容器初始化过程解析_第3张图片

从图中我们可以看到ClassPathXmlApplicationContext调用的refresh()方法,其实就是调用父类AbstractApplicationContext的refresh()方法,那我们现在主要就是分析这个方法的执行过程

    public void refresh() throws BeansException {
		//获取当前时间
        this.startupTime = System.currentTimeMillis();
		//创建beanFactory容器,同时解析bean.xml文件,并将bean的定义信息保存起来
        this.refreshBeanFactory();
		//获取当前容器
        ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
		//设置类的属性编辑器
        beanFactory.registerCustomEditor(class$org$springframework$core$io$Resource == null ? (class$org$springframework$core$io$Resource = class$("org.springframework.core.io.Resource")) : class$org$springframework$core$io$Resource, new ContextResourceEditor(this));
		//添加自带的beanPostProcessor处理器(当前只加了ApplicationContextAwareProcessor)
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
		//设置需要忽略的接口类型
        beanFactory.ignoreDependencyType(class$org$springframework$core$io$ResourceLoader == null ? (class$org$springframework$core$io$ResourceLoader = class$("org.springframework.core.io.ResourceLoader")) : class$org$springframework$core$io$ResourceLoader);
		//设置需要忽略的接口类型
        beanFactory.ignoreDependencyType(class$org$springframework$context$ApplicationContext == null ? (class$org$springframework$context$ApplicationContext = class$("org.springframework.context.ApplicationContext")) : class$org$springframework$context$ApplicationContext);
        //空方法,留给第三方添加组件的入口
		this.postProcessBeanFactory(beanFactory);
		
		//遍历执行容器自带的beanFactoryPostProcessor
        Iterator it = this.getBeanFactoryPostProcessors().iterator();

        while(it.hasNext()) {
            BeanFactoryPostProcessor factoryProcessor = (BeanFactoryPostProcessor)it.next();
            factoryProcessor.postProcessBeanFactory(beanFactory);
        }
		
		//判断容器中所有bean定义信息总数是否为0
        if (this.getBeanDefinitionCount() == 0) {
            this.logger.warn("No beans defined in ApplicationContext [" + this.getDisplayName() + "]");
        } else {
            this.logger.info(this.getBeanDefinitionCount() + " beans defined in ApplicationContext [" + this.getDisplayName() + "]");
        }
		//遍历执行所有的beanFactoryPostProcessor
        this.invokeBeanFactoryPostProcessors();
		//添加beanPostProcessor后置处理器
        this.registerBeanPostProcessors();
		//获取国际化的bean
        this.initMessageSource();
		//空方法,后续可能会用到初始化特别的bean
        this.onRefresh();
		//往事件派发器中添加的事件
        this.refreshListeners();
		//实例化所有还未创建的单实例bean
        beanFactory.preInstantiateSingletons();
		//发布事件(当前主要发布容器启动完成事件)
        this.publishEvent(new ContextRefreshedEvent(this));
    }

可以看到,在refresh()方法中做了很多初始化的事情,那么我们今天主要讲的是bean的实例化,所以主要看this.refreshBeanFactory();和beanFactory.preInstantiateSingletons();这个方法,其他的方法,在我们后续使用的过程中,如果用到了,我们再来讲。

this.refreshBeanFactory()这个方法呢,主要就是给我们创建一个BeanFactory的默认实例,我们点进去(Ctrl+Alt+B)看下这个方法干了什么

在点进去的过程中呢,我们发现编辑器提示我们有两个类重写了这个方法,那我们到底应该去看哪一个呢?

那么在java中,子类实例化的时候呢,会优先执行父类的实例化,我们上面说了这个继承关系(ClassPathXmlApplicationContext是继承自AbstractXmlApplicationContext的,而AbstractXmlApplicationContext又继承自AbstractApplicationContext),那么在父类执行子类的方法时,那应该是谁实例化我,我就执行谁的重写方法。所以我们这个应该看AbstractXmlApplicationContext这个类中的refreshBeanFactory()方法,这一点在我们后面的源码分析中显得尤为重要,spring中用到了很多的继承和接口,所以我们看源码的过程中一定要把类继承树搞清楚。

    protected void refreshBeanFactory() throws BeansException {
        try {
            //调用创建bean的方法
            DefaultListableBeanFactory beanFactory = this.createBeanFactory();
            XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
            beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
            this.initBeanDefinitionReader(beanDefinitionReader);
            this.loadBeanDefinitions(beanDefinitionReader);
            this.beanFactory = beanFactory;
            if (this.logger.isInfoEnabled()) {
                this.logger.info("Bean factory for application context '" + this.getDisplayName() + "': " + beanFactory);
            }

        } catch (IOException var3) {
            throw new ApplicationContextException("I/O error parsing XML document for application context [" + this.getDisplayName() + "]", var3);
        }
    }

    protected DefaultListableBeanFactory createBeanFactory() {
        //直接newDefaultListableBeanFactory返回
        return new DefaultListableBeanFactory(this.getParent());
    }

在上面的方法中,我们可以看到最后的beanFactory就是new了一个DefaultListableBeanFactory对象,这个方法里面还涉及到将xml文件解析成beanDefinition,并将beanDefinition保存在DefaultListableBeanFactory的beanDefinitionNames和beanDefinitionMap两个属性中的工作,这个暂时不去拓展,感兴趣的可以自己研究。

接下来看下beanFactory.preInstantiateSingletons()这个方法,这个方法在DefaultListableBeanFactory类中

	public void preInstantiateSingletons() {
        if (this.logger.isInfoEnabled()) {
            this.logger.info("Pre-instantiating singletons in factory [" + this + "]");
        }
		//遍历beanDefinitionNames集合
        Iterator it = this.beanDefinitionNames.iterator();

        while(it.hasNext()) {
            String beanName = (String)it.next();
			//判断beanDefinitionMap是不是包含这个bean的名称
            if (this.containsBeanDefinition(beanName)) {
				//获取bean的定义信息BeanDefinition
                RootBeanDefinition bd = this.getMergedBeanDefinition(beanName, false);
				//判断bean是否为单例并且不是懒加载
                if (bd.isSingleton() && !bd.isLazyInit()) {
					//判断bean是不是FactoryBean类型的
                    if ((class$org$springframework$beans$factory$FactoryBean == null ? (class$org$springframework$beans$factory$FactoryBean = class$("org.springframework.beans.factory.FactoryBean")) : class$org$springframework$beans$factory$FactoryBean).isAssignableFrom(bd.getBeanClass())) {
                        FactoryBean factory = (FactoryBean)this.getBean("&" + beanName);
                        if (factory.isSingleton()) {
                            this.getBean(beanName);
                        }
                    } else {
						//获取bean
                        this.getBean(beanName);
                    }
                }
            }
        }

    }

根据配置及断点调试,我们的bean是在beanDefinitionMap中的,并且是单例,不是懒加载,也不是通过实现FactoryBean来创建,所以执行到这段代码的最后一步this.getBean(beanName),那么我们看看this.getBean(beanName)又做了哪些事?这个方法在AbstractBeanFactory中

	public Object getBean(String name) throws BeansException {
		//处理bean的名称,判断名称中是否包含"&",如果包含,则去掉,判断bean的名称是否用的别名,如果是,则返回别名对应的实际beanName
        String beanName = this.transformedBeanName(name);
		//从单实例bean缓存中获取bean对象
        Object sharedInstance = this.singletonCache.get(beanName);
		//如果对象不为空,则返回这个对象
        if (sharedInstance != null) {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
            }
			//去判断这个对象是否需要由FactoryBean来创建,如果不是,则直接返回该对象
            return this.getObjectForSharedInstance(name, sharedInstance);
        } else {//如果缓存中没有这个对象
            RootBeanDefinition mergedBeanDefinition = null;

            try {
				//获取该bean的定义信息
                mergedBeanDefinition = this.getMergedBeanDefinition(beanName, false);
            } catch (NoSuchBeanDefinitionException var7) {
                if (this.parentBeanFactory != null) {
                    return this.parentBeanFactory.getBean(name);
                }

                throw var7;
            }
			//判断bean是否是单例
            if (mergedBeanDefinition.isSingleton()) {
                synchronized(this.singletonCache) {
					//如果是单例,则从缓存中获取一次
                    sharedInstance = this.singletonCache.get(beanName);
					//如果缓存中没有
                    if (sharedInstance == null) {
                        this.logger.info("Creating shared instance of singleton bean '" + beanName + "'");
						//创建bean对象
                        sharedInstance = this.createBean(beanName, mergedBeanDefinition);
						//添加到缓存中
                        this.addSingleton(beanName, sharedInstance);
                    }
                }
				//再执行一次返回bean的逻辑(去判断这个对象是否需要由FactoryBean来创建,如果不是,则直接返回该对象)
                return this.getObjectForSharedInstance(name, sharedInstance);
            } else {
				//如果不是单实例,则直接调用创建bean的方法,但是不会去缓存这个bean
                return this.createBean(name, mergedBeanDefinition);
            }
        }
    }

由于这里我们是创建一个普通的bean,没有通过实现FactoryBean方式来创建bean,所以暂时不考虑这种方法,等到后面我们用到的时候,再去分析。我们先暂且看普通bean的创建方式,根据注释,我们知道一般的bean是调用this.createBean(beanName, mergedBeanDefinition)来创建bean,那我们来断点调试一下具体是怎么创建的。

this.createBean(beanName, mergedBeanDefinition)的具体实现是在AbstractAutowireCapableBeanFactory中的,为什么会在这个类中,就像上面我们提到的,还是得看继承关系:

可以看到AbstractBeanFactory调用createBean其实就是调用子类AbstractAutowireCapableBeanFactory的createBean

	protected Object createBean(String beanName, RootBeanDefinition mergedBeanDefinition) throws BeansException {
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Creating instance of bean '" + beanName + "' with merged definition [" + mergedBeanDefinition + "]");
        }
		//判断该bean是否有依赖,如果有依赖,则先创建依赖bean,又走一遍上一步的getBean方法
        if (mergedBeanDefinition.getDependsOn() != null) {
            for(int i = 0; i < mergedBeanDefinition.getDependsOn().length; ++i) {
                this.getBean(mergedBeanDefinition.getDependsOn()[i]);
            }
        }
		//创建一个bean的包装对象(将bean封装到这个对象中,这样对spring内部提供了统一的bean访问方式,包括bean的实例,bean的属性等等)
        BeanWrapper instanceWrapper = null;
		//判断这个bean创建时,是否调用了有参构造器
        if (mergedBeanDefinition.getResolvedAutowireMode() != 3 && !mergedBeanDefinition.hasConstructorArgumentValues()) {//如果没有有参构造器
			//直接创建bean并包装成BeanWrapper
            instanceWrapper = new BeanWrapperImpl(mergedBeanDefinition.getBeanClass());
			//解析这个实例的属性,并封装到BeanWrapper
            this.initBeanWrapper((BeanWrapper)instanceWrapper);
        } else {
            instanceWrapper = this.autowireConstructor(beanName, mergedBeanDefinition);
        }
		//通过BeanWrapper获取到当前这个对象的bean实例
        Object bean = ((BeanWrapper)instanceWrapper).getWrappedInstance();
		//如果这个bean是单例,则添加到单例容器中
        if (mergedBeanDefinition.isSingleton()) {
            this.addSingleton(beanName, bean);
        }
		//为这个实例进行赋值操作
        this.populateBean(beanName, mergedBeanDefinition, (BeanWrapper)instanceWrapper);

        try {
			//判断当前bean是否实现了BeanNameAware接口,如果有,则执行这个接口的实现方法
            if (bean instanceof BeanNameAware) {
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Invoking setBeanName() on BeanNameAware bean '" + beanName + "'");
                }

                ((BeanNameAware)bean).setBeanName(beanName);
            }
			//判断这个bean是否实现了BeanFactoryAware接口,如果有,则执行这个接口的实现方法
            if (bean instanceof BeanFactoryAware) {
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Invoking setBeanFactory() on BeanFactoryAware bean '" + beanName + "'");
                }

                ((BeanFactoryAware)bean).setBeanFactory(this);
            }
			//执行这个bean的后置处理器的初始化方法执行之前的方法
            bean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
			//执行这个bean的初始化方法(注意,不是实例化方法,初始化方法是可以在xml设定的,默认没有)
            this.invokeInitMethods(bean, beanName, mergedBeanDefinition);
			//执行这个bean的后置处理器的初始化方法执行之后的方法
            bean = this.applyBeanPostProcessorsAfterInitialization(bean, beanName);
			//返回这个bean
            return bean;
        } catch (InvocationTargetException var6) {
            throw new BeanCreationException(mergedBeanDefinition.getResourceDescription(), beanName, "Initialization of bean failed", var6.getTargetException());
        } catch (Exception var7) {
            throw new BeanCreationException(mergedBeanDefinition.getResourceDescription(), beanName, "Initialization of bean failed", var7);
        }
    }

至此,我们这个bean就已经创建完成了,并可以在容器中使用了。下一节,我们将介绍FactoryBean创建bean的方式。

你可能感兴趣的:(spring演变史,spring,java)