IOC容器的初始化过程
这里我们以FileSystemXmlApplicationContext为例,
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super(parent); setConfigLocations(configLocations); if (refresh) { refresh(); } }
简单来说IOC容器的初始化是通过refresh()方法来启动的,这个方法标志着IOC容器的正式启动。具体来说,这个启动包括
BeanDefinition的Resource的定位、载人和注册三个基本过程。在分析之前,Spring把这三个过程分开,并使用不同的模块来完成,如使用相应的ResourceLoader、
BeanDefinitionReader等模块,通过这样的设计方式,可以让用户更加灵活地对这三个过程进行裁剪和扩展,定义出最适合自己的IOC容器的初始化过程。
第一个过程Resource定位。这个Resource指的是BeanDefinition的资源定位,它由ResourceLoader统一的Resource接口来完成,这个Resource对各种形式的BeanDefinition
的使用都提供了统一的接口。下面清单为ResourceLoader接口定义代码:
public interface ResourceLoader { String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX; Resource getResource(String location); ClassLoader getClassLoader(); }
对于BeanDefinition的存在形式,比如在文件系统中的Bean定义信息可以使用FileSystemResource进行抽象;在类路径中的Bean定义信息可以使用ClassPathResource来使
用。
第二个过程是BeanDefinition的载入。这个载入过程是把用户定义好的Bean表示成IOC容器内部的数据结构,而这个容器内部的数据结构就是BeanDefinition。具体来说。这个
BeanDefinition实际上就是POJO对象在IOC容器中的抽象,通过这个BeanDefinition定义的数据结构,使IOC容器能够方便地对POJO对象也就是Bean进行管理。
第三个过程是向IOC容器注册这些BeanDefinition的过程。这个过程是通过调用BeanDefinitionRegistry接口的实现来完成的。这个注册过程中把载入过程中解析到的
BeanDefinition向IOC容器进行注册。通过分析,在IOC容器内部将BeanDefinition注入到一个HashMap中去,IOC容器就是通过这个HashMap来持有这些BeanDefinition数据的。下面为BeanDefinitionRegistry代码清单:
public interface BeanDefinitionRegistry extends AliasRegistry { void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException; void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException; BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException; boolean containsBeanDefinition(String beanName); String[] getBeanDefinitionNames(); int getBeanDefinitionCount(); boolean isBeanNameInUse(String beanName); }
值得注意的是,这里谈的是IOC容器初始化过程,在这个过程中,一般不包含Bean依赖注入实现,在IOC设计中,Bean定义的载入和依赖注入是两个独立的过程。依赖注入一般发
生在应用第一次通过getBean向容器索取Bean的时候。但有一个例外,在IOC容器时有一个预实例化的配置,通过这个预实例化的配置(可以通过bean定义信息的lazyinit,实
际应用中也就是spring ioc配置文件的<bean lazyinit="true">这种配置),用户可以对容器初始化过程作一个微小的控制,从而改变这个被设置lazyinit属性的Bean的依赖注入
过程。比如,如果我们对某个Bean设置了lazyinit属性,那么这个Bean的依赖注入在IOC容器初始化时就预先完成了,而不需要等到整个初始化完成以后,第一次使用getBean时
才会触发。
关于定位、载入、注册的详细分析,后面会对此阐述,这里只是让需要的人了解下基本过程。