【spring mvc】application context的生命周期
上一次讲application context中bean的生命周期,后面贴了一部分代码,但根本没理解代码意思,有幸在博客园看到一篇关于这部分的代码解析,特别长,特此做了一些整理笔记,并附上链接:http://www.cnblogs.com/ITtangtang/p/3978349.html
这部分内容从application context的创建开始讲起,上次讲bean的生命周期时,默认application context已经创建完了,但这部分是怎么创建的也不是特别清楚,这次弄明白一下。
下面主要分为四部分:
1、ioc容器(application context)的创建;
2、读取配置文件,加载BeanDefinition(Bean定义资源)到ioc容器中;
3、实例化Bean
4、设置属性值,即执行setXxx()方法
下面依次解读代码:
1、ioc容器的创建
ApplicationContext =new FileSystemXmlApplicationContext(xmlPath);
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super(parent); setConfigLocations(configLocations); if (refresh) { refresh(); } }
分析FileSystemXmlApplicationContext的源代码可以知道,在创建FileSystemXmlApplicationContext容器时,构造方法做以下两项重要工作:
- 调用父类容器的构造方法(super(parent)方法)为容器设置好Bean资源加载器。
- 再调用父类AbstractRefreshableConfigApplicationContext的setConfigLocations(configLocations)方法设置Bean定义资源文件的定位路径。
- refresh()方法的作用是:在创建IoC容器前,如果已经有容器存在,则需要把已有的容器销毁和关闭,以保证在refresh之后使用的是新建立起来的IoC容器。refresh的作用类似于对IoC容器的重启,在新建立好的容器中对容器进行初始化,对Bean定义资源进行载入
2、BeanDefinition的加载
Spring IoC容器对BeanDefinition(即Bean定义资源)的载入是从refresh()函数开始的。
FileSystemXmlApplicationContext通过调用其父类AbstractApplicationContext的refresh()函数启动整个IoC容器对Bean定义的载入过程:
通过 ResourceLoader 来完成资源文件位置的定位,可以从类路径,文件系统, URL 等方式来定为资源位置。如果是 XmlBeanFactory作为 IOC 容器,容器通过使用XmlBeanDefinitionReader 来解析读取bean的xml定义文件,然后加载bean的定义信息,并将XML的定义信息转换为Document对象。
之后,按照Spring的Bean规则对Document对象进行解析。经过对Spring Bean定义资源文件转换的Document对象中的元素层层解析,Spring IoC现在已经将XML形式定义的Bean定义资源文件转换为Spring IoC所识别的数据结构——BeanDefinition,它是Bean定义资源文件中配置的POJO对象在Spring IoC容器中的映射。所以在解析<Bean>元素过程中没有创建和实例化Bean对象,只是创建了Bean对象的定义类BeanDefinition,将<Bean>元素中的配置信息设置到BeanDefinition中作为记录,当依赖注入时才使用这些记录信息创建和实例化具体的Bean对象。
容器解析得到 BeanDefinition后,需要把它在 IOC 容器中注册,这由 IOC 实现 BeanDefinitionRegistry 接口来实现。注册过程就是在 IOC 容器内部维护的一个HashMap 来保存得到的 BeanDefinition 的过程。这个 HashMap 是 IoC 容器持有 bean 信息的场所,以后对 bean 的操作都是围绕这个HashMap 来实现的。
Bean定义资源文件中配置的Bean被解析成BeanDefinition,注册到IoC容器中,被容器管理起来,真正完成了IoC容器初始化所做的全部工作。现 在IoC容器中已经建立了整个Bean的配置信息,这些BeanDefinition信息已经可以使用,并且可以被检索,IoC容器的作用就是对这些注册的Bean定义信息进行处理和维护。这些的注册的Bean定义信息是IoC容器控制反转的基础,正是有了这些注册的数据,容器才可以进行依赖注入。
3、Bean的实例化
Spring IoC容器完成了Bean定义资源的定位、载入和解析注册以后,IoC容器中已经管理类Bean定义的相关数据,但是此时IoC容器还没有对所管理的Bean进行依赖注入,依赖注入在以下两种情况发生:
(1).用户第一次通过getBean方法向IoC容索要Bean时,IoC容器触发依赖注入。
(2).当用户在Bean定义资源中为<Bean>元素配置了lazy-init属性,即让容器在解析注册Bean定义时进行预实例化,触发依赖注入。
BeanFactory接口中定义了几个getBean方法,就是用户向IoC容器索取管理的Bean的方法。当调用者通过 getBean( name )向容器寻找Bean时,就可以开始看Bean的生命周期了。详见:http://www.cnblogs.com/hantalk/p/6644701.html
如果Bean定义的单态模式(Singleton),则容器在创建之前先从缓存中查找,以确保整个容器中只存在一个实例对象。如果Bean定义的是原型模式(Prototype),则容器每次都会创建一个新的实例对象。
Ioc容器从BeanDefinitionRegistry中取出BeanDefinition对象,调用InstantiationStrategy,采用反射机制进行Bean实例化的工作。InstantiationStrategy仅负责实例化Bean的操作,相当于执行Java语言中new的功能,不会参与Bean属性的设置工作。
1 //使用初始化策略实例化Bean对象 2 public Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) { 3 //如果Bean定义中没有方法覆盖,则就不需要CGLIB父类类的方法 4 if (beanDefinition.getMethodOverrides().isEmpty()) { 5 Constructor<?> constructorToUse; 6 synchronized (beanDefinition.constructorArgumentLock) { 7 //获取对象的构造方法或工厂方法 8 constructorToUse = (Constructor<?>) beanDefinition.resolvedConstructorOrFactoryMethod; 9 //如果没有构造方法且没有工厂方法 10 if (constructorToUse == null) { 11 //使用JDK的反射机制,判断要实例化的Bean是否是接口 12 final Class clazz = beanDefinition.getBeanClass(); 13 if (clazz.isInterface()) { 14 throw new BeanInstantiationException(clazz, "Specified class is an interface"); 15 } 16 try { 17 if (System.getSecurityManager() != null) { 18 //这里是一个匿名内置类,使用反射机制获取Bean的构造方法 19 constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor>() { 20 public Constructor run() throws Exception { 21 return clazz.getDeclaredConstructor((Class[]) null); 22 } 23 }); 24 } 25 else { 26 constructorToUse = clazz.getDeclaredConstructor((Class[]) null); 27 } 28 beanDefinition.resolvedConstructorOrFactoryMethod = constructorToUse; 29 } 30 catch (Exception ex) { 31 throw new BeanInstantiationException(clazz, "No default constructor found", ex); 32 } 33 } 34 } 35 //使用BeanUtils实例化,通过反射机制调用”构造方法.newInstance(arg)”来进行实例化 36 return BeanUtils.instantiateClass(constructorToUse); 37 } 38 else { 39 //使用CGLIB来实例化对象 40 return instantiateWithMethodInjection(beanDefinition, beanName, owner); 41 } }
4、Bean的属性注入
Spring IoC容器是如何将属性的值注入到Bean实例对象中去的,通过BeanWrapper将Bean包装起来,从Bean对应的BeanDefinition中获取Bean属性的配置信息PropertyValue,然后进行类型转换解析:
(1).对于集合类型list,array,map的属性,将其属性值解析为目标类型的集合后直接赋值给属性。
(2).对于非集合类型的属性,大量使用了JDK的反射和内省机制,通过属性的getter方法(reader method)获取指定属性注入以前的值,同时调用属性的setter方法(writer method)为属性设置注入后的值。看到这里相信很多人都明白了Spring的setter注入原理。
5、关于Bean懒加载的实例化,可参考这篇文章:http://blog.csdn.net/chjttony/article/details/6278627
简单就是说:在上面“2、BeanDefinition的加载”中执行refresh()函数时,在此进行实例化。
ApplicationContext实现的默认行为就是在启动时将所有singleton bean提前进行实例化。也就是说,默认情况下lazy-init=false(不延迟加载),大部分的bean默认在refresh()的时候进行bean的预实例化,提前注入。而lazy-init=true时,才不会提前实例化,等到beandefinition加载完了再实例化。
//容器初始化的过程,读入Bean定义资源,并解析注册 2 public void refresh() throws BeansException, IllegalStateException { 3 synchronized (this.startupShutdownMonitor) { 4 //调用容器准备刷新的方法,获取容器的当时时间,同时给容器设置同步标识 5 prepareRefresh(); 6 //告诉子类启动refreshBeanFactory()方法,Bean定义资源文件的载入从 7 //子类的refreshBeanFactory()方法启动 8 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); 9 //为BeanFactory配置容器特性,例如类加载器、事件处理器等 10 prepareBeanFactory(beanFactory); 11 try { 12 //为容器的某些子类指定特殊的BeanPost事件处理器 13 postProcessBeanFactory(beanFactory); 14 //调用所有注册的BeanFactoryPostProcessor的Bean 15 invokeBeanFactoryPostProcessors(beanFactory); 16 //为BeanFactory注册BeanPost事件处理器. 17 //BeanPostProcessor是Bean后置处理器,用于监听容器触发的事件 18 registerBeanPostProcessors(beanFactory); 19 //初始化信息源,和国际化相关. 20 initMessageSource(); 21 //初始化容器事件传播器. 22 initApplicationEventMulticaster(); 23 //调用子类的某些特殊Bean初始化方法 24 onRefresh(); 25 //为事件传播器注册事件监听器. 26 registerListeners(); 27 //这里是对容器lazy-init属性进行处理的入口方法 28 finishBeanFactoryInitialization(beanFactory); 29 //初始化容器的生命周期事件处理器,并发布容器的生命周期事件 30 finishRefresh(); 31 } 32 catch (BeansException ex) { 33 //销毁以创建的单态Bean 34 destroyBeans(); 35 //取消refresh操作,重置容器的同步标识. 36 cancelRefresh(ex); 37 throw ex; 38 } 39 } }
AbstractApplicationContext类中的finishBeanFactoryInitialization方法对配置了预实例化属性的Bean进行预初始化过程,
//对配置了lazy-init属性的Bean进行预实例化处理 2 protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { 3 //这是Spring3以后新加的代码,为容器指定一个转换服务(ConversionService) 4 //在对某些Bean属性进行转换时使用 5 if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) && 6 beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) { 7 beanFactory.setConversionService( 8 beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)); 9 } 10 //为了类型匹配,停止使用临时的类加载器 11 beanFactory.setTempClassLoader(null); 12 //缓存容器中所有注册的BeanDefinition元数据,以防被修改 13 beanFactory.freezeConfiguration(); 14 //对配置了lazy-init属性的单态模式Bean进行预实例化处理 15 beanFactory.preInstantiateSingletons(); }
ConfigurableListableBeanFactory是一个接口,其preInstantiateSingletons方法由其子类DefaultListableBeanFactory提供。
1//对配置lazy-init属性单态Bean的预实例化 2public void preInstantiateSingletons() throws BeansException { 3 if (this.logger.isInfoEnabled()) { 4 this.logger.info("Pre-instantiating singletons in " + this); 5 } 6 //在对配置lazy-init属性单态Bean的预实例化过程中,必须多线程同步,以确保数据一致性 7 synchronized (this.beanDefinitionMap) { 8 for (String beanName : this.beanDefinitionNames) { 9 //获取指定名称的Bean定义 10 RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); 11 //Bean不是抽象的,是单态模式的,且lazy-init属性配置为false 12 if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { 13 //如果指定名称的bean是创建容器的Bean 14 if (isFactoryBean(beanName)) { 15 //FACTORY_BEAN_PREFIX=”&”,当Bean名称前面加”&”符号 16 //时,获取的是产生容器对象本身,而不是容器产生的Bean. 17 //调用getBean方法,触发容器对Bean实例化和依赖注入过程 18 final FactoryBean factory = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName); 19 //标识是否需要预实例化 20 boolean isEagerInit; 21 if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { 22 //一个匿名内部类 23 isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() { 24 public Boolean run() { 25 return ((SmartFactoryBean) factory).isEagerInit(); 26 } 27 }, getAccessControlContext()); 28 } 29 else { 30 isEagerInit = factory instanceof SmartFactoryBean && ((SmartFactoryBean) factory).isEagerInit(); 31 } 32 if (isEagerInit) { 33 //调用getBean方法,触发容器对Bean实例化和依赖注入过程 34 getBean(beanName); 35 } 36 } 37 else { 38 //调用getBean方法,触发容器对Bean实例化和依赖注入过程 39 getBean(beanName); 40 } 41 } 42 } 43 } }
推荐参考链接: