- 浏览: 1843877 次
- 性别:
- 来自: 深圳
文章分类
- 全部博客 (665)
- 闲话 (17)
- ruby (1)
- javascript (40)
- linux (7)
- android (22)
- 开发过程 (11)
- 哥也读读源代码 (13)
- JVM (1)
- ant (2)
- Hibernate (3)
- jboss (3)
- web service (17)
- https (4)
- java基础 (17)
- spring (7)
- servlet (3)
- 杂记 (39)
- struts2 (10)
- logback (4)
- 多线程 (2)
- 系统诊断 (9)
- UI (4)
- json (2)
- Java EE (7)
- eclipse相关 (4)
- JMS (1)
- maven (19)
- 版本管理 (7)
- sso (1)
- ci (1)
- 设计 (18)
- 戒烟 (4)
- http (9)
- 计划 (4)
- HTML5 (3)
- chrome extensions (5)
- tomcat源码阅读 (4)
- httpd (5)
- MongoDB (3)
- node (2)
最新评论
-
levin_china:
勾选了,还是找不到
用spring annotation声明的bean,当打包在jar中时,无法被扫描到 -
GGGGeek:
我用的maven-3.5.0,还没有遇到这种情况,使用jar ...
用spring annotation声明的bean,当打包在jar中时,无法被扫描到 -
GGGGeek:
受益匪浅,从组织项目结构,到技术细节,讲的很到位,只是博主不再 ...
一个多maven项目聚合的实例 -
Aaron-Joe-William:
<?xml version="1.0" ...
hibernate逆向工程 -
li272355201:
http://archive.apache.org/dist/ ...
tomcat源码阅读(一)——环境搭建
上一篇博客说到,BeanDefinition的解析,已经走到了DefaultBeanDefinitionDocumentReader里,这时候配置文件已经被加载,并解析成w3c的Document对象。
这篇博客就接着介绍,DefaultBeanDefinitionDocumentReader和BeanDefinitionParserDelegate类,是怎么协同完成bean的解析和注册的
这段代码,创建了一个BeanDefinitionParserDelegate组件,然后就是preProcessXml()、parseBeanDefinitions()、postProcessXml()方法
其中preProcessXml()和postProcessXml()默认是空方法,接下来就看下parseBeanDefinitions()方法
从这个方法开始,BeanDefinitionParserDelegate就开始发挥作用了,判断当前解析元素是否属于默认的命名空间,如果是的话,就调用parseDefaultElement()方法,否则调用delegate上的parseCustomElement()方法
只有http://www.springframework.org/schema/beans,会被认为是默认的命名空间。也就是说,<beans>、<bean>这些元素,会认为属于默认的命名空间,而像<task:scheduled>这些,就认为不属于默认命名空间
根节点<beans>的一个子节点<bean>,是属于默认命名空间的,所以会进入parseDefaultElement()方法
这里可能会有4种情况,<import>、<alias>、<bean>、<beans>,分别有一个方法与之对应,这里解析的是<bean>元素,所以会进入processBeanDefinition()方法
这里主要有3个步骤,先是委托delegate对bean进行解析,然后委托delegate对bean进行装饰,最后由一个工具类来完成BeanDefinition的注册。
可以看出来,DefaultBeanDefinitionDocumentReader不负责任何具体的bean解析,它面向的是xml Document对象,根据其元素的命名空间和名称,起一个类似路由的作用(不过,命名空间的判断,也是委托给delegate来做的)。所以这个类的命名,是比较贴切的,突出了其面向Document的特性。具体的工作,是由BeanDefinitionParserDelegate来完成的
下面就看下parseBeanDefinitionElement()方法
这个方法很长,可以分成三段来看
这一段,主要是处理一些跟alias,id等标识相关的东西
这一行是核心,进行实际的解析
这段是后置处理,对beanName进行处理
前置处理和后置处理,不是核心,就不细看了,重点看下核心的那一行调用
这个方法也挺长的,拆开看看
这段是从配置中抽取出类名。接下来的长长一段,把异常处理先抛开,看看实际的业务
这里每个方法的命名,就说明了是要干什么,可以一个个跟进去看,本文就不细说了。总之,经过这里的解析,就得到了一个完整的BeanDefinitionHolder。只是说明一下,如果在配置文件里,没有对一些属性进行设置,比如autowire-candidate等,那么这个解析生成的BeanDefinition,都会得到一个默认值
然后,对这个Bean做一些必要的装饰
完成了BeanDefinition的解析和装饰之后(装饰也是解析的一部分),就将BeanDefinition在BeanFactory里进行注册。
这个方法,是在BeanRegistry接口里定义的,前面提到过,DefaultListableBeanFactory实现了这个接口,所以这部分工作,也就是在DefaultListableBeanFactory里完成的
这个方法里,最关键的是以下2行
前者是把beanName放到队列里,后者是把BeanDefinition放到map中,到此注册就完成了。在后面实例化的时候,就是从beanDefinitionMap中的BeanDefinition取出来,逐一实例化
BeanFactory准备完毕之后,代码又回到了XmlWebApplicationContext里
也就是obtainFreshBeanFactory()方法执行之后,再进行下面的步骤。每个步骤的作用,在前面的博客里已经介绍过了
总结来说,ApplicationContext将解析配置文件的工作委托给BeanDefinitionReader,然后BeanDefinitionReader将配置文件读取为xml的Document文档之后,又委托给BeanDefinitionDocumentReader
BeanDefinitionDocumentReader这个组件是根据xml元素的命名空间和元素名,起到一个路由的作用,实际的解析工作,是委托给BeanDefinitionParserDelegate来完成的
BeanDefinitionParserDelegate的解析工作完成以后,会返回BeanDefinitionHolder给BeanDefinitionDocumentReader,在这里,会委托给DefaultListableBeanFactory完成bean的注册
XmlBeanDefinitionReader(计数、解析XML文档)-->BeanDefinitionDocumentReader(依赖xml文档,进行解析和注册)-->BeanDefinitionParserDelegate(实际的解析工作)。可以看出,在解析bean的过程中,这3个组件的分工是比较清晰的,各司其职,这种设计思想值得学习
到此为止,<bean>的解析过程就基本分析结束了。下一篇博客,会针对另外一些非Default Namespace的元素的处理过程,再更深入地分析一下spring的加载过程
hehe,过奖了
这篇博客就接着介绍,DefaultBeanDefinitionDocumentReader和BeanDefinitionParserDelegate类,是怎么协同完成bean的解析和注册的
BeanDefinitionParserDelegate parent = this.delegate; this.delegate = createHelper(readerContext, root, parent); preProcessXml(root); parseBeanDefinitions(root, this.delegate); postProcessXml(root); this.delegate = parent;
这段代码,创建了一个BeanDefinitionParserDelegate组件,然后就是preProcessXml()、parseBeanDefinitions()、postProcessXml()方法
其中preProcessXml()和postProcessXml()默认是空方法,接下来就看下parseBeanDefinitions()方法
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(root)) { 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); } else { delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } }
从这个方法开始,BeanDefinitionParserDelegate就开始发挥作用了,判断当前解析元素是否属于默认的命名空间,如果是的话,就调用parseDefaultElement()方法,否则调用delegate上的parseCustomElement()方法
public boolean isDefaultNamespace(String namespaceUri) { return (!StringUtils.hasLength(namespaceUri) || BEANS_NAMESPACE_URI.equals(namespaceUri)); } public boolean isDefaultNamespace(Node node) { return isDefaultNamespace(getNamespaceURI(node)); }
只有http://www.springframework.org/schema/beans,会被认为是默认的命名空间。也就是说,<beans>、<bean>这些元素,会认为属于默认的命名空间,而像<task:scheduled>这些,就认为不属于默认命名空间
根节点<beans>的一个子节点<bean>,是属于默认命名空间的,所以会进入parseDefaultElement()方法
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // recurse doRegisterBeanDefinitions(ele); } }
这里可能会有4种情况,<import>、<alias>、<bean>、<beans>,分别有一个方法与之对应,这里解析的是<bean>元素,所以会进入processBeanDefinition()方法
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // Send registration event. getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
这里主要有3个步骤,先是委托delegate对bean进行解析,然后委托delegate对bean进行装饰,最后由一个工具类来完成BeanDefinition的注册。
可以看出来,DefaultBeanDefinitionDocumentReader不负责任何具体的bean解析,它面向的是xml Document对象,根据其元素的命名空间和名称,起一个类似路由的作用(不过,命名空间的判断,也是委托给delegate来做的)。所以这个类的命名,是比较贴切的,突出了其面向Document的特性。具体的工作,是由BeanDefinitionParserDelegate来完成的
下面就看下parseBeanDefinitionElement()方法
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { String id = ele.getAttribute(ID_ATTRIBUTE); String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); List<String> aliases = new ArrayList<String>(); if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); aliases.addAll(Arrays.asList(nameArr)); } 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) { checkNameUniqueness(beanName, aliases, ele); } AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null) { if (!StringUtils.hasText(beanName)) { try { if (containingBean != null) { beanName = BeanDefinitionReaderUtils.generateBeanName( beanDefinition, this.readerContext.getRegistry(), true); } else { beanName = this.readerContext.generateBeanName(beanDefinition); // Register an alias for the plain bean class name, if still possible, // if the generator returned the class name plus a suffix. // This is expected for Spring 1.2/2.0 backwards compatibility. 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; }
这个方法很长,可以分成三段来看
String id = ele.getAttribute(ID_ATTRIBUTE); String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); List<String> aliases = new ArrayList<String>(); if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); aliases.addAll(Arrays.asList(nameArr)); } 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) { checkNameUniqueness(beanName, aliases, ele); }
这一段,主要是处理一些跟alias,id等标识相关的东西
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
这一行是核心,进行实际的解析
if (beanDefinition != null) { if (!StringUtils.hasText(beanName)) { try { if (containingBean != null) { beanName = BeanDefinitionReaderUtils.generateBeanName( beanDefinition, this.readerContext.getRegistry(), true); } else { beanName = this.readerContext.generateBeanName(beanDefinition); // Register an alias for the plain bean class name, if still possible, // if the generator returned the class name plus a suffix. // This is expected for Spring 1.2/2.0 backwards compatibility. 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); }
这段是后置处理,对beanName进行处理
前置处理和后置处理,不是核心,就不细看了,重点看下核心的那一行调用
public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, BeanDefinition containingBean) { this.parseState.push(new BeanEntry(beanName)); String className = null; if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } try { String parent = null; if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } AbstractBeanDefinition bd = createBeanDefinition(className, parent); parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); parseMetaElements(ele, bd); parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); parseConstructorArgElements(ele, bd); parsePropertyElements(ele, bd); 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; }
这个方法也挺长的,拆开看看
this.parseState.push(new BeanEntry(beanName)); String className = null; if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); }
这段是从配置中抽取出类名。接下来的长长一段,把异常处理先抛开,看看实际的业务
String parent = null; if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } AbstractBeanDefinition bd = createBeanDefinition(className, parent); parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); parseMetaElements(ele, bd); parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); parseConstructorArgElements(ele, bd); parsePropertyElements(ele, bd); parseQualifierElements(ele, bd); bd.setResource(this.readerContext.getResource()); bd.setSource(extractSource(ele)); return bd;
这里每个方法的命名,就说明了是要干什么,可以一个个跟进去看,本文就不细说了。总之,经过这里的解析,就得到了一个完整的BeanDefinitionHolder。只是说明一下,如果在配置文件里,没有对一些属性进行设置,比如autowire-candidate等,那么这个解析生成的BeanDefinition,都会得到一个默认值
然后,对这个Bean做一些必要的装饰
public BeanDefinitionHolder decorateBeanDefinitionIfRequired( Element ele, BeanDefinitionHolder definitionHolder, BeanDefinition containingBd) { BeanDefinitionHolder finalDefinition = definitionHolder; // Decorate based on custom attributes first. NamedNodeMap attributes = ele.getAttributes(); for (int i = 0; i < attributes.getLength(); i++) { Node node = attributes.item(i); finalDefinition = decorateIfRequired(node, finalDefinition, containingBd); } // Decorate based on custom nested elements. NodeList children = ele.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { Node node = children.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) { finalDefinition = decorateIfRequired(node, finalDefinition, containingBd); } } return finalDefinition; }
完成了BeanDefinition的解析和装饰之后(装饰也是解析的一部分),就将BeanDefinition在BeanFactory里进行注册。
这个方法,是在BeanRegistry接口里定义的,前面提到过,DefaultListableBeanFactory实现了这个接口,所以这部分工作,也就是在DefaultListableBeanFactory里完成的
public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { // Register bean definition under primary name. String beanName = definitionHolder.getBeanName(); registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // Register aliases for bean name, if any. String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String aliase : aliases) { registry.registerAlias(beanName, aliase); } } }
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"); if (beanDefinition instanceof AbstractBeanDefinition) { try { ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } } synchronized (this.beanDefinitionMap) { Object oldBeanDefinition = this.beanDefinitionMap.get(beanName); if (oldBeanDefinition != null) { if (!this.allowBeanDefinitionOverriding) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound."); } else { if (this.logger.isInfoEnabled()) { this.logger.info("Overriding bean definition for bean '" + beanName + "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } } else { this.beanDefinitionNames.add(beanName); this.frozenBeanDefinitionNames = null; } this.beanDefinitionMap.put(beanName, beanDefinition); resetBeanDefinition(beanName); } }
这个方法里,最关键的是以下2行
this.beanDefinitionNames.add(beanName);
this.beanDefinitionMap.put(beanName, beanDefinition);
前者是把beanName放到队列里,后者是把BeanDefinition放到map中,到此注册就完成了。在后面实例化的时候,就是从beanDefinitionMap中的BeanDefinition取出来,逐一实例化
BeanFactory准备完毕之后,代码又回到了XmlWebApplicationContext里
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. 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) { // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } } }
也就是obtainFreshBeanFactory()方法执行之后,再进行下面的步骤。每个步骤的作用,在前面的博客里已经介绍过了
总结来说,ApplicationContext将解析配置文件的工作委托给BeanDefinitionReader,然后BeanDefinitionReader将配置文件读取为xml的Document文档之后,又委托给BeanDefinitionDocumentReader
BeanDefinitionDocumentReader这个组件是根据xml元素的命名空间和元素名,起到一个路由的作用,实际的解析工作,是委托给BeanDefinitionParserDelegate来完成的
BeanDefinitionParserDelegate的解析工作完成以后,会返回BeanDefinitionHolder给BeanDefinitionDocumentReader,在这里,会委托给DefaultListableBeanFactory完成bean的注册
XmlBeanDefinitionReader(计数、解析XML文档)-->BeanDefinitionDocumentReader(依赖xml文档,进行解析和注册)-->BeanDefinitionParserDelegate(实际的解析工作)。可以看出,在解析bean的过程中,这3个组件的分工是比较清晰的,各司其职,这种设计思想值得学习
到此为止,<bean>的解析过程就基本分析结束了。下一篇博客,会针对另外一些非Default Namespace的元素的处理过程,再更深入地分析一下spring的加载过程
评论
3 楼
nidetaidengma
2015-07-29
给博主点个赞,确实很不错,应该置顶才对
2 楼
kyfxbl
2015-07-03
lalahei 写道
写的这么好竟然没人顶
hehe,过奖了
1 楼
lalahei
2015-07-02
写的这么好竟然没人顶
发表评论
-
小读spring ioc源码(四)——BeanDefinitionReader
2012-07-24 19:02 2440上一篇博客说到,ApplicationContext将解析Be ... -
小读spring ioc源码(三)——XmlWebApplicationContext初始化的整体过程
2012-07-12 16:54 2923上一篇说到,ContextLoader ... -
小读spring ioc源码(二)——ContextLoaderListener
2012-06-25 18:41 2872实际开发中,比较多的项目是web项目,这时候加载spring, ... -
小读spring ioc源码(一)——整体介绍
2012-06-18 22:59 2604最近在读spring ioc的源码,用EA画了几张比较清楚的类 ... -
读logback源码系列文章(八)——记录日志的实际工作类Encoder
2011-10-17 20:34 3012本系列的博客从logback怎么对接slf4j开始,逐步介绍了 ... -
读logback源码系列文章(七)——配置的实际工作类Action
2011-10-11 22:59 3564上篇博客介绍了ContextInitializer类如何把框架 ... -
读logback源码系列文章(六)——ContextInitializer
2011-10-09 21:46 6835放了一个长假回来啦,继续写本系列博客 这篇博客我们接着上一篇 ... -
读logback源码系列文章(五)——Appender
2011-09-16 21:03 13848明天要带老婆出国旅游 ... -
读logback源码系列文章(四)——记录日志
2011-09-12 02:22 4434今天晚上本来想来写一下Logger怎么记录日志,以及Appen ... -
读logback源码系列文章(三)——创建Logger
2011-09-07 21:35 6214上一篇博客介绍了logback的StaticLoggerBin ... -
读logback源码系列文章(二)——提供ILoggerFactory
2011-09-07 20:07 6661上篇博客介绍了logback是 ... -
读logback源码系列文章(一)——对接slf4j
2011-08-29 02:43 7538以前也读过一些开源项目的源码,主要是spring和ant,不过 ...
相关推荐
《Spring IOC源码解析(一)——整体介绍》 在深入理解Spring框架的过程中,源码分析是不可或缺的一环。本文将对Spring的IOC(Inversion of Control,控制反转)容器的源码进行初步探讨,旨在帮助读者从整体上把握...
标题《Spring IoC源码深度剖析开源架构源码2021.pdf》和描述《Spring IoC源码深度剖析开源架构源码2021.pdf》表明该文档主要面向于分析Spring框架中控制反转(IoC)容器的核心源码,解析和理解其内部的工作机制及...
Spring IOC,即Inversion of Control(控制反转),是Spring框架的核心特性之一,它负责管理和装配应用程序中的对象。...理解并掌握Spring的IOC源码,对于深入学习Spring框架以及提升系统设计能力具有重要意义。
### Spring IoC源码解读 #### 一、Spring IoC 容器概述 Spring框架的核心功能之一便是依赖注入(Dependency Injection, DI),而这一功能主要通过IoC容器来实现。在Spring框架中,IoC容器负责管理应用对象的生命...
**五、Spring Ioc的工作流程** 1. **读取配置**:Spring容器读取XML、Java配置或基于注解的配置信息,构建BeanDefinition对象,其中包含了对象的类名、属性、依赖等信息。 2. **Bean实例化**:根据BeanDefinition,...
在"基于Maven构建的Spring IoC源码实例"中,我们可以学到如何使用Maven搭建Spring项目,并通过Spring IoC实现组件间的依赖注入。以下是这个实例中可能包含的关键知识点: 1. **Maven项目结构**:了解标准的Maven...
老王读 Spring IoC 系列文章的源码分析&测试代码 Spring IoC 源码分析,帮助大家学习 Spring 源码,更加了解 Spring 的底层 博客专栏地址:https://blog.csdn.net/wang489687009/category_11269905.html
【标题】"Java进阶之SpringIoC源码深度剖析共19页.pd" 提供的是一项关于Java开发中的高级主题,特别是针对Spring框架的依赖注入(Inversion of Control,IoC)部分的深入研究。Spring IoC是Spring框架的核心特性之一...
### Spring源码分析_Spring_IOC:深入理解Spring的IOC容器机制 #### 基本概念与核心作用 在探讨Spring框架的核心组件之一——IOC(Inversion of Control,控制反转)容器之前,首先需要理解它在Spring框架中的角色...
这是spring_ioc部分的内容。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。...
Spring框架是Java开发中不可或缺的一部分,它主要由两个核心组件构成:IoC(Inversion of Control,控制反转)和AOP(Aspect Oriented Programming,面向切面编程)。本笔记将深入探讨这两个概念以及它们在Spring中...
在这个示例源码中,我们可以深入理解并学习如何在实际项目中运用Spring的IOC容器来管理对象的生命周期和依赖关系。 1. **Spring 框架介绍** Spring是一个开源的Java平台,它提供了全面的企业级应用开发解决方案,...
《Spring源码分析——BeanFactory》 在Java的IoC(Inversion of Control)和DI(Dependency Injection)领域,Spring框架扮演着至关重要的角色。BeanFactory是Spring的核心组件之一,它是容器的基石,负责管理应用...
《深入解析Spring IoC源码:核心机制与实践应用》 Spring框架的IoC(Inversion of Control,控制反转)是其核心特性之一,它极大地简化了Java应用程序的开发。本文将深入剖析Spring IoC容器的源码,揭示其工作原理...
Spring Ioc 源码分析系列--自动注入循环依赖的处理 本篇文章主要讲解了 Spring Ioc 源码分析系列中自动注入循环依赖的处理机制。循环依赖是 Spring 框架中一个经典的问题,也是面试中常被问到的问题。本篇文章将...
我们从一个简单的容器开始,一步步的重构,最后实现一个基本的Spring框架的雏形,为了帮助我们更加深入的理解Spring的IoC的原理和源码。 详细内容见博文: 【SSH进阶之路】一步步重构容器实现Spring的IoC——从一个...
《Spring源码分析——ApplicationContext》 在Java世界中,Spring框架是不可或缺的一部分,它以其强大的IoC(Inversion of Control,控制反转)和AOP(Aspect Oriented Programming,面向切面编程)特性,极大地...
"Spring IOC基本操作" Spring IOC(Inversion of Control,控制反转)是一种软件设计模式,它将对象的创建和管理交给容器,实现了对象之间的解耦合。 SpringIOC是Spring Framework中的核心组件之一,负责管理应用...
springIOC手写框架分析springIOC手写框架分析springIOC手写框架分析springIOC手写框架分析springIOC手写框架分析springIOC手写框架分析springIOC手写框架分析springIOC手写框架分析springIOC手写框架分析springIOC...
spring ioc模块手写demospring ioc模块手写demospring ioc模块手写demospring ioc模块手写demospring ioc模块手写demospring ioc模块手写demospring ioc模块手写demospring ioc模块手写demospring ioc模块手写demo...