Spring3.1.1浅析(一)
来源:互联网 发布:latex有windows版么 编辑:程序博客网 时间:2024/06/05 22:39
首先了解一下spring的启动细节:
1、 创建maven工程,pom文件中加入对spring的依赖和log4j的支持:
2、建立两个测试类,其中service中包含对dao的引用,然后定义一个Test类进行测试用:
package com.yushh.test.chapter42;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;public class DaoFoo {protected final Log log = LogFactory.getLog(DaoFoo.class);private String daoName;private String daoPartern;public String getDaoName() {return daoName;}public void setDaoName(String daoName) {this.daoName = daoName;}public String getDaoPartern() {return daoPartern;}public void setDaoPartern(String daoPartern) {this.daoPartern = daoPartern;}@Overridepublic String toString() {return "DaoFoo [daoName=" + daoName + ", daoPartern=" + daoPartern+ "]";}public void doSomething(){log.info("DaoFoo method doSomething()!");}}
package com.yushh.test.chapter42;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.apache.log4j.Logger;public class ServiceFoo {protected final Log log = LogFactory.getLog(ServiceFoo.class);private String name;private String user;private DaoFoo dao;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getUser() {return user;}public void setUser(String user) {this.user = user;} @Overridepublic String toString() {return "ServiceFoo [name=" + name + ", user=" + user + "]";}public void doSomething(){log.info("ServiceFoo's method doSomething()!");}public void setDao(DaoFoo dao) {this.dao = dao;}}
package com.yushh.test.chapter42;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test {public static void main(String[] args) {ApplicationContext context =new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"});ServiceFoo service = context.getBean("serviceFoo", ServiceFoo.class);service.doSomething();}}
3、 配置文件中配置dao和service:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd"><bean id="daoFoo" class="com.yushh.test.chapter42.DaoFoo"></bean></beans>Service.xml:<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd"><!-- services --><bean id="serviceFoo"class="com.yushh.test.chapter42.ServiceFoo"><property name="dao" ref="daoFoo"/></bean></beans>
Log4J.properties:
log4j.rootCategory=INFO,stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE}%5p%t%c{2}:%L-%m%n
log4j.category.org.springframework.beans.factory=DEBUG
运行结果如下:
11:18:46,280 INFO main support.ClassPathXmlApplicationContext:495 - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@9f2a0b: startup date [Tue Mar 27 11:18:46 CST 2012]; root of context hierarchy11:18:46,312 INFO main xml.XmlBeanDefinitionReader:315 - Loading XML bean definitions from class path resource [services.xml]11:18:46,327 DEBUG main xml.DefaultDocumentLoader:72 - Using JAXP provider [com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl]11:18:46,358 DEBUG main xml.PluggableSchemaResolver:140 - Loading schema mappings from [META-INF/spring.schemas]11:18:46,358 DEBUG main xml.PluggableSchemaResolver:146 - Loaded schema mappings: {http://www.springframework.org/schema/util/spring-util.xsd=org/springframework/beans/factory/xml/spring-util-3.1.xsd, http://www.springframework.org/schema/beans/spring-beans-3.1.xsd=org/springframework/beans/factory/xml/spring-beans-3.1.xsd, http://www.springframework.org/schema/task/spring-task.xsd=org/springframework/scheduling/config/spring-task-3.1.xsd, http://www.springframework.org/schema/cache/spring-cache.xsd=org/springframework/cache/config/spring-cache-3.1.xsd, http://www.springframework.org/schema/aop/spring-aop-3.0.xsd=org/springframework/aop/config/spring-aop-3.0.xsd, http://www.springframework.org/schema/task/spring-task-3.1.xsd=org/springframework/scheduling/config/spring-task-3.1.xsd, http://www.springframework.org/schema/aop/spring-aop-2.0.xsd=org/springframework/aop/config/spring-aop-2.0.xsd, http://www.springframework.org/schema/tool/spring-tool-2.5.xsd=org/springframework/beans/factory/xml/spring-tool-2.5.xsd, http://www.springframework.org/schema/beans/spring-beans.xsd=org/springframework/beans/factory/xml/spring-beans-3.1.xsd, http://www.springframework.org/schema/jee/spring-jee-2.5.xsd=org/springframework/ejb/config/spring-jee-2.5.xsd, http://www.springframework.org/schema/tool/spring-tool-3.1.xsd=org/springframework/beans/factory/xml/spring-tool-3.1.xsd, http://www.springframework.org/schema/jee/spring-jee-3.1.xsd=org/springframework/ejb/config/spring-jee-3.1.xsd, http://www.springframework.org/schema/aop/spring-aop.xsd=org/springframework/aop/config/spring-aop-3.1.xsd, http://www.springframework.org/schema/beans/spring-beans-2.0.xsd=org/springframework/beans/factory/xml/spring-beans-2.0.xsd, http://www.springframework.org/schema/beans/spring-beans-3.0.xsd=org/springframework/beans/factory/xml/spring-beans-3.0.xsd, http://www.springframework.org/schema/task/spring-task-3.0.xsd=org/springframework/scheduling/config/spring-task-3.0.xsd, http://www.springframework.org/schema/context/spring-context-2.5.xsd=org/springframework/context/config/spring-context-2.5.xsd, http://www.springframework.org/schema/tool/spring-tool-3.0.xsd=org/springframework/beans/factory/xml/spring-tool-3.0.xsd, http://www.springframework.org/schema/util/spring-util-2.5.xsd=org/springframework/beans/factory/xml/spring-util-2.5.xsd, http://www.springframework.org/schema/tool/spring-tool-2.0.xsd=org/springframework/beans/factory/xml/spring-tool-2.0.xsd, http://www.springframework.org/schema/lang/spring-lang.xsd=org/springframework/scripting/config/spring-lang-3.1.xsd, http://www.springframework.org/schema/lang/spring-lang-2.5.xsd=org/springframework/scripting/config/spring-lang-2.5.xsd, http://www.springframework.org/schema/jee/spring-jee-3.0.xsd=org/springframework/ejb/config/spring-jee-3.0.xsd, http://www.springframework.org/schema/jee/spring-jee-2.0.xsd=org/springframework/ejb/config/spring-jee-2.0.xsd, http://www.springframework.org/schema/context/spring-context-3.1.xsd=org/springframework/context/config/spring-context-3.1.xsd, http://www.springframework.org/schema/util/spring-util-3.1.xsd=org/springframework/beans/factory/xml/spring-util-3.1.xsd, http://www.springframework.org/schema/lang/spring-lang-3.1.xsd=org/springframework/scripting/config/spring-lang-3.1.xsd, http://www.springframework.org/schema/cache/spring-cache-3.1.xsd=org/springframework/cache/config/spring-cache-3.1.xsd, http://www.springframework.org/schema/context/spring-context.xsd=org/springframework/context/config/spring-context-3.1.xsd, http://www.springframework.org/schema/jee/spring-jee.xsd=org/springframework/ejb/config/spring-jee-3.1.xsd, http://www.springframework.org/schema/aop/spring-aop-2.5.xsd=org/springframework/aop/config/spring-aop-2.5.xsd, http://www.springframework.org/schema/aop/spring-aop-3.1.xsd=org/springframework/aop/config/spring-aop-3.1.xsd, http://www.springframework.org/schema/context/spring-context-3.0.xsd=org/springframework/context/config/spring-context-3.0.xsd, http://www.springframework.org/schema/tool/spring-tool.xsd=org/springframework/beans/factory/xml/spring-tool-3.1.xsd, http://www.springframework.org/schema/util/spring-util-3.0.xsd=org/springframework/beans/factory/xml/spring-util-3.0.xsd, http://www.springframework.org/schema/lang/spring-lang-3.0.xsd=org/springframework/scripting/config/spring-lang-3.0.xsd, http://www.springframework.org/schema/util/spring-util-2.0.xsd=org/springframework/beans/factory/xml/spring-util-2.0.xsd, http://www.springframework.org/schema/lang/spring-lang-2.0.xsd=org/springframework/scripting/config/spring-lang-2.0.xsd, http://www.springframework.org/schema/beans/spring-beans-2.5.xsd=org/springframework/beans/factory/xml/spring-beans-2.5.xsd}11:18:46,358 DEBUG main xml.PluggableSchemaResolver:118 - Found XML schema [http://www.springframework.org/schema/beans/spring-beans-3.0.xsd] in classpath: org/springframework/beans/factory/xml/spring-beans-3.0.xsd11:18:46,390 DEBUG main xml.DefaultBeanDefinitionDocumentReader:108 - Loading bean definitions11:18:46,405 DEBUG main xml.XmlBeanDefinitionReader:216 - Loaded 1 bean definitions from location pattern [services.xml]11:18:46,405 INFO main xml.XmlBeanDefinitionReader:315 - Loading XML bean definitions from class path resource [daos.xml]11:18:46,405 DEBUG main xml.DefaultDocumentLoader:72 - Using JAXP provider [com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl]11:18:46,405 DEBUG main xml.PluggableSchemaResolver:118 - Found XML schema [http://www.springframework.org/schema/beans/spring-beans-3.0.xsd] in classpath: org/springframework/beans/factory/xml/spring-beans-3.0.xsd11:18:46,421 DEBUG main xml.DefaultBeanDefinitionDocumentReader:108 - Loading bean definitions11:18:46,421 DEBUG main xml.XmlBeanDefinitionReader:216 - Loaded 1 bean definitions from location pattern [daos.xml]11:18:46,436 INFO main support.DefaultListableBeanFactory:557 - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1081d2e: defining beans [serviceFoo,daoFoo]; root of factory hierarchy11:18:46,436 DEBUG main support.DefaultListableBeanFactory:217 - Creating shared instance of singleton bean 'serviceFoo'11:18:46,436 DEBUG main support.DefaultListableBeanFactory:430 - Creating instance of bean 'serviceFoo'11:18:46,436 DEBUG main support.DefaultListableBeanFactory:504 - Eagerly caching bean 'serviceFoo' to allow for resolving potential circular references11:18:46,452 DEBUG main support.DefaultListableBeanFactory:217 - Creating shared instance of singleton bean 'daoFoo'11:18:46,452 DEBUG main support.DefaultListableBeanFactory:430 - Creating instance of bean 'daoFoo'11:18:46,452 DEBUG main support.DefaultListableBeanFactory:504 - Eagerly caching bean 'daoFoo' to allow for resolving potential circular references11:18:46,452 DEBUG main support.DefaultListableBeanFactory:458 - Finished creating instance of bean 'daoFoo'11:18:46,468 DEBUG main support.DefaultListableBeanFactory:458 - Finished creating instance of bean 'serviceFoo'11:18:46,468 DEBUG main support.DefaultListableBeanFactory:245 - Returning cached instance of singleton bean 'daoFoo'11:18:46,483 DEBUG main support.DefaultListableBeanFactory:245 - Returning cached instance of singleton bean 'lifecycleProcessor'11:18:46,483 DEBUG main support.DefaultListableBeanFactory:245 - Returning cached instance of singleton bean 'serviceFoo'11:18:46,483 INFO main chapter42.ServiceFoo:46 - ServiceFoo's method doSomething()!
可见我们成功调用了ServiceFoo的doSomething方法,下面我们看一下spring在这期间究竟做了什么:
1、刷新org.springframework.context.support.ClassPathXmlApplicationContext对象,因为我们用的是ClassPathXmlApplicationContext这种方式创建ApplicationContext,所以spring启动后先调用这个类进行初始化。
那么ClassPathXmlApplicationContext这个类干了些什么工作呢,我们打开源码:public ClassPathXmlApplicationContext(String... configLocations) throws BeansException {this(configLocations, true, null);}
可见,这个类就是根据location指定的位置读取xml文件,真正的读取方法是它的父类AbstractXmlApplicationContext中定义的,代码如下:
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {// Create a new XmlBeanDefinitionReader for the given BeanFactory.XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);// Configure the bean definition reader with this context's// resource loading environment.beanDefinitionReader.setEnvironment(this.getEnvironment());beanDefinitionReader.setResourceLoader(this);beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));// Allow a subclass to provide custom initialization of the reader,// then proceed with actually loading the bean definitions.initBeanDefinitionReader(beanDefinitionReader);loadBeanDefinitions(beanDefinitionReader);}
传入的参数就是DefaultListableBeanFactory,这应该是spring的默认beanFactory,然后初始化一个
XmlBeanDefinitionReader用来读取xml,首先设置了一下
XmlBeanDefinitionReader它要做的一件事就是先解析出DefaultListableBeanFactory中的资源列表,然后一个一个读取:
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;}
loadBeanDefinitions首先指定Resource和Encoding方式,并把它们放在EncodedResource对象中,接着调用读取的方法:
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();if (currentResources == null) {currentResources = new HashSet<EncodedResource>(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 {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();}}}
接下来我们断点调试一下这个方法,看看其中有什么奥秘,第一行首先读入的是class path resource [services.xml]这个配置,resourcesCurrentlyBeingLoaded这个是个ThreadLocal<Set<EncodedResource>>,也就是是个线程绑定的集合,集合中防入了EncodedResource对象,这个我们在上文中也提到过就是编码和Resource的封装对象,然后是这个集合的初始化工作,这个不用解释了,
InputStream inputStream = encodedResource.getResource().getInputStream();执行到这个代码时就开始读取services.xml这个文件了。
doLoadBeanDefinitions这个方法时实际解析bean定义的方法,我们看一下这个方法:
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)throws BeanDefinitionStoreException {try {int validationMode = getValidationModeForResource(resource);Document doc = this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());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);}}
documentLoader.loadDocument方法读取了services.xml的内容并得到Document对象,当然了还有些附件操作,如格式验证,命名空间验证等。
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();documentReader.setEnvironment(this.getEnvironment());int countBefore = getRegistry().getBeanDefinitionCount();documentReader.registerBeanDefinitions(doc, createReaderContext(resource));return getRegistry().getBeanDefinitionCount() - countBefore;}
这个方法根据刚才生成的Document对象解析bean的定义,registerBeanDefinitions除了Document之外另一个参数是ReaderContext,这个我的理解是一个和命令空间有关的XmlReaderContext对象,也就是说可能不同的命名空间下有同名的xmlReader对象,这个就是区分的作用。
说了这么多总要开始解析了吧,protected void doRegisterBeanDefinitions(Element root) {String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);if (StringUtils.hasText(profileSpec)) {Assert.state(this.environment != null, "environment property must not be null");String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);if (!this.environment.acceptsProfiles(specifiedProfiles)) {return;}}// any nested <beans> elements will cause recursion in this method. In// order to propagate and preserve <beans> default-* attributes correctly,// keep track of the current (parent) delegate, which may be null. Create// the new (child) delegate with a reference to the parent for fallback purposes,// then ultimately reset this.delegate back to its original (parent) reference.// this behavior emulates a stack of delegates without actually necessitating one.BeanDefinitionParserDelegate parent = this.delegate;this.delegate = createHelper(readerContext, root, parent);preProcessXml(root);parseBeanDefinitions(root, this.delegate);postProcessXml(root);this.delegate = parent;}
这个也是一个很重要的方法,其中BeanDefinitionParserDelegate对象是个bean定义的代理类,
preProcessXml(root);和postProcessXml(root);
目前是这个接口中声明的方法,没有具体实现,作用就是可以在解析xml为bean之前和之后进行一些回调操作。
parseBeanDefinitions解析终于开始了:
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)) {// recursedoRegisterBeanDefinitions(ele);}}
定义了四种解析的方式:解析import标签、beans标签、bean标签和alias标签。其中 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,getReaderContext().getRegistry());
这个方法时核心方法,就是把解析到的bean注册到容器中:
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);}}}
beanName:得到serviceFoo
definitionHolder:保留了bean的属性信息:
Bean definition withname 'serviceFoo' and aliases []: Generic bean: class[com.yushh.test.chapter42.ServiceFoo]; scope=; abstract=false; lazyInit=false;autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false;factoryBeanName=null; factoryMethodName=null; initMethodName=null;destroyMethodName=null; defined in class path resource [services.xml]
至此完成了对一个bean的解析。
下面我们总结一下:spring通过ClassPathXmlApplicationContext类的loadBeanDefinitions完成对bean的解析。后者通过调用XmlBeanDefinitionReader的doLoadBeanDefinitions生成要解析的Document对象,然后调用BeanDefinitionDocumentReader的实现类DefaultBeanDefinitionDocumentReader的doRegisterBeanDefinitions方法进行真正的解析,最后把解析到的bean通过BeanDefinitionReaderUtils注册到容器中。
- Spring3.1.1浅析(一)
- [spring3]springMVC总结(一)
- Spring3注解实例(一)
- Spring3注解实例(一)
- Spring3注解实例(一)
- Spring3 MVC 笔记(一)
- [Spring3.x源码]IoC(一)例子
- [Spring3.x源码]AOP(一)例子
- 1、Spring3核心技术-IoC(一)
- spring3+mybaitis3遇到的问题(一)
- Spring3.0中的AOP(一)
- spring3.x + activemq学习笔记(一)
- Spring3+mybatis+mysql整合详解(一)
- IL浅析(一)
- LDA浅析(一)
- javaBean浅析(一)
- NFC 浅析(一)
- 数据结构浅析(一)
- 理想与现实
- 无递归堆栈遍历树
- java——语言基础
- 11级csdn java第二课总结
- 任务四:设计三角形类
- Spring3.1.1浅析(一)
- jquery实现居中、左下角、右下角窗口效果
- android核心架构
- jquery基础
- 基于.net开发平台项目案例集锦
- 任务五:一个项目多文件组织完成任务四
- 实验二:大小写的转换
- Yahoo!S4分布式流处理引擎分析总结
- Android客户端请求服务端资源(HttpURLConnection和输入流实现)