目录:
- spring4中IOC容器初始化
(1) 设置资源的加载setConfigLocations
(2) AbstractApplicationContext类之refresh方法加载bean
(3)AbstractApplicationContext类之obtainFreshBeanFactory方法委派子类加载bean
(4)AbstractRefreshableApplicationContext类之refreshBeanFactory方法
(5)AbstractXmlApplicationContext类之loadBeanDefinitions方法读取XML配置文件bean
(6)AbstractBeanDefinitionReader类之loadBeanDefinitions方法读取XML配置的Bean,将其转化为Resource类
(7)XmlBeanDefinitionReader类之loadBeanDefinitions方法加载Resource类(bean资源)
(8)DocumentLoader类之loadDocument将Resource对象转换为Document对象
(9)XmlBeanDefinitionReader类之registerBeanDefinitions方法解析Document对象
(10) DefaultBeanDefinitionDocumentReader类之registerBeanDefinitions方法解析Document中的Bean定义
(11)DefaultBeanDefinitionDocumentReader类之解析, , , 元素
(12) BeanDefinitionReaderUtils类之registerBeanDefinition将BeanDefinition在IOC容器中注册
(13) DefaultListableBeanFactory类之registerBeanDefinition方法真正注册BeanDefinition
(14)spring4中IOC容器初始化步骤总结
spring4中IOC容器初始化
1. 设置资源的加载setConfigLocations
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
ClassPathXmlApplicationContext构造方法:
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
// 设置ApplicationContext为null
super(parent);
// 将配置文件的路径存放到字符串数组中
setConfigLocations(configLocations);
if (refresh) {
// spring加载bean的核心方法,作用就是刷新spring的上下文
refresh();
}
}
public void setConfigLocations(String... locations) {
// 如果locations数组不为null
if (locations != null) {
// 判断数组路径不为null
Assert.noNullElements(locations, "Config locations must not be null");
// configLocations开辟空间
this.configLocations = new String[locations.length];
// 遍历,然后为configLocations数组赋值
for (int i = 0; i < locations.length; i++) {
this.configLocations[i] = resolvePath(locations[i]).trim();
}
}
else {
this.configLocations = null;
}
}
说明:
传入多个配置文件路径可以设置分隔符为 ,; \t\n
String CONFIG_LOCATION_DELIMITERS = ",; \t\n";
public void setConfigLocation(String location) {
setConfigLocations(StringUtils.tokenizeToStringArray(location, CONFIG_LOCATION_DELIMITERS));
}
2. AbstractApplicationContext类之refresh方法加载bean
spring IOC创建容器之前,会先判断BeanFactory容器是否已经存在:① 如果容器已经存在,那么销毁bean。关闭beanFactory,将序列号设置为null,将beanFactory设置为null。② 如果容器不存在,那么创建容器DefaultListableBeanFactory,加载所有的bean定义和创建bean的单例。
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;
}
}
}
3. AbstractApplicationContext类之obtainFreshBeanFactory方法委派子类加载bean
AbstractApplicationContext类obtainFreshBeanFactory方法委派给子类AbstractRefreshableApplicationContext中的refreshBeanFactory方法来载入bean资源文件,刷新内部bean工厂。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 刷新Bean工厂
refreshBeanFactory();
// 获取bean工厂
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
// 返回bean工厂
return beanFactory;
}
4. AbstractRefreshableApplicationContext类之refreshBeanFactory方法
@Override
protected final void refreshBeanFactory() throws BeansException {
// 如果beanFactory不为null
if (hasBeanFactory()) {
// 1. 获取beanFactory;如果为null,就抛出IllegalStateException.
// 2. 销毁bean
destroyBeans();
// 关闭beanFactory,将序列号设置为null,将beanFactory设置为null
closeBeanFactory();
}
try {
// 创建父级别的DefaultListableBeanFactory(真正的IOC容器)
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 将beanFactory设置序列化id
beanFactory.setSerializationId(getId());
// 自定义上下文使用的工厂beanFactory(主要是定制化自动装配等配置)
customizeBeanFactory(beanFactory);
// 使用XmlBeanDefinitionReader加载XML配置文件
loadBeanDefinitions(beanFactory);
// 初始化beanFactory
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
流程说明:
① 首先判断BeanFactory工厂是否已经创建,如果已经创建那么就销毁关闭BeanFactory工厂。(可以发现spring每次都是建立新的IOC容器)
② 创建DefaultListableBeanFactory真正的ioc容器。
③ 调用loadBeanDefinitions方法加载Bean,实际使用XmlBeanDefinitionReader类操作的。
5. AbstractXmlApplicationContext类之loadBeanDefinitions方法读取XML配置文件bean
// 使用XmlBeanDefinitionReader加载Bean
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 通过BeanFactory来创建一个新的XmlBeanDefinitionReader
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// 设置资源加载的环境
beanDefinitionReader.setEnvironment(this.getEnvironment());
// 设置资源加载器,而容器本身就是一个资源加载器
beanDefinitionReader.setResourceLoader(this);
// 设置schema、dtd解析器
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// 当Bean读取器读取Bean定义的Xml资源文件时,启用Xml的校验机制
initBeanDefinitionReader(beanDefinitionReader);
// Bean加载器真正加载Bean的方法
loadBeanDefinitions(beanDefinitionReader);
}
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
// 获取配置文件的路径存放到字符串数组
Resource[] configResources = getConfigResources();
// 如果该资源对象数组不为null
if (configResources != null) {
// 使用AbstractBeanDefinitionReader读取定位的Bean定义资源
reader.loadBeanDefinitions(configResources);
}
// 获取ClassPathXmlApplicationContext类中setConfigLocations方法设置的资源路径的数组
String[] configLocations = getConfigLocations();
// 如果资源路径数组不为null
if (configLocations != null) {
// 使用AbstractBeanDefinitionReader读取定位的Bean定义资源
reader.loadBeanDefinitions(configLocations);
}
}
@Override
protected Resource[] getConfigResources() {
return this.configResources;
}
说明:
XmlBeanDefinitionReader实例化并且初始化,设置资源加载环境、资源加载器、设置schema、dtd解析器、启动Xml校验机制、设置之前配置configLocation配置文件的路径。委派它的父类AbstractBeanDefinitionReader类实现loadBeanDefinitions读取XML配置文件bean
6. AbstractBeanDefinitionReader类之loadBeanDefinitions方法读取XML配置的Bean,将其转化为Resource类
// 通过资源路径数组来加载Bean
@Override
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;
}
// 通过单个资源路径来加载Bean
@Override
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
return loadBeanDefinitions(location, null);
}
// 从指定的资源位置加载bean
public int loadBeanDefinitions(String location, Set actualResources) throws BeanDefinitionStoreException {
// 获取资源加载器(根据给定的资源文件地址返回对应的Resource)
ResourceLoader resourceLoader = getResourceLoader();
// 如果资源加载器为空就抛出异常
if (resourceLoader == null) {
throw new BeanDefinitionStoreException(
"Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
}
if (resourceLoader instanceof ResourcePatternResolver) {
// Resource pattern matching available.
try {
// 将资源文件路径解析为Spring容器支持的资源对象Resource数组
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
// 最终还是委派给XmlBeanDefinitionReader来加载资源Resource
// 返回加载次数
int loadCount = loadBeanDefinitions(resources);
// 如果实际资源不为空,将资源添加进去
// 而传入的集合为null
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 {
// 通过URL方式加载资源
Resource resource = resourceLoader.getResource(location);
int loadCount = loadBeanDefinitions(resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean defintions from location [" + location + "]");
}
return loadCount;
}
}
说明:
AbstractBeanDefinitionReader类只是通过我们之前设置的configLocation的路径查找对应的资源(路径有classpath*、url等),进行加载,加载完所有资源,封装为Resource类。加载完毕后由子类XmlBeanDefinitionReader类的loadBeanDefinitions方法来读取Resource类(bean定义的资源)。
7. XmlBeanDefinitionReader类之loadBeanDefinitions方法加载Resource类(bean资源)
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
// 将资源Resource包装成特殊编码的EncodedResource
return loadBeanDefinitions(new EncodedResource(resource));
}
// XmlBeanDefinitionReader读取Bean定义的资源
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isInfoEnabled()) {
logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}
Set currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
// 将资源文件解析为字节输入流
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
// 定义输入源,设置了资源文件xml的字节输入流
InputSource inputSource = new InputSource(inputStream);
// 如果编码不为空,那么在定义的输入源中设置编码
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
// 真正读取过程
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
// 使用配置的文档来加载程序和加载指定文档
// 将Resource资源(XML文件)转换为Document独享,而解析加载过程使用了documentLoader实现
Document doc = doLoadDocument(inputSource, resource);
// 对Bean定义解析
return registerBeanDefinitions(doc, resource);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}
// 使用配置的文档来加载程序和加载指定文档
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
getValidationModeForResource(resource), isNamespaceAware());
}
说明:
XmlBeanDefinitionReader类之loadBeanDefinitions方法加载Resource类:①委派DocumentLoader类的loadDocument方法将Resource类转成Document类。②使用XmlBeanDefinitionReader类的registerBeanDefinitions方法解析Document中的bean定义。
8. DocumentLoader类之loadDocument将Resource对象转换为Document对象
使用JAXP来解析XML文档为Document对象,JAXP就是封装的DOM接口,使用DOM技术来解析文档模型(譬如元素节点,文档节点)
// 使用JAXP来解析XML文档为Document对象
@Override
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
// 创建文档解析工厂
DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
if (logger.isDebugEnabled()) {
logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
}
// 创建文档解析器
DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
// 解析Bean定义的资源
return builder.parse(inputSource);
}
// 创建DocumentBuilderFactory工厂实例
protected DocumentBuilderFactory createDocumentBuilderFactory(int validationMode, boolean namespaceAware)
throws ParserConfigurationException {
// 创建文档解析工厂
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(namespaceAware);
// 设置文档校验模型,validationMode不为0
if (validationMode != XmlValidationModeDetector.VALIDATION_NONE) {
// 设置校验为true
factory.setValidating(true);
// 如果文档校验模型为XSD校验
if (validationMode == XmlValidationModeDetector.VALIDATION_XSD) {
// Enforce namespace aware for XSD...
factory.setNamespaceAware(true);
try {
// SCHEMA_LANGUAGE_ATTRIBUTE 使用JAXP属性配置验证的语言
// XSD_SCHEMA_LANGUAGE XSD模式语言的JAXP属性值
factory.setAttribute(SCHEMA_LANGUAGE_ATTRIBUTE, XSD_SCHEMA_LANGUAGE);
}
catch (IllegalArgumentException ex) {
ParserConfigurationException pcex = new ParserConfigurationException(
"Unable to validate using XSD: Your JAXP provider [" + factory +
"] does not support XML Schema. Are you running on Java 1.4 with Apache Crimson? " +
"Upgrade to Apache Xerces (or Java 1.5) for full XSD support.");
pcex.initCause(ex);
throw pcex;
}
}
}
return factory;
}
// 使用JAXP创建一个文档解析器DocumentBuilder,用于解析XML文档
protected DocumentBuilder createDocumentBuilder(
DocumentBuilderFactory factory, EntityResolver entityResolver, ErrorHandler errorHandler)
throws ParserConfigurationException {
// 通过工厂创建文档解析器
DocumentBuilder docBuilder = factory.newDocumentBuilder();
if (entityResolver != null) {
docBuilder.setEntityResolver(entityResolver);
}
if (errorHandler != null) {
docBuilder.setErrorHandler(errorHandler);
}
return docBuilder;
}
上面步骤将bean资源封装成了Resource、Document对象,下面将Document对象解析并且加载到spring IOC容器中。
9. XmlBeanDefinitionReader类之registerBeanDefinitions方法解析Document对象
// 解析DOM文档Document中包含的Bean定义
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
// 创建BeanDefinitionDocumentReader用来解析Document
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
// 获取容器中注册的Bean的数量
int countBefore = getRegistry().getBeanDefinitionCount();
// 此处委派给了DefaultBeanDefinitionDocumentReader来实现Bean定义的解析
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
// 返回解析的Bean数量
return getRegistry().getBeanDefinitionCount() - countBefore;
}
// 创建一个BeanDefinitionDocumentReader用来解析Document
protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
// 使用构造器通过反射来创建对象,强制类型转换为BeanDefinitionDocumentReader类型
return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));
}
说明:
真正解析Document对象,委派给DefaultBeanDefinitionDocumentReader类的registerBeanDefinitions方法实现。
10. DefaultBeanDefinitionDocumentReader类之registerBeanDefinitions方法解析Document中的Bean定义
// 根据spring-beans的XSD文件来解析bean的定义
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
// 初始化XML描述符
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
// 获取document的根元素
Element root = doc.getDocumentElement();
// 在给定的根元素root的内部注册每个Bean的定义
doRegisterBeanDefinitions(root);
}
// 在给定的根元素的内部注册每个Bean的定义
protected void doRegisterBeanDefinitions(Element root) {
// 使用BeanDefinitionParserDelegate用于完成真正的解析过程
BeanDefinitionParserDelegate parent = this.delegate;
// 对BeanDefinitionParserDelegate进行初始化
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isInfoEnabled()) {
logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
// 在解析Bean定义之前,扩展解析自定义配置
preProcessXml(root);
// 从Document的根元素root开始进行Bean定义的Document对象
parseBeanDefinitions(root, this.delegate);
// 在解析Bean定义之后,扩展解析自定义配置
postProcessXml(root);
this.delegate = parent;
}
说明:
获取Document对应的根元素,从根元素root开始解析文档。
-------------------------开始解析标签元素----------------------
从根节点开始遍历文档标签节点进行解析
// 解析文档中的根级别元素(import标签,alias标签,bean标签,beans元素)
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
// Bean定义的document对象使用spring的默认xml命名空间
if (delegate.isDefaultNamespace(root)) {
// 获取bean根元素下的所有子节点
NodeList nl = root.getChildNodes();
// 遍历所有子节点
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
// 判断节点是否为Element元素节点
if (node instanceof Element) {
// 将节点node强制类型转为Element元素
Element ele = (Element) node;
// 使用Spring的Bean规则解析元素节点
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else {// 使用用户自定义的命名空间解析
delegate.parseCustomElement(ele);
}
}
}
}
else {
// 根节点没有使用spring的默认命名空间,就使用用户自定义的命名空间解析
delegate.parseCustomElement(root);
}
}
11. DefaultBeanDefinitionDocumentReader类之解析,,,元素
// 解析Document元素Element节点
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
// 如果元素节点是节点
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
// 解析Document元素中的节点
importBeanDefinitionResource(ele);
}
// 如果元素节点是节点
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
// 解析Document元素中的节点
processAliasRegistration(ele);
}
// 如果元素节点是节点
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
// 解析Document元素中的节点
processBeanDefinition(ele, delegate);
}
// 如果元素节点是节点
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// 解析Document元素中的节点
doRegisterBeanDefinitions(ele);
}
}
------------------------- ① 真正解析
解析import标签配置的url,判断路径是否为绝对路径,然后重新调用loadBeanDefinitions方法,加载路径对应的xml资源。
// 解析节点元素并且将bean定义从给定资源中加载到bean工厂
protected void importBeanDefinitionResource(Element ele) {
// 获取导入资源的location属性
String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
// 如果location属性值为空,那么直接返回
if (!StringUtils.hasText(location)) {
getReaderContext().error("Resource location must not be empty", ele);
return;
}
// 使用系统变量值来解析location属性值
location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);
Set actualResources = new LinkedHashSet(4);
// 判断location属性值的定位是否为绝对路径
boolean absoluteLocation = false;
try {
absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();
}
catch (URISyntaxException ex) {
// cannot convert to an URI, considering the location relative
// unless it is the well-known Spring prefix "classpath*:"
}
// 如果location定位为绝对路径
if (absoluteLocation) {
try {
// 通过指定路径加载bean定义的资源,返回节点的加载次数
int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
if (logger.isDebugEnabled()) {
logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]");
}
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error(
"Failed to import bean definitions from URL location [" + location + "]", ele, ex);
}
}
else {// 否则location定位按照相对路径处理
try {
int importCount;
// 通过指定路径获取相对路径下的资源Resource
Resource relativeResource = getReaderContext().getResource().createRelative(location);
// 判断相对路径对应的资源是否存在
if (relativeResource.exists()) {
// 使用XmlBeanDefinitionReader读取相对路径下的资源
importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
actualResources.add(relativeResource);
}
else {
String baseLocation = getReaderContext().getResource().getURL().toString();
importCount = getReaderContext().getReader().loadBeanDefinitions(
StringUtils.applyRelativePath(baseLocation, location), actualResources);
}
if (logger.isDebugEnabled()) {
logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]");
}
}
catch (IOException ex) {
getReaderContext().error("Failed to resolve current resource location", ele, ex);
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]",
ele, ex);
}
}
Resource[] actResArray = actualResources.toArray(new Resource[actualResources.size()]);
// 在解析完元素之后,发送容器导入其他资源处理完成事件
getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
}
-------------------------② 真正解析
解析bean属性:id、name、别名、class、meta元信息、构造方法、parent属性、单例属性,property属性、qualifier属性。创建BeanDefinition,将属性设置到BeanDefinition中(只是进行初始化并没有将其依赖注入到beanFactory中)。然后创建一个BeanDefinitionHolder对象,构造器方式设置BeanDefinition、Bean名称、别名数组。
// 解析Document元素中的节点
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// BeanDefinitionHolder类对BeanDefinition的封装
// 使用BeanDefinitionParserDelegate解析默认的bean标签(包括属性及子元素标签的解析)
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
// 解析自定义标签
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// IOC容器注册BeanDefinition
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
//在完成向Spring IoC容器注册解析得到的Bean定义之后,发送注册事件
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
// 解析提供的Bean元素
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
return parseBeanDefinitionElement(ele, null);
}
// 解析提供的Bean元素
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
// 获取bean元素中的id属性
// public static final String ID_ATTRIBUTE = "id";
String id = ele.getAttribute(ID_ATTRIBUTE);
// 获取bean元素中的name属性
// public static final String NAME_ATTRIBUTE = "name";
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
List aliases = new ArrayList();
// 将bean元素中name属性值存放到别名中
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
// 如果bean设置了id,那么将id作为beanName
// 如果别名集合不为空,那么将别名集合的第一个元素作为beanName
String beanName = id;
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
if (logger.isDebugEnabled()) {
logger.debug("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
}
if (containingBean == null) {
// 检查Bean元素配置的id、name或者别名是否重复
checkNameUniqueness(beanName, aliases, ele);
}
// 解析bean定义本身,而不考虑名称或别名。
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
// 如果bean元素没有配置id、别名或者name并且没有包含子Bean元素
// 那么就解析Bean生成唯一beanName并注册
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
// 如果bean元素没有配置id、别名或者name并且包含子Bean元素
// 那么就解析Bean使用别名注册
beanName = this.readerContext.generateBeanName(beanDefinition);
// 为了保持对于Spring 1.2/2.0向后兼容性
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Neither XML 'id' nor 'name' specified - " +
"using generated bean name [" + beanName + "]");
}
}
catch (Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
// 解析bean定义本身,而不考虑id、名称、别名(上面已经处理过了)
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, BeanDefinition containingBean) {
// 专门记录解析的Bean元素
this.parseState.push(new BeanEntry(beanName));
String className = null;
// 获取bean元素中的class属性
// public static final String CLASS_ATTRIBUTE = "class";
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
try {
String parent = null;
// 获取bean元素中的parent属性
// public static final String PARENT_ATTRIBUTE = "parent";
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
// 为Bean元素配置的class名称和parent属性值创建BeanDefinition
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
// 对当前的Bean元素中配置的一些属性进行解析和设置,如配置的单态(singleton)属性等
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
// 为Bean元素解析的Bean设置description信息
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
// 对Bean元素的meta(元信息)属性解析
parseMetaElements(ele, bd);
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
// 解析Bean元素的构造方法设置
parseConstructorArgElements(ele, bd);
// 解析Bean元素的property属性
parsePropertyElements(ele, bd);
// 解析Bean元素的qualifier属性
parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
return bd;
}
catch (ClassNotFoundException ex) {
error("Bean class [" + className + "] not found", ele, ex);
}
catch (NoClassDefFoundError err) {
error("Class that bean class [" + className + "] depends on not found", ele, err);
}
catch (Throwable ex) {
error("Unexpected failure during bean definition parsing", ele, ex);
}
finally {
this.parseState.pop();
}
return null;
}
------------------------- ③ 真正解析
解析
(1)解析property标签及其子标签和属性,得到指向解析的property标签引用对象ref。
(2)定义一个属性对象PropertyValue,构造器方式封装引用对象ref、set方法方式封装Element对象,方式为:pv.setSource(extractSource(ele));(Element对象为bean封装)。
(3)将属性对象PropertyValue添加到BeanDefinition对象中。
// 解析Property元素及其子元素
public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
// 获取bean元素中的子元素
NodeList nl = beanEle.getChildNodes();
// 遍历子元素节点
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
// 判断子元素是否子元素
if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
// 调用解析子元素方法解析
parsePropertyElement((Element) node, bd);
}
}
}
// 解析Property元素
public void parsePropertyElement(Element ele, BeanDefinition bd) {
// 获取property元素中的name属性
// public static final String NAME_ATTRIBUTE = "name";
String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
// 校验属性值不为null
if (!StringUtils.hasLength(propertyName)) {
error("Tag 'property' must have a 'name' attribute", ele);
return;
}
this.parseState.push(new PropertyEntry(propertyName));
try {
// 判断Bean定义中是否存在这个property元素
if (bd.getPropertyValues().contains(propertyName)) {
error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
return;
}
// 遍历property元素及其子元素,同时解析遍历到的元素的属性,如:ref、value。
Object val = parsePropertyValue(ele, bd, propertyName);
PropertyValue pv = new PropertyValue(propertyName, val);
// 解析property元素中的元属性,key、value
parseMetaElements(ele, pv);
pv.setSource(extractSource(ele));
bd.getPropertyValues().addPropertyValue(pv);
}
finally {
this.parseState.pop();
}
}
上面解析完spring中的各种标签,将property属性与PropertyValue对象关联,将PropertyValue对象与BeanDefinition对象关联,将BeanDefinitionHolder对象关联。回到DefaultBeanDefinitionDocumentReader类的processBeanDefinition方法中,开始向spring IOC容器注册BeanDefinitionHolder。
12. BeanDefinitionReaderUtils类之registerBeanDefinition将BeanDefinition在IOC容器中注册
// 将Bean定义注册到Bean工厂
// BeanDefinitionHolder包括了BeanDefinition和bean的别名
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
// 获取Bean定义的名称
String beanName = definitionHolder.getBeanName();
// 使用Bean名称和BeanDefinition向IOC容器注册
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
// 如果BeanDefinition有别名,那么向ioc容器注册别名
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
说明:
从BeanDefinitionHolder中获取BeanDefinition,将BeanDefinition注册的任务委派到DefaultListableBeanFactory类的registerBeanDefinition方法实现。
13. DefaultListableBeanFactory类之registerBeanDefinition方法真正注册BeanDefinition
// 存储注册的BeanDefinition
private final Map beanDefinitionMap = new ConcurrentHashMap();
// 使用Bean名称和BeanDefinition向IOC容器注册
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
// 校验BeanDefinition;校验方法的注解、方法名称等
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
BeanDefinition oldBeanDefinition;
// 通过beanName获取对应的旧的BeanDefinition
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
// 检查是否有同名的BeanDefinition已经在IoC容器中注册
if (oldBeanDefinition != null) {
// 如果不允许BeanDefinition重写,那么抛出BeanDefinition存储异常
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (this.logger.isWarnEnabled()) {
this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(oldBeanDefinition)) {
// 如果新的需要注册的BeanDefinition不等于之前已经注册的BeanDefinition
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
// 进行新的需要注册的BeanDefinition覆盖之前已经注册的BeanDefinition
if (this.logger.isDebugEnabled()) {
this.logger.debug("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
// 设置新的需要注册的BeanDefinition
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else { // 之前没有注册过BeanDefinition
if (hasBeanCreationStarted()) {// 如果已经创建BeanDefinition不为空
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
// 设置当前需要注册BeanDefinition
this.beanDefinitionMap.put(beanName, beanDefinition);
// 创建存储更新BeanDefinition的名称的集合
List updatedDefinitions = new ArrayList(this.beanDefinitionNames.size() + 1);
// 将之前的BeanDefinition的名称插入到集合中
updatedDefinitions.addAll(this.beanDefinitionNames);
// 将当前的BeanDefinition的名称插入到集合中
updatedDefinitions.add(beanName);
// 设置最新的BeanDefinition的名称集合
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set updatedSingletons = new LinkedHashSet(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {// 如果已经创建BeanDefinition为空
// 设置beanName对应的beanDefinition
this.beanDefinitionMap.put(beanName, beanDefinition);
// 将beanName添加到名称集合中
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
// 重置所有已经注册过的BeanDefinition的缓存
if (oldBeanDefinition != null || containsSingleton(beanName))
resetBeanDefinition(beanName);
}
}
说明:
将BeanDefinition对象注册到BeanDefinitionMap容器中,就相当于注册初始化到spring IOC容器中,IOC操作BeanDefinitionMap就可以获取到所有的Bean的资源、配置信息,根据BeanDefinitionMap中的所有BeanDefinition,就可以实现依赖注入。
以上就完成了ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");代码对于spring IOC容器的初始化。
spring4中IOC容器初始化的步骤总结
- 根据指定路径加载资源
- refresh方法加载bean是初始化的入口。
- 使用loadBeanDefinition方法载入bean定义资源:
- 使用ResourceLoader通过给定的类路径加载资源,spring将资源文件封装成了Resource类,这样就拿到了Resource对象。
- 使用DocumentLoader将资源Resource转换为Document文档对象,这样就拿到了Document对象。
- 使用DefaultBeanDefinitionDocumentReader类解析Document对象中的
, , , 元素。 - 将
元素和对应属性封装成BeanDefinition,再将BeanDefinition封装成BeanDefinitionHolder。 - DefaultListableBeanFactory类中注册BeanDefinition。
- 注册过程就是维护一个公共的ConcurrentHashMap类型的BeanDefinitionMap来保存Bean配置的BeanDefinition。