Spring IOC 加载过程(一 加载xml)
程序员文章站
2022-07-12 13:10:17
...
Spring IOC 加载过程
看过很多次Spring容器的源码,每次都没有记录,每次都看到放弃,这次下决心要学习一下源码了,所以写一篇博文来记录,也希望有各路大神来指点不足之处,话不多说,下面开始!
- 加载Context
- 创建beanFactory
- 加载xml
Spring容器结构图
加载Context
我是从一个web程序打断点一步一步跟代码走的,一个web程序的入口应该是web.xml文件
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-config.xml</param-value>
</context-param>
<!-- 注册Spring ContextLoaderListener -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
web.xml中关于Spring的配置就这么简单,这里我们只看Spring的内容,暂时先不看SpringMVC(web)的内容
然后根据上面的配置进入代码(启动tomcat可以进入)
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
public ContextLoaderListener() {
}
public ContextLoaderListener(WebApplicationContext context) {
super(context);
}
/**
* 初始化Spring容器入口
*/
@Override
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
@Override
public void contextDestroyed(ServletContextEvent event) {
closeWebApplicationContext(event.getServletContext());
ContextCleanupListener.cleanupAttributes(event.getServletContext());
}
}
这里就是入口,其实就是执行了一个initWebApplicationContext(event.getServletContext())
这个方法。我们进入方法来看:
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
/*
* WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = "org.springframework.web.context.WebApplicationContext.ROOT" servletContext中没有这个属性
*/
if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
throw new IllegalStateException(
"Cannot initialize context because there is already a root application context present - " +
"check whether you have multiple ContextLoader* definitions in your web.xml!");
}
Log logger = LogFactory.getLog(ContextLoader.class);
servletContext.log("Initializing Spring root WebApplicationContext");
if (logger.isInfoEnabled()) {
logger.info("Root WebApplicationContext: initialization started");
}
//这里记录一个开始时间
long startTime = System.currentTimeMillis();
try {
if (this.context == null) { //默认是null
/*创建web应用上下文
这里获取到的是默认给的 org.springframework.web.context.support.XmlWebApplicationContext这个类,
创建web应用下文结束(创建了一个XmlWebApplicationContext对象)*/
this.context = createWebApplicationContext(servletContext);
}
if (this.context instanceof ConfigurableWebApplicationContext) {
//这里做一下转换
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
if (!cwac.isActive()) {//这里初始值是false
if (cwac.getParent() == null) { //父容器为空,这里加载回来也是一个空,因为是初次加载还没有父容器
ApplicationContext parent = loadParentContext(servletContext);
cwac.setParent(parent);
}
//配置刷新Spring容器,这里是这个方法最重要的部分,我们后面解释
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
//把初始化好的Sping容器 放到 sevlet 容器中 这个属性就是上面判断的属性
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
//获取类加载器
ClassLoader ccl = Thread.currentThread().getContextClassLoader();
if (ccl == ContextLoader.class.getClassLoader()) {
currentContext = this.context;
}
else if (ccl != null) {
currentContextPerThread.put(ccl, this.context);
}
if (logger.isDebugEnabled()) {
logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
}
if (logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startTime;
logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
}
return this.context;
}
catch (RuntimeException ex) {
logger.error("Context initialization failed", ex);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
throw ex;
}
catch (Error err) {
logger.error("Context initialization failed", err);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
throw err;
}
}
下面我们看重点的方法configureAndRefreshWebApplicationContext(cwac, servletContext);
这个方法,上代码
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
//这里wac.getId() 是类中id属性,内部初始化的方法就是ObjectUtils.identityToString(wac)
if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
// The application context id is still set to its original default value
// -> assign a more useful id based on available information
String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);//这里没有这个属性,为空
if (idParam != null) {
wac.setId(idParam);
}
else {
// Generate default id...
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
ObjectUtils.getDisplayString(sc.getContextPath()));//设置一个新的id:org.springframework.web.context.WebApplicationContext:
}
}
wac.setServletContext(sc);//将servletContext放入到Spring容器中
String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
if (configLocationParam != null) {
wac.setConfigLocation(configLocationParam);//设置配置文件路径,classpath:spring-config.xml 这是我们在web.xml中配置的
}
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
}
customizeContext(sc, wac);//这里其实什么都没干,因为没有相应的配置
//刷新容器。
wac.refresh();
}
创建beanFactory
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 做准备工作. 这里对一些必要属性做了验证。
prepareRefresh();
// 告诉子类刷新内部bean工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//准备在这个上下文中使用bean工厂。
prepareBeanFactory(beanFactory);
try {
// 允许在上下文子类中对bean工厂进行后处理。
postProcessBeanFactory(beanFactory);
// 调用在上下文中注册为bean的工厂处理器.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// 初始化此上下文的消息源.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
介绍obtainFreshBeanFactory()这个方法
/**
* Tell the subclass to refresh the internal bean factory.
* @return the fresh BeanFactory instance
* @see #refreshBeanFactory()
* @see #getBeanFactory()
*/
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//刷新beanFactory
refreshBeanFactory();
//获取beanFactory
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
refreshBeanFactory()
protected final void refreshBeanFactory() throws BeansException {
//清空原来的beanFactory(),其实这里也没有
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
//创建beanFactory,这里如果有父容器会加载父容器的beanFactory为当前beanFactory的parentBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
//加载beanDefinitions 这里是对xml尽心校验并解析
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
加载xml
继续从上面的loadBeanDefinitions(beanFactory)这个方法开始
//类XmlWebApplicationContext
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 为beanFactory创建一个beanDefinitionReader,用于读取xml,这里是xmlWebApplicatioContext类实现的这个方法,定义的是xmlBeanDefinitionReader
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// 设置黄建,资源加载器,资源处理类
beanDefinitionReader.setEnvironment(getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// 初始化beanDefinitionReader (这个方法没有实体,留给用户自己扩展)
initBeanDefinitionReader(beanDefinitionReader);
// 加载资源
loadBeanDefinitions(beanDefinitionReader);
}
//加载资源 //类XmlWebApplicationContext
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
String[] configLocations = getConfigLocations();
if (configLocations != null) {
for (String configLocation : configLocations) {
//根据配置文件目录加载
reader.loadBeanDefinitions(configLocation);
}
}
}
//根据配置文件目录加载 类AbstractBeanDefinitionReader
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
return loadBeanDefinitions(location, null);
}
//这里才是最终实现 类AbstractBeanDefinitionReader
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
//前面设置的RescourceLoader() 就是XmlWebApplicationContext对象 上面的结构图中最终实现了ResourcePatternResolver类
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 {
//加载资源
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
//注册bean 这里对xml进行校验 解析 注册bean
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 {
// Can only load single resources by absolute URL.
Resource resource = resourceLoader.getResource(location);
int loadCount = loadBeanDefinitions(resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
}
return loadCount;
}
加载xml资源 对xml 校验解析 返回Document
//类AbstractBeanDefinitionReader
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
Assert.notNull(resources, "Resource array must not be null");
int counter = 0;
for (Resource resource : resources) {
counter += loadBeanDefinitions(resource);
}
return counter;
}
/*
* 类XmlBeanDefinitionReader 这里对资源进行了编码 转换为EncodeResource
* Resource接口和EncodeResource类 都实现了InputStreamSource接口
*/
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
/*
* 类XmlBeanDefinitionReader
*/
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<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
//初始化一个Set集合,设置到当前对象中
if (currentResources == null) {
currentResources = new HashSet<EncodedResource>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
//将encodedResource放到上面初始化的集合中
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//这里对xml转化的流读取解析
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();
}
}
}
/*
* 类XmlBeanDefinitionReader 这里只有两个方法,下面都是处理的异常
*/
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
Document doc = doLoadDocument(inputSource, resource);
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);
}
}
/*
* 类XmlBeanDefinitionReader 这里是把xml解析成Document
* 这个方法传的参数很多。包括上面传过来的inputSource 当前对象的资源处理器,错误处理器,xml验证模式,
* 还有一个默认为false的boolean,暂且不管他是干什么的
*/
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
getValidationModeForResource(resource), isNamespaceAware());
}
/*
* 类XmlBeanDefinitionReader
* 获取验证模式
* VALIDATION_AUTO = 1
*/
protected int getValidationModeForResource(Resource resource) {
//这里获取的是validationMode这个属性 private int validationMode = VALIDATION_AUTO;默认为1
int validationModeToUse = getValidationMode();
if (validationModeToUse != VALIDATION_AUTO) {
return validationModeToUse;
}
int detectedMode = detectValidationMode(resource);//这里根据配置文件获取验证模式
if (detectedMode != VALIDATION_AUTO) {
return detectedMode;
}
// Hmm, we didn't get a clear indication... Let's assume XSD,
// since apparently no DTD declaration has been found up until
// detection stopped (before finding the document's root tag).
return VALIDATION_XSD;
}
/*
* 类XmlBeanDefinitionReader
* 根据配置文件获取验证模式
*/
protected int detectValidationMode(Resource resource) {
if (resource.isOpen()) {
throw new BeanDefinitionStoreException(
"Passed-in Resource [" + resource + "] contains an open stream: " +
"cannot determine validation mode automatically. Either pass in a Resource " +
"that is able to create fresh streams, or explicitly specify the validationMode " +
"on your XmlBeanDefinitionReader instance.");
}
InputStream inputStream;
try {
inputStream = resource.getInputStream();
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Unable to determine validation mode for [" + resource + "]: cannot open InputStream. " +
"Did you attempt to load directly from a SAX InputSource without specifying the " +
"validationMode on your XmlBeanDefinitionReader instance?", ex);
}
try {
//根据xml内容 如果第一行有“DOCTYPE”则DTD 否则XSD
return this.validationModeDetector.detectValidationMode(inputStream);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("Unable to determine validation mode for [" +
resource + "]: an error occurred whilst reading from the InputStream.", ex);
}
}
/*
* 类DefaultDocumentLoader 这里就是解析xml了 最终返回一个Document
*/
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);
return builder.parse(inputSource);
}
下面是注册Bean加载到容器中 重点 重点 重点
/*
* 类XmlBeanDefinitionReader
*/
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//创建一个DefaultBeanDefinitionDocumentReader对象 实现了BeanDefinitionDocumentReader 接口
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
//getRegistry()这个方法是获取当前对象的beanFactory
// getBeanDefinitionCount() 获取beanFactory中beanDefinitionMap()(ConcurrentHashMap) 的size,初始化之前为0
//这里是获取之前注册的bean
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
//返回这次注册的对象的数量
return getRegistry().getBeanDefinitionCount() - countBefore;
}
/*
* 类DefaultBeanDefinitionDocumentReader
* 注册bean
*/
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
//获取根节点
Element root = doc.getDocumentElement();
//注册bean
doRegisterBeanDefinitions(root);
}
/*
*类DefaultBeanDefinitionDocumentReader
* 到这里是不是觉得读到根节点了 终于要开始了? 呵呵 你小看他了,还有延伸
*/
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate; //上面方法刚实例化出来,这个属性还是null
//这里创建一个对象,你可以理解为这个类是真正解析Element的工作类(确实是这样的)
//创建这个对象的方法后面再看,这里先往下面走
this.delegate = createDelegate(getReaderContext(), root, parent);
//刚才创建对象的时候 把root传进去了,这里获取到的值是true
if (this.delegate.isDefaultNamespace(root)) {
//PROFILE_ATTRIBUTE = "profile" root节点里没有这个属性 返回false
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;
}
}
}
//准备解析xml方法,这个方法是空的 留给用户自己扩展
preProcessXml(root);
//解析xml (这里才是重点!!)
parseBeanDefinitions(root, this.delegate);
//解析完成,下一步流程 也是空的,留给用户自己扩展
postProcessXml(root);
//设置当前对象内的解析对象属性为当前对象的parent 默认为空
this.delegate = parent;
}
然后我们看这个方法createDelegate(getReaderContext(), root, parent)
/*
* 类DefaultBeanDefinitionDocumentReader 创建解析类
*/
protected BeanDefinitionParserDelegate createDelegate(
XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) {
BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
delegate.initDefaults(root, parentDelegate);
return delegate;
}
/*
* BeanDefinitionParserDelegate 初始默认值
*
public void initDefaults(Element root, BeanDefinitionParserDelegate parent) {
populateDefaults(this.defaults, (parent != null ? parent.defaults : null), root);
this.readerContext.fireDefaultsRegistered(this.defaults);
}
/*
* BeanDefinitionParserDelegate 设置一些默认值,这里我们都没有配置,基本都是默认的,后面解析的时候会用到
*/
protected void populateDefaults(DocumentDefaultsDefinition defaults, DocumentDefaultsDefinition parentDefaults, Element root) {
//从参数根节点即<beans>节点中获取default-lazy-init参数
String lazyInit = root.getAttribute(DEFAULT_LAZY_INIT_ATTRIBUTE);
////如果lazyInit的值为default,如果parentDefaults不为null则侧其中获取lazyInit,否则设置为false
if (DEFAULT_VALUE.equals(lazyInit)) {
// Potentially inherited from outer <beans> sections, otherwise falling back to false.
lazyInit = (parentDefaults != null ? parentDefaults.getLazyInit() : FALSE_VALUE);
}
defaults.setLazyInit(lazyInit);
String merge = root.getAttribute(DEFAULT_MERGE_ATTRIBUTE);
if (DEFAULT_VALUE.equals(merge)) {
// Potentially inherited from outer <beans> sections, otherwise falling back to false.
merge = (parentDefaults != null ? parentDefaults.getMerge() : FALSE_VALUE);
}
defaults.setMerge(merge);
String autowire = root.getAttribute(DEFAULT_AUTOWIRE_ATTRIBUTE);
if (DEFAULT_VALUE.equals(autowire)) {
// Potentially inherited from outer <beans> sections, otherwise falling back to 'no'.
autowire = (parentDefaults != null ? parentDefaults.getAutowire() : AUTOWIRE_NO_VALUE);
}
defaults.setAutowire(autowire);
// Don't fall back to parentDefaults for dependency-check as it's no longer supported in
// <beans> as of 3.0. Therefore, no nested <beans> would ever need to fall back to it.
defaults.setDependencyCheck(root.getAttribute(DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE));
if (root.hasAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE)) {
defaults.setAutowireCandidates(root.getAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE));
}
else if (parentDefaults != null) {
defaults.setAutowireCandidates(parentDefaults.getAutowireCandidates());
}
if (root.hasAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)) {
defaults.setInitMethod(root.getAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE));
}
else if (parentDefaults != null) {
defaults.setInitMethod(parentDefaults.getInitMethod());
}
if (root.hasAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE)) {
defaults.setDestroyMethod(root.getAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE));
}
else if (parentDefaults != null) {
defaults.setDestroyMethod(parentDefaults.getDestroyMethod());
}
defaults.setSource(this.readerContext.extractSource(root));
}
解析的方法parseBeanDefinitions(root, this.delegate);
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {//这里是true 按根节点来解析
NodeList nl = root.getChildNodes();//获取子节点列表
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {//节点是否是默认命名空间
parseDefaultElement(ele, delegate);//具体解析 默认命名空间 标签<bean>
}
else {
delegate.parseCustomElement(ele);//具体解析 自定义标签 <context:...
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
具体解析,后面再写。
推荐阅读
-
Spring源码剖析2:Spring IOC容器的加载过程
-
Tomcat源码分析三:Tomcat启动加载过程(一)的源码解析
-
概述一个页面从输入URL到页面加载完的过程
-
spring源码深度解析— IOC 之 开启 bean 的加载
-
DB数据源之SpringBoot+MyBatis踏坑过程(二)手工配置数据源与加载Mapper.xml扫描
-
<转> Spring如何加载XSD文件(org.xml.sax.SAXParseException: Failed to read schema documen
-
Spring IOC 加载过程(一 加载xml)
-
Spring基础使用(一)--------IOC、Bean的XML方式装配
-
深刻理解java中new一个对象的执行过程及类的加载顺序
-
Spring IOC高级特性(lazy-Init 延迟加载,FactoryBean,后置处理器)