前面讲过,spring的生命周期为:实例化前奏-->实例化-->实例化后期-->初始化前期-->初始化-->初始化后期-->bean的具体调用-->销毁前-->销毁。那么,从装配XML属性到实例化bean的内部机制是怎样的,没有细说,今天我们来一起刨根问底。
还是老风格,以具体例子先入为主。下面是一个再简单不过的spring框架的栗子。(XML,有。Bean,有。Spring容器,有。main函数,有。麻雀虽小,但是够了。)
这是XML,简单易懂,嘎嘣脆:
1 。。。。。。 2 3 <bean id="car" class="com.mesopotamia.test1.Car" 4 p:brand="宝马X5" 5 p:maxSpeed="200"/> 6 beans>
这是Bean,要个子有个子,要西一翁有西一翁:
代码001 1 public class Car { 2 private String name; 3 private String brand; 4 private double maxSpeed; 5 public double getMaxSpeed() { 6 return maxSpeed; 7 } 8 public void setMaxSpeed(double maxSpeed) { 9 this.maxSpeed = maxSpeed; 10 } 11 12 13 private Log log=LogFactory.getLog(Car.class); 14 15 public Car(){ 16 name="宝马"; 17 log.info("调用了Car的构造函数,实例化了Car,并把Car的name属性设为:"+name); 18 } 19 public String getName() { 20 return name; 21 } 22 public void setName(String name) { 23 this.name = name; 24 } 25 public String getBrand() { 26 return brand; 27 } 28 public void setBrand(String brand) { 29 this.brand = brand; 30 } 31 32 33 public String toString(){ 34 return "名字"+name+" 型号"+" 速度:"+maxSpeed; 35 } 36 37 38 }
下面是启动函数,精悍!干练:
代码002 1 public class Main { 2 private static Log log=LogFactory.getLog(Main.class); 3 4 public static void main(String args[]){ 5 ApplicationContext ctx = new ClassPathXmlApplicationContext("com/mesopotamia/test1/*.xml"); 6 Car car1 = ctx.getBean("car",Car.class); 7 log.info(car1.toString()); 8 }
但是我要讲的重点是main函数跑起来后的日志:
代码003 1 2016-11-25 20:19:04,318 INFO [main] (AbstractApplicationContext.java:456) - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1ff5ea7: startup date [Mon Nov 16 20:19:04 CST 2015]; root of context hierarchy 2 2016-11-25 20:19:04,371 INFO [main] (XmlBeanDefinitionReader.java:315) - Loading XML bean definitions from file [C:\MySoftware\workspace\springtest\WebRoot\WEB-INF\classes\com\mesopotamia\test1\beans.xml] 3 2016-11-25 20:19:04,482 INFO [main] (DefaultListableBeanFactory.java:555) - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@6e293a: defining beans [car]; root of factory hierarchy 4 2016-11-25 20:19:04,483 INFO [main] (Car.java:22) - 调用了Car的构造函数,实例化了Car,并把Car的name属性设为:宝马 5 2016-11-25 20:19:04,533 INFO [main] (Main.java:15) - 名字宝马 型号 速度:200.0
一开始就加载了AbstractApplicationContext里的方法,那么这个方法做了什么?实际上,第一行是由AbstractApplicationContext的refresh()方法打印出的,容器一启动就要加载这个方法,让我们来揭开refresh()的面纱吧。
首先,这个AbstractApplicationContext必须是ClassPathXmlApplicationContext的父类,否则代码002的第5行怎么一跑起来会跑到AbstractApplicationContext里面的方法里去?孩子被打,当然是去叫爹咯。
在MyEclipse里,我们按住ctrl键,点击ClassPathXmlApplicationContext一路点下去你就发现其中的继承关系(姑且用—>表示子类指向被继承的父类):
ClassPathXmlApplicationContext —> AbstractXmlApplicationContext —>AbstractRefreshableConfigApplicationContext —>AbstractRefreshableApplicationContext—>AbstractApplicationContext。
我们进入AbstractApplicationContext,看到refresh()方法的庐山真面目:
1 public void refresh() throws BeansException, IllegalStateException { 2 synchronized (this.startupShutdownMonitor) { 3 // Prepare this context for refreshing. 4 prepareRefresh(); 5 6 // Tell the subclass to refresh the internal bean factory. 7 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); 8 9 // Prepare the bean factory for use in this context. 10 prepareBeanFactory(beanFactory); 11 12 try { 13 // Allows post-processing of the bean factory in context subclasses. 14 postProcessBeanFactory(beanFactory); 15 16 // Invoke factory processors registered as beans in the context. 17 invokeBeanFactoryPostProcessors(beanFactory); 18 19 // Register bean processors that intercept bean creation. 20 registerBeanPostProcessors(beanFactory); 21 22 // Initialize message source for this context. 23 initMessageSource(); 24 25 // Initialize event multicaster for this context. 26 initApplicationEventMulticaster(); 27 28 // Initialize other special beans in specific context subclasses. 29 onRefresh(); 30 31 // Check for listener beans and register them. 32 registerListeners(); 33 34 // Instantiate all remaining (non-lazy-init) singletons. 35 finishBeanFactoryInitialization(beanFactory); 36 37 // Last step: publish corresponding event. 38 finishRefresh(); 39 } 40 41 catch (BeansException ex) { 42 // Destroy already created singletons to avoid dangling resources. 43 destroyBeans(); 44 45 // Reset 'active' flag. 46 cancelRefresh(ex); 47 48 // Propagate exception to caller. 49 throw ex; 50 } 51 } 52 }
人生若只如初见,看到这如此美丽的代码是否惊呆了天真烂漫的你?OK,我知道你英语没我好,我就大概讲一下这refresh()里面都干了些什么,这些步骤实际上就是实例化之前的一系列美丽动作:
第9行:准备bean factory (BeanFactory是spring框架的基础设施)
第16行:调用被注册为bean的BeanFactoryPostProcessors(工厂后处理器) (工厂后处理器负责对实例化之前未成形的bean进行加工处理)
第19行:注册BeanPostProcessors(Bean后处理器)来阻挡bean的创建。 (实例化后的bean需要用这个后处理器来进一步加工)
第22行:初始化消息源(国际化信息资源)。 (国际化很容易理解吧?比如微信可以切换中英文版本等等,后面会独列篇幅讲解)
第25行:初始化应用上下文事件广播器。 (spring有一套完善的事件发布和监听机制,事件广播器负责把事件通知给监听器,监听器来执行事件。后面会独列篇幅讲解)。
第28行:初始化其他特殊的bean。
第31行:检查是否有监听器然后注册监听器(监听器就跟bean一样,需要放在注册表中。后面会独列篇幅讲解)。
第34行:初始化所有单实例的bean(懒模式bean除外),单实例的bean初始化后把bean的引用放在spring容器的缓存中,调用者使用的是同一个额引用,任何一个调用者对bean的修改都会影响其他调用者。懒模式是指,spring容器启动时不会初始化,而在需要用到该bean时才初始化。XML
第37行:创建上下文刷新事件,发布广播器。 (事件机制后面会独列篇幅讲解)
上面这些就是bean实例化前后的细枝末节了。那么上面的什么工厂后处理器,bean后处理器被调用后又是怎样处理的呢?
下面我们来细化一下创建一个完整的bean的作业流程:
整体是下面这样的:
简单点:
读取XML,转化并加工成BeanDefinition,实例化BeanDefinition。
具体点:
ResourceLoader加载XML配置信息后,由BeanDefinitionReader读取配置信息文件,把每个
再具体点:
1 <bean id="simpleBean" class="com.spring.ch04.SimplePostProcessor"> 2 <property name="connectionString" value="${simpleBean.connectionString}"/> 3 <property name="password" value="${simpleBean.password}"/> 4 <property name="username" value="${simpleBean.username}"/> 5 6 bean>