1.IOC容器初始化
(1)xmlBeanFactory的IOC容器流程
(2)FileSystemXmlApplicationContext 的IOC容器流程
2.IOC容器依赖注入
IOC容器初始化
IoC容器的初始化包括BeanDefinition的Resource定位、载入和注册这三个基本的过程。
一.xmlBeanFactory的IOC容器流程
BeanFactory b=new XmlBeanFactory(new ClassPathResource(“beanFactryTest.xml”));
xmlBeanFactory类真正实现资源加载是loanBeanDefinitions(resource)方法。
public class XmlBeanFactory extends DefaultListableBeanFactory{
private final XmlBeanDefinitionReader reader;
public XmlBeanFactory(Resource resource)throws BeansException{
this(resource, null);
}
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException{
super(parentBeanFactory);
this.reader = new XmlBeanDefinitionReader(this);
this.reader.loadBeanDefinitions(resource);
}
}
//根据Xml配置文件创建Resource资源对象,该对象中包含了BeanDefinition的信息
ClassPathResource resource =new ClassPathResource("application-context.xml");//创建DefaultListableBeanFactory
DefaultListableBeanFactory factory =new DefaultListableBeanFactory();//创建XmlBeanDefinitionReader读取器,用于载入BeanDefinition。之所以需要BeanFactory作为参数,是因为会将读取的信息回调配置给factory
XmlBeanDefinitionReader reader =new XmlBeanDefinitionReader(factory);//XmlBeanDefinitionReader执行载入BeanDefinition的方法,最后会完成Bean的载入和注册。完成后Bean就成功的放置到IOC容器当中,以后我们就可以从中取得Bean来使用
reader.loadBeanDefinitions(resource);
1.loanBeanDefinitions方法实现:
(1)封装资源文件。当进入XmlBeanDefiniftionReader后首先对参数Resource使用EncodeResource类进行封装。
loadBeanDefinitions(new EncodeResource(resource));
(2)获取输入流。从Resource中获取对应的ImputStream并构造InputSource.
InputStream inputStream=encodeResource.getResource().getInputStream();
InputSource inputSource=new InputSource(inputStream);
(3)通过构造的inputSource实例和Resource实例继续调用doLoadBeanDefinitions.
doLoanBeanDefinitions(inputSource,encodedResource.getResource());
2.doLoanBeanDefinitions方法实现:
(1)获取对XML文件的验证模式。
代码:getValidationModeForResource(resource);
DTD:文档类型定义,包含元素的定义规则,元素间关系的定义规则,元素可使用属性,可使用实体或符号规则。检测XML文档格式是否符合规范,元素和标签使用是否正确。
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
XSD:描述了XML文档的结构。检测XML文档是否符合其要求。
<beans xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd”>
(2)加载XML文件,并得到对应的Document.
代码:
Documnet doc=this.documentLoader.loadDocumnet(inputSource,getEntityResolver(),
this.errorHandler,validationMode,isNamespaceAware());
获取Document首先创建DocumentBuilderFactory,在通过DocumentBuilderFactory创建DocumentBuilder,进而解析inputSource来返回Document对象。
DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
Document=builder.parse(inputSource);
(3)根据返回的Document注册Bean信息。
代码:registerBeanDefinitions(doc,resource);
registerBeanDefinitions实现:
1.实例化documentReader
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
2.documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
registerBeanDefinitions实现:
调用doRegisterBeanDefinitions方法实现parseBeanDefitions(root,this.delegate);
parseBeanDefitions根据不同标签进行处理(import,alias,bean,beans)
二.FileSystemXmlApplicationContext 的IOC容器流程
ApplicationContext =new FileSystemXmlApplicationContext(xmlPath);
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
(super(parent)方法)为容器设置好Bean资源加载器
setConfigLocations(configLocations)方法设置Bean定义资源文件的定位路径。
Spring IoC容器对Bean定义资源的载入是从refresh()函数开始的,refresh()是一个模板方法,refresh()方法的作用是:在创建IoC容器前,如果已经有容器存在,则需要把已有的容器销毁和关闭,以保证在refresh之后使用的是新建立起来的IoC容器。refresh的作用类似于对IoC容器的重启,在新建立好的容器中对容器进行初始化,对Bean定义资源进行载入。
refresh方法实现:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//调用容器准备刷新的方法,获取容器的当时时间,同时给容器设置同步标识
prepareRefresh();
//告诉子类启动refreshBeanFactory()方法,Bean定义资源文件的载入从
//子类的refreshBeanFactory()方法启动
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//为BeanFactory配置容器特性,例如类加载器、事件处理器等
prepareBeanFactory(beanFactory);
try {
//为容器的某些子类指定特殊的BeanPost事件处理器
postProcessBeanFactory(beanFactory);
//调用所有注册的BeanFactoryPostProcessor的Bean
invokeBeanFactoryPostProcessors(beanFactory);
//为BeanFactory注册BeanPost事件处理器.
//BeanPostProcessor是Bean后置处理器,用于监听容器触发的事件
registerBeanPostProcessors(beanFactory);
//初始化信息源,和国际化相关.
initMessageSource();
//初始化容器事件传播器.
initApplicationEventMulticaster();
//调用子类的某些特殊Bean初始化方法
onRefresh();
//为事件传播器注册事件监听器.
registerListeners();
//初始化所有剩余的单态Bean.
finishBeanFactoryInitialization(beanFactory);
//初始化容器的生命周期事件处理器,并发布容器的生命周期事件
finishRefresh();
}
catch (BeansException ex) {
//销毁以创建的单态Bean
destroyBeans();
//取消refresh操作,重置容器的同步标识.
cancelRefresh(ex);
throw ex;
}
}
}
“ConfigurableListableBeanFactory beanFactory =obtainFreshBeanFactory();”这句以后代码的都是注册容器的信息源和生命周期事件,载入过程就是从这句代码启动。
obtainFreshBeanFactory实现
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//这里使用了委派设计模式,父类定义了抽象的refreshBeanFactory()方法,具体实现调用子类容器的 //refreshBeanFactory()方法
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {//如果已经有容器,销毁容器中的bean,关闭容器
destroyBeans();
closeBeanFactory();
}
try {
//创建IoC容器
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
//对IoC容器进行定制化,如设置启动参数,开启注解的自动装配等
customizeBeanFactory(beanFactory);
//调用载入Bean定义的方法,主要这里又使用了一个委派模式,在当前类中只定义了抽象的loadBeanDefinitions方法,具体的实现调用子类容器
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
//创建XmlBeanDefinitionReader,即创建Bean读取器,并通过回调设置到容器中去,容 器使用该读取器读取Bean定义资源
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
//为Bean读取器设置Spring资源加载器,AbstractXmlApplicationContext的
//祖先父类AbstractApplicationContext继承DefaultResourceLoader,因此,容器本身也是一个资源加载器
beanDefinitionReader.setResourceLoader(this);
//为Bean读取器设置SAX xml解析器
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
//当Bean读取器读取Bean定义的Xml资源文件时,启用Xml的校验机制
initBeanDefinitionReader(beanDefinitionReader);
//Bean读取器真正实现加载的方法
loadBeanDefinitions(beanDefinitionReader);
}
//Xml Bean读取器加载Bean定义资源
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { 20 //获取Bean定义资源的定位
Resource[] configResources = getConfigResources();
if (configResources != null) {
//Xml Bean读取器调用其父类AbstractBeanDefinitionReader读取定位
//的Bean定义资源
reader.loadBeanDefinitions(configResources);
}
//如果子类中获取的Bean定义资源定位为空,则获取FileSystemXmlApplicationContext构造方法中setConfigLocations方法设置的资源
String[] configLocations = getConfigLocations();
if (configLocations != null) {
//Xml Bean读取器调用其父类AbstractBeanDefinitionReader读取定位
//的Bean定义资源
reader.loadBeanDefinitions(configLocations);
}
}
//这里又使用了一个委托模式,调用子类的获取Bean定义资源定位的方法
//该方法在ClassPathXmlApplicationContext中进行实现,对于我们
//举例分析源码的FileSystemXmlApplicationContext没有使用该方法
protected Resource[] getConfigResources() {
return null;
}
//重载方法,调用下面的loadBeanDefinitions(String, Set<Resource>);方法
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
return loadBeanDefinitions(location, null);
}
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
//获取在IoC容器初始化过程中设置的资源加载器
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException(
"Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
}
if (resourceLoader instanceof ResourcePatternResolver) {
try {
//将指定位置的Bean定义资源文件解析为Spring IoC容器封装的资源
//加载多个指定位置的Bean定义资源文件
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); 17 //委派调用其子类XmlBeanDefinitionReader的方法,实现加载功能
int loadCount = loadBeanDefinitions(resources);
if (actualResources != null) {
for (Resource resource : resources) {
actualResources.add(resource);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
}
return loadCount;
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Could not resolve bean definition resource pattern [" + location + "]", ex); }
}
else {
//将指定位置的Bean定义资源文件解析为Spring IoC容器封装的资源
//加载单个指定位置的Bean定义资源文件
Resource resource = resourceLoader.getResource(location);
//委派调用其子类XmlBeanDefinitionReader的方法,实现加载功能
int loadCount = loadBeanDefinitions(resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
}
return loadCount;
}
}
//重载方法,调用loadBeanDefinitions(String);
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
Assert.notNull(locations, "Location array must not be null");
int counter = 0;
for (String location : locations) {
counter += loadBeanDefinitions(location);
}
return counter;
}
//获取Resource的具体实现方法
public Resource getResource(String location) {
Assert.notNull(location, "Location must not be null");
//如果是类路径的方式,那需要使用ClassPathResource 来得到bean 文件的资源对象
if (location.startsWith(CLASSPATH_URL_PREFIX)) {
return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader()); }
try {
// 如果是URL 方式,使用UrlResource 作为bean 文件的资源对象
URL url = new URL(location);
return new UrlResource(url);
}
catch (MalformedURLException ex) {
}
//如果既不是classpath标识,又不是URL标识的Resource定位,则调用
//容器本身的getResourceByPath方法获取Resource
return getResourceByPath(location);
}
protected Resource getResourceByPath(String path) {
if (path != null && path.startsWith("/")) {
path = path.substring(1);
} //这里使用文件系统资源对象来定义bean 文件
return new FileSystemResource(path);
}
IOC容器依赖注入
MyTestBean bean=(MyTestBean) bf.getBean(“meTestBean”);
getBean方法的doGetBean
方法里包含:
1.存在缓存
(1)getSingleton方法:缓存中获取单例bean
SingletonObjects:一级缓存,先从此中获取实例
earlySingletonObjects:二级缓存,如果一级缓存获取不到实例,再从此种获取实例
singletonFactories:三级缓存,如果二级缓存获取不到实例,再从此种获取实例
(2)getObjectForBeanInstance方法:从bean的实例中获取对象
对FactoryBean正确性的验证。
对非FactoryBean不做任何处理。
对bean进行转换。
将从Factory中解析bean的工作委托给GetObjectFromFactoryBean.
GetObjectFromFactoryBean:返回的bean如果是单例的,那就必须要保证全局唯一,同时因为是单例的,所以不必重复创建,可以使用缓存来提高性能。
doGetObjectFromFactoryBean方法:
factory.getObject();
postProcessObjectFromFactoryBean
2.无缓存:
(1)getSingleton方法:检查缓存是否已经加载过,若没有加载,则记录beanName的正在加载状态。
beforeSingletonCreation:加载单例前记录加载状态.
singletonFactory.getObject();:实例化bean
afterSingletonCreation:加载单例后处理方法调用,即移除缓存中对该bean正在加载状态的记录。
addSingleton:将结果记录至缓存并删除加载bean过程中所记录的各种辅助状态。
3.准备创建bean
CreateBean方法:
resolveBeanClass:根据设置的class属性或者根据className来解析Class.
mbd.prepareMethodOverrides:验证及准备覆盖的方法。对Override属性进行标记及验证。
resolveBeforeInstantiation:给beanProcessors一个机会来返回代理来替代真正的实例。应用初始化前的后处理器,解析指定bean是否存在初始化前的短路操作。
docreateBean:创建bean
循环依赖
4.创建bean
docreateBean方法:
(1)createBeanInstance方法:
AutowireConstructor:带参数构造函数实例化
instantiateBean:不带参数构造函数实例化
循环依赖检查。
(2)populateBean方法:
InstantiationAwareBeanPostProcessor处理器的postProcessAfterInstantiation函数的应用,此函数可以控制程序是否继续进行属性填充。
autowireByName:属性注入(根据名称自动注入)
autowireByType:属性注入(根据类型自动注入)
InstantiationAwareBeanPostProcessor处理器的postProcessPropertyValues方法,对属性获取完毕填充前对属性的再次处理。
ApplyPropertyValues:将所有propertyValues中的属性填充至BeanWrapper.
(3)initializeBean:调用用户设置的初始化方法。
(4)registerDisposableBeanIfNecessary:注册后处理器来统一处理bean的销毁方法。