spring源码--容器的基本实现

简介:




spring源码各版本下载地址:

    https://github.com/spring-projects/spring-framework/tags


在工作中见得非常多的容器使用是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<beans xmlns= "http://www.springframework.org/schema/beans"
     xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"  xmlns:util= "http://www.springframework.org/schema/util"
     xmlns:jee= "http://www.springframework.org/schema/jee"  xmlns:aop= "http://www.springframework.org/schema/aop"
     xmlns:tx= "http://www.springframework.org/schema/tx"  xmlns:context= "http://www.springframework.org/schema/context"
     xmlns:p= "http://www.springframework.org/schema/p"  xmlns:cache= "http://www.springframework.org/schema/cache"
     xmlns:task= "http://www.springframework.org/schema/task"
     xsi:schemaLocation="
     http: //www.springframework.org/schema/task 
     http: //www.springframework.org/schema/task/spring-task-4.1.xsd
     http: //www.springframework.org/schema/beans
     http: //www.springframework.org/schema/beans/spring-beans-4.1.xsd
     http: //www.springframework.org/schema/aop 
     http: //www.springframework.org/schema/aop/spring-aop-4.1.xsd
     http: //www.springframework.org/schema/tx
     http: //www.springframework.org/schema/tx/spring-tx-4.1.xsd
     http: //www.springframework.org/schema/context
     http: //www.springframework.org/schema/context/spring-context-4.1.xsd
     http: //www.springframework.org/schema/util 
     http: //www.springframework.org/schema/util/spring-util-4.1.xsd
     http: //www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.1.xsd">
     <bean id= "adapConsumer"  class = "com.ad.jms.AdapConsumer" >
           <property name= "queueChannel"  ref= "inputFromKafkaAdap" ></property>
     </bean>
</beans>
1
2
final  ApplicationContext app =  new  ClassPathXmlApplicationContext( "applicationContext.xml" );
AdapConsumer adConsumer = app.getBean( "adapConsumer" , AdapConsumer. class );

其底层实现原理是怎样的?根据《Spring源码深度解析》以另外一个容器BeanFactory来解析源码实现。

image.png



一、可以发现BeanFactory是通过XmlBeanFactory创建的,而XmlBeanFactory继承了DefaultListableBeanFactory,主要增加了XMLBeanDefinitionReader,接下来先认识一下这两个类。

    1.1 DefaultListableBeanFactory

image.png

其中各个类的作用

image.png

image.png

image.png

    

    1.2 XMLBeanDefinitionReader

完成了对配置文件进行封装后配置文件的读取工作。

image.png


二、我们根据BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"))来分析建立过程

    2.1 new ClassPathResource("beanFactoryTest.xml")

这是通过ClassPathResource构造函数来构造一个ReSource,然后交给XmlBeanFactory的构造函数。那么ClassPathResource怎么处理的?


ReSource底层实现:

image.png

image.png

    

    2.2 new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"))

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public  class  XmlBeanFactory  extends  DefaultListableBeanFactory {
 
    private  final  XmlBeanDefinitionReader reader =  new  XmlBeanDefinitionReader( this );
 
    public  XmlBeanFactory(Resource resource)  throws  BeansException {
       this (resource,  null );
    }
 
    public  XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory)  throws  BeansException {
       super (parentBeanFactory);
       this .reader.loadBeanDefinitions(resource);
       
    }
}
//最后一句代码主要完成下面三个功能

image.png

image.png

可以看到有XMLBeanDefinitionReader对象(完成了对配置文件进行封装后配置文件的读取工作),就是加载bean,在代码中一层一层往下看:

1
2
3
public  int  loadBeanDefinitions(Resource resource)  throws  BeanDefinitionStoreException {
    return  loadBeanDefinitions( new  EncodedResource(resource));
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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<>( 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();
       }
    }
}

上面这段代码真正进入了数据的准备阶段执行下面正式进入核心部分:

1
doLoadBeanDefinitions(inputSource, encodedResource.getResource())

doLoadBeanDefinitions之所以很核心,因为做了三件重要的事情:

image.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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);
    }
}
protected  Document doLoadDocument(InputSource inputSource, Resource resource)  throws  Exception {
    return  this .documentLoader.loadDocument(inputSource, getEntityResolver(),  this .errorHandler,
          getValidationModeForResource(resource), isNamespaceAware());
}
public  int  registerBeanDefinitions(Document doc, Resource resource)  throws  BeanDefinitionStoreException {
    BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    int  countBefore = getRegistry().getBeanDefinitionCount();
    documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    return  getRegistry().getBeanDefinitionCount() - countBefore;
}

接下来将这三件事情逐个分析:

    2.2.1 获取xml文件的验证模式

    DTD和XSD的区别:

image.png

image.png

 

    验证模式的读取:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
protected  int  getValidationModeForResource(Resource resource) {
    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;
}

    2.2.2 读取document

image.png

1
2
3
4
protected  Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
    return  this .documentLoader.loadDocument(inputSource, getEntityResolver(),  this .errorHandler,
          getValidationModeForResource(resource), isNamespaceAware());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package  org.springframework.beans.factory.xml;
 
import  org.w3c.dom.Document;
import  org.xml.sax.EntityResolver;
import  org.xml.sax.ErrorHandler;
import  org.xml.sax.InputSource;
 
public  interface  DocumentLoader {
 
    Document loadDocument(
          InputSource inputSource, EntityResolver entityResolver,
          ErrorHandler errorHandler,  int  validationMode,  boolean  namespaceAware)
          throws  Exception;
 
}

    2.2.3 根据返回的document注册bean信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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);
    }
}

registerBeanDefinitions方法:

1
2
3
4
5
6
public  int  registerBeanDefinitions(Document doc, Resource resource)  throws  BeanDefinitionStoreException {
    BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    int  countBefore = getRegistry().getBeanDefinitionCount();
    documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    return  getRegistry().getBeanDefinitionCount() - countBefore;
}

image.png

image.png

image.png

image.png

image.png

解析并注册BeanDefinition

image.png


image.png

image.png



本文转自 叫我北北 51CTO博客,原文链接:http://blog.51cto.com/qinbin/2059124


相关文章
|
7月前
|
XML Java 测试技术
《深入理解Spring》:IoC容器核心原理与实战
Spring IoC通过控制反转与依赖注入实现对象间的解耦,由容器统一管理Bean的生命周期与依赖关系。支持XML、注解和Java配置三种方式,结合作用域、条件化配置与循环依赖处理等机制,提升应用的可维护性与可测试性,是现代Java开发的核心基石。
|
7月前
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
725 2
|
前端开发 Java 物联网
智慧班牌源码,采用Java + Spring Boot后端框架,搭配Vue2前端技术,支持SaaS云部署
智慧班牌系统是一款基于信息化与物联网技术的校园管理工具,集成电子屏显示、人脸识别及数据交互功能,实现班级信息展示、智能考勤与家校互通。系统采用Java + Spring Boot后端框架,搭配Vue2前端技术,支持SaaS云部署与私有化定制。核心功能涵盖信息发布、考勤管理、教务处理及数据分析,助力校园文化建设与教学优化。其综合性和可扩展性有效打破数据孤岛,提升交互体验并降低管理成本,适用于日常教学、考试管理和应急场景,为智慧校园建设提供全面解决方案。
704 70
|
9月前
|
设计模式 Java 开发者
如何快速上手【Spring AOP】?从动态代理到源码剖析(下篇)
Spring AOP的实现本质上依赖于代理模式这一经典设计模式。代理模式通过引入代理对象作为目标对象的中间层,实现了对目标对象访问的控制与增强,其核心价值在于解耦核心业务逻辑与横切关注点。在框架设计中,这种模式广泛用于实现功能扩展(如远程调用、延迟加载)、行为拦截(如权限校验、异常处理)等场景,为系统提供了更高的灵活性和可维护性。
1327 0
|
XML Java 数据格式
Spring IoC容器的设计与实现
Spring 是一个功能强大且模块化的 Java 开发框架,其核心架构围绕 IoC 容器、AOP、数据访问与集成、Web 层支持等展开。其中,`BeanFactory` 和 `ApplicationContext` 是 Spring 容器的核心组件,分别定位为基础容器和高级容器,前者提供轻量级的 Bean 管理,后者扩展了事件发布、国际化等功能。
339 18
|
XML Java 数据格式
京东一面:spring ioc容器本质是什么? ioc容器启动的步骤有哪些?
京东一面:spring ioc容器本质是什么? ioc容器启动的步骤有哪些?
|
XML Java 数据格式
Spring容器的本质
本文主要讨论Spring容器最核心的机制,用最少的代码讲清楚Spring容器的本质。
|
监控 JavaScript 数据可视化
建筑施工一体化信息管理平台源码,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
智慧工地云平台是专为建筑施工领域打造的一体化信息管理平台,利用大数据、云计算、物联网等技术,实现施工区域各系统数据汇总与可视化管理。平台涵盖人员、设备、物料、环境等关键因素的实时监控与数据分析,提供远程指挥、决策支持等功能,提升工作效率,促进产业信息化发展。系统由PC端、APP移动端及项目、监管、数据屏三大平台组成,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
625 7
|
存储 监控 数据可视化
SaaS云计算技术的智慧工地源码,基于Java+Spring Cloud框架开发
智慧工地源码基于微服务+Java+Spring Cloud +UniApp +MySql架构,利用传感器、监控摄像头、AI、大数据等技术,实现施工现场的实时监测、数据分析与智能决策。平台涵盖人员、车辆、视频监控、施工质量、设备、环境和能耗管理七大维度,提供可视化管理、智能化报警、移动智能办公及分布计算存储等功能,全面提升工地的安全性、效率和质量。
363 0