Spring-IOC源碼解讀2-容器的初始化過程
阿新 • • 發佈:2017-10-15
創建 對象 配置文件 instance tee rem leg source lag
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-容器的初始化過程