码迷,mamicode.com
首页 > 编程语言 > 详细

Spring-IOC源码解读2-容器的初始化过程

时间:2017-10-15 17:40:24      阅读:265      评论:0      收藏:0      [点我收藏+]

标签:java   代码   .config   protect   final   eset   不包含   ecif   int   

1. IOC容器的初始化过程:IOC容器的初始化由refresh()方法启动,这个启动包括:BeanDifinition的Resource定位,加载和注册三个过程。初始化的过程不包含Bean依赖注入的实现。

  •  第一个过程是Resource的定位过程。这个Resource的定位指的是BeanDefinition的资源定位,它由ResourceLoader通过统一的Resource接口完成。
  •  第二个过程是BeanDefinition的载入,这个过程是把用户定义好的Bean表示为容器的内部数据结构(即BeanDefinition)
  •  第三个过程是向IOC容器注册这些BeanDefinition的过程。

2. 下面我们以ClassPathXmlApplicationContext 为例分析这个ApplicationContext的实现,使用的spring版本是3.0.2版本。首先看下我们测试的代码和配置文件:

  • 2.1:javaBean的定义
public class Person {
	private String name;
	private int age;
	private int sex;
	private Dog dog;
	private List<Address> addressList;
       } public class Dog { private String dogName; } public class Address { private String type; private String city; }
  • 2. 2beans.xml文件定义:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://www.springframework.org/schema/beans"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    <!-- person对象 -->
	<bean id="person" class="com.pepper.spring.model.Person" >
		<property name="name" value="pepper" />
		<property name="age" value="24" />
		<property name="sex" value="1" />
		<property name="dog" ref="dog" />
		<property name="addressList">
			<list>
				<ref bean="home"/>
				<ref bean="work"/>
			</list>
		</property>
	</bean>
	
	<!-- person对象的Dog属性 -->
	<bean id="dog" class="com.pepper.spring.model.Dog">
		<property name="dogName" value="Edward" />
	</bean>
	
	<!-- person对象AddressList属性的两个值 -->
	<bean id="home" class="com.pepper.spring.model.Address">
		<property name="type" value="home" />
		<property name="city" value="SX" />
	</bean>
	<bean id="work" class="com.pepper.spring.model.Address">
		<property name="type" value="work" />
		<property name="city" value="SZ" />
	</bean>
</beans>
  • 2.3. 容器启动类:
public class TestSpring {

	public static final String BEAN_CONFIG_FILE = "E:/workspace_selflearn/read-spring/src/spring-beans.xml";
	public static final String BEAN_CONFIG_CLASS = "spring-beans.xml";
	
	public static void main(String[] args) {
		testApplicationContext();
	}
	//使用XmlBeanFactory
	public static void testBeanFactory() {
		Resource res = new ClassPathResource(BEAN_CONFIG_CLASS);
		BeanFactory fac = new XmlBeanFactory(res);
		Person p = fac.getBean("person", Person.class);
		System.out.println(p);
	}
	
        //使用ApplicationContext
	public static void testApplicationContext() {
		ApplicationContext ac = null;
	     // ac = new FileSystemXmlApplicationContext(BEAN_CONFIG_FILE);
		ac = new ClassPathXmlApplicationContext(BEAN_CONFIG_CLASS);
		Person p = ac.getBean("person", Person.class);
		System.out.println(p);
	}
}

3. 我们先看下ClassPathXmlApplicationContext类的定义:

public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {

    private Resource[] configResources;

    public ClassPathXmlApplicationContext() {
    }

    public ClassPathXmlApplicationContext(ApplicationContext parent) {
        super(parent);
    }
    // configLocation对象表示BeanDefinition所在的文件路径
    public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
        this(new String[] {configLocation}, true, null);
    }
    // Spring支持传入多个BeanDefinition配置文件
    public ClassPathXmlApplicationContext(String... configLocations) throws BeansException {
        this(configLocations, true, null);
    }
    // 此构造方法除了包含配置文件路径,还允许指定想要使用的父类IOC容器
    public ClassPathXmlApplicationContext(String[] configLocations, ApplicationContext parent) throws BeansException {
        this(configLocations, true, parent);
    }

    public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh) throws BeansException {
        this(configLocations, refresh, null);
    }
    //对象的初始化过程中,调用refresh()方法启动BeanDefinition的载入过程
    public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)throws BeansException {
        super(parent);
        setConfigLocations(configLocations);
        if (refresh) {
            refresh();
        }
    }

    public ClassPathXmlApplicationContext(String[] paths, Class clazz) throws BeansException {
        this(paths, clazz, null);
    }

    public ClassPathXmlApplicationContext(String[] paths, Class clazz, ApplicationContext parent) throws BeansException {

        super(parent);
        Assert.notNull(paths, "Path array must not be null");
        Assert.notNull(clazz, "Class argument must not be null");
        this.configResources = new Resource[paths.length];
        for (int i = 0; i < paths.length; i++) {
            this.configResources[i] = new ClassPathResource(paths[i], clazz);
        }
        refresh();
    }
    //这是应用于类路径上的Resource实现,这个getResource是在BeanDefinitionReader类(AbstractXmlApplicationContext)的loadBeanDefinition方法中调用的,
//loadBeanDefinition采用了模板方法设计模式,具体的实现实际是由各个子类来实现的。 @Override protected Resource[] getConfigResources() { return this.configResources; } } 

容器启动的时候会调用ClassPathXmlApplicationContext的构造方法,在这个构造方法中会调用refresh()方法,这个方法十分重要,这是我们分析容器初始化过程中至关重要的一个接口,我们后面分析的Bean的载入,解析,注册都是以这个方法作为入口开始的。

public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.准备上下文
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.通知子类刷新内部的bean工厂
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.准备beanfactory来使用这个上下文.做一些准备工作,例如classloader,beanfactoryPostProcessor等
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.在子类上下文中允许beanfactory进行后置处理
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.调用工厂处理器作为bean注册到上下文中
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.开始注册BeanPostProcessor来拦截bean的创建过程
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.为上下文初始化消息源
                initMessageSource();

                // Initialize event multicaster for this context.为上下文初始化事件广播
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.在具体的子类上下文中初始化特殊的bean
                onRefresh();

                // Check for listener beans and register them.检查监听器bean并注册
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.实例化所有的剩余的singleton的bean
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.最后一步,发布应用
                finishRefresh();
            }

            catch (BeansException ex) {
                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

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

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

  

 

Spring-IOC源码解读2-容器的初始化过程

标签:java   代码   .config   protect   final   eset   不包含   ecif   int   

原文地址:http://www.cnblogs.com/pepper7/p/7672560.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!