Spring之容器的实现
来源:互联网 发布:mac查看内存占用 编辑:程序博客网 时间:2024/06/15 19:49
对于经常使用spring框架的同学,对于下面的这段代码肯定不会陌生
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
(1)读取配置文件applicationContext
(2)找到配置文件中定义的配置并实例化
以上是Spring实现容器的基础,虽然只有短短的一行,但是里面却包含了复杂的逻辑。为了分析里面包含的逻辑,我们可以使用他的父类BeanFactory来分析。下面代码是Spring比较原始的实现容器的方法。
BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactory.xml"));
代码实现的逻辑为:
1.使用ClassPathResource将beanFactory.xml封装成Resource
2.完成XmlBeanFactory的初始化
ClassPathResource
在 Java中,将不同来源的资源抽象成URL,通过注册不同的handler(URLStreamHandler)来处理不同来源间的资源读取逻辑。而 URL中却没有提供一些基本方法来实现自己的抽象结构。因而Spring对其内部资源,使用了自己的抽象结构:Resource接口来封装。而 ClassPathResource实现类即是对Resource的实现。而Resource实现了InputStreamSource。
public interface InputStreamSource { InputStream getInputStream() throws IOException;}public interface Resource extends InputStreamSource { boolean exists(); boolean isReadable(); boolean isOpen(); URL getURL() throws IOException; URI getURI() throws IOException; File getFile() throws IOException; long contentLength() throws IOException; long lastModified() throws IOException; Resource createRelative(String relativePath) throws IOException; String getFilename(); String getDescription();}
不同的Resource实现代表了不同来源的资源,对于来自ClassPath的资源就是用ClassPathResource来实现。
XmlBeanDefinitionReader
将配置文件封装好以后就需要对其读取,这个工作由XmlBeanDefinitionReader来完成。XmlBeanDefinitionReader中由loadBeanDefinitions方法实现读取的功能。loadBeanDefinitions方法的源代码如下:
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException { //loadBeanDefinitions的具体实现,而EncodedResource主要用于对资源文件的处理 return loadBeanDefinitions(new EncodedResource(resource)); }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()); }//通过属性来记录已经加载的资源 。。。。。。。。。。 // 调用DefaultResourceLoader的getResources方法完成具体的Resource定位 try { //从EncodedResource中获取已经封装的Resource对象并再次从Resource中获取inputStream InputStream inputStream = encodedResource.getResource().getInputStream(); try { InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null) { inputSource.setEncoding(encodedResource.getEncoding()); } //真正的实现核心 return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } 。。。。。。。。。。。。。}
对于上述源码,只需要知道实现逻辑:
(1)对于resource做一次封装,为了考虑到resource可能存在的编码问题,我们使用了new EncodedResource(resource)来实现。
(2)准备获得InputSource对象。
(3)将封装好的resource和InputSource传递给真正的核心部分:doLoadBeanDefinitions(inputSource, encodedResource.getResource());
doLoadBeanDefinitions
我们看一看doLoadBeanDefinitions(inputSource, encodedResource.getResource())中的实现方法:
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { //这里略去了冗余的代码,值需要注意三个方法 //获得验证模式 int validationMode = getValidationModeForResource(Resource resource) //获得document Document document = loadDocument(InputSource inputSource, EntityResolver entityResolver,ErrorHandler errorHandler, int validationMode, boolean namespaceAware) //注册Bean信息 registerBeanDefinitions(Document doc, XmlReaderContext readerContext) }
doLoadBeanDefinitions只做了三件事:
1.获得验证模式
2.获得document
3.注册Bean信息
获得验证模式
验证模式就两种,DTD和XSD。如果xml文件中有则表示使用DTD验证模式,否则使用XSD。源代码如下,比较简单。
protected int getValidationModeForResource(Resource resource) { int validationModeToUse = getValidationMode(); //如果手动指定了验证模式则使用指定的验证模式 if (validationModeToUse != VALIDATION_AUTO) { return validationModeToUse; } //如果没有指定,则自动检测 int detectedMode = detectValidationMode(resource); //自动检测主要是在detectValidationMode(Resource resource)完成的 if (detectedMode != VALIDATION_AUTO) { return detectedMode; } return VALIDATION_XSD;}
获得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);}
逻辑:
1.创建DocumentBuilderFactory
2.通过DocumentBuilderFactory创建DocumentBuilder
3.DocumentBuilder解析inputSource返回一个Document对象。
registerBeanDefinitions
获得了XML文档文件的Document以后,就会执行BeanDefinitions的解析和注册。
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { // 得到BeanDefinitionDocumentReader来对XML的BeanDefinition进行解析 BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); int countBefore = getRegistry().getBeanDefinitionCount(); // 具体的解析过程在BeanDefinitionDocumentReader的registerBeanDefinitions方法中完成 documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; }
registerBeanDefinitions对前一步获得的Document进行了处理,实现注册和解析由方法documentReader.registerBeanDefinitions(doc, createReaderContext(resource))实现。
documentReader中的registerBeanDefinitions方法如下:
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); Element root = doc.getDocumentElement(); // 获得Document的根元素 //核心逻辑 doRegisterBeanDefinitions(root);}
真正的实现XML文件解析和加载的核心部分——doRegisterBeanDefinitions方法:
protected void doRegisterBeanDefinitions(Element root) { BeanDefinitionParserDelegate parent = this.delegate; 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)) { return; } } } preProcessXml(root); // 解析Bean定义之前, 增强解析过程的可扩展性 parseBeanDefinitions(root, this.delegate); // 从Document的根元素开始进行Bean定义的Document对象 postProcessXml(root); // 解析Bean定义之前, 增强解析过程的可扩展性 this.delegate = parent;}
核心代码逻辑如下:
1.对profile属性的处理。不同的profile属性可以理解为:代表了xml中beans的不同namespace,一个namespace代表一套的配置方案。
2.preProcessXml方法。在解析之前,我们可以根据需要实现一些逻辑,需要我们自己实现。
3.parseBeanDefinitions方法,对xml配置文件的读取和解析。
4.postProcessXml,在解析完成之后,我们可以根据需要实现一些逻辑,需要我们自己实现。
总结
BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactory.xml"));
1.beanFactory.xml→ClassPathResource
2.使用XmlBeanDefinitionReader的loadBeanDefinitions(Resource resource)读取Resource。
loadBeanDefinitions(resource)的实现逻辑:
2.1.封装资源,new EncodeResource(resource);
2.2.获得输入流,并构造inputsource。
2.3.调用doLoadBeanDefinitions(inputsource,resource)。
doLoadBeanDefinitions(inputsource,resource)的实现:
2.3.1.获得XML验证模式:
方法:getValidationModeForResource
2.3.2.加载XML文件,获得Document类。
方法:loadDocument
2.3.3.根据Document获得Bean。
方法:registerBeanDefinitions(document,resource);
registerBeanDefinitions(document,resource)中的doRegisterBeanDefinitions方法是真正的核心实现。
doRegisterBeanDefinitions实现逻辑:
1.处理profile
2.preProcessXml
3.parseBeanDefinitions方法,对xml配置文件的读取和解析
4.postProcessXml
- Spring之容器的实现
- Spring之IOC容器的实现
- spring技术内幕之IoC容器的实现
- Spring IOC容器的实现
- Spring的IoC容器实现
- 《Spring源码深度解析》阅读笔记3-容器的基本实现之容器的基础XmlBeanFactory
- Spring技术内幕之IOC容器的实现(01)-IOC容器初始化过程
- Spring源码解析之IoC容器系列的设计实现(IoC容器系列概况)
- spring(2) spring容器的实现过程
- Spring IOC之容器实现过程
- Spring 核心之 Ioc容器实现
- 《Spring源码深度解析》阅读笔记2-容器的基本实现之Spring的结构组成
- Spring实现基于容器的事务管理
- 自己实现的Spring IOC容器
- Spring容器内部的实现机制
- Spring中父子容器的实现实例
- spring中父子容器的实现
- Spring中父子容器的实现实例
- Python 写的学生管理系统
- automake搭建项目工程例子讲解
- oracle 数据库
- 学习akka之——akka监督supervision
- 移植Usmart串口调试组件过程
- Spring之容器的实现
- pe节表
- 单元测试A ServletContext is required to configure default servlet handling错误
- JZOJ 5496 Tree
- 第十周 项目1
- 欢迎使用CSDN-markdown编辑器
- MAC 忘记mysql密码怎么办
- CentOS7系统安装Caffe
- 400% 的飞跃-web 页面加载速度优化实战