Spring 源代码阅读指南

本文说明2点:

1.阅读源码的入口在哪里?

2.入门前必备知识了解:IOC和AOP

一、我们从哪里开始

1.准备工作:在官网上下载了Spring源代码之后,导入Eclipse,以方便查询。

2.打开我们使用Spring的项目工程,找到Web.xml这个网站系统配置文件,在其中找到Spring的初始化信息:

 
 
  1. <listener> 
  2.  <listener-class>org.springframework.web.context.ContextLoaderListener</< nodeIndex="1" span>listener-class> 
  3. </< span>listener> 

由配置信息可知,我们开始的入口就这里ContextLoaderListener这个监听器。

在源代码中我们找到了这个类,它的定义是:

 
 
  1. public class ContextLoaderListener extends ContextLoader  
  2.  implements ServletContextListener {  
  3.     …  
  4.  /**  
  5.   * Initialize the root web application context.  
  6.   */ 
  7.  public void contextInitialized(ServletContextEvent event) {  
  8.   this.contextLoader = createContextLoader();  
  9.   if (this.contextLoader == null) {  
  10.    this.contextLoader = this;  
  11.   }  
  12.   this.contextLoader.initWebApplicationContext(event.getServletContext());  
  13.  }  
  14.   ...  
  15. }  

该类继续了ContextLoader并实现了监听器,关于Spring的信息载入配置、初始化便是从这里开始了,具体其他阅读另外写文章来深入了解。

二、关于IOC和AOP

关于Spring IOC 网上很多相关的文章可以阅读,那么我们从中了解到的知识点是什么?

1)IOC容器和AOP切面依赖注入是Spring是核心。

IOC容器为开发者管理对象之间的依赖关系提供了便利和基础服务,其中Bean工厂(BeanFactory)和上下文(ApplicationContext)就是IOC的表现形式

BeanFactory是个接口类,只是对容器提供的最基本服务提供了定义,而DefaultListTableBeanFactory、XmlBeanFactory、ApplicationContext等都是具体的实现。

接口:

 
 
  1. public interface BeanFactory {  
  2.  //这里是对工厂Bean的转义定义,因为如果使用bean的名字检索IOC容器得到的对象是工厂Bean生成的对象,  
  3.  //如果需要得到工厂Bean本身,需要使用转义的名字来向IOC容器检索  
  4.  String FACTORY_BEAN_PREFIX = "&";  
  5.  //这里根据bean的名字,在IOC容器中得到bean实例,这个IOC容器就象一个大的抽象工厂,用户可以根据名字得到需要的bean  
  6.  //在Spring中,Bean和普通的JAVA对象不同在于:  
  7.  //Bean已经包含了我们在Bean定义信息中的依赖关系的处理,同时Bean是已经被放到IOC容器中进行管理了,有它自己的生命周期  
  8.  Object getBean(String name) throws BeansException;  
  9.  //这里根据bean的名字和Class类型来得到bean实例,和上面的方法不同在于它会抛出异常:如果根名字取得的bean实例的Class类型和需要的不同的话。  
  10.  Object getBean(String name, Class requiredType) throws BeansException;  
  11.  //这里提供对bean的检索,看看是否在IOC容器有这个名字的bean  
  12.  boolean containsBean(String name);  
  13.  //这里根据bean名字得到bean实例,并同时判断这个bean是不是单件,在配置的时候,默认的Bean被配置成单件形式,如果不需要单件形式,需要用户在Bean定义信息中标注出来,这样IOC容器在每次接受到用户的getBean要求的时候,会生成一个新的Bean返回给客户使用 - 这就是Prototype形式  
  14.  boolean isSingleton(String name) throws NoSuchBeanDefinitionException;  
  15.  //这里对得到bean实例的Class类型  
  16.  Class getType(String name) throws NoSuchBeanDefinitionException;  
  17.  //这里得到bean的别名,如果根据别名检索,那么其原名也会被检索出来  
  18.  String[] getAliases(String name);  

实现:

XmlBeanFactory的实现是这样的:

 
 
  1. public class XmlBeanFactory extends DefaultListableBeanFactory {  
  2.  //这里为容器定义了一个默认使用的bean定义读取器,在Spring的使用中,Bean定义信息的读取是容器初始化的一部分,但是在实现上是和容器的注册以及依赖的注入是分开的,这样可以使用灵活的 bean定义读取机制。  
  3.  private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);  
  4.  //这里需要一个Resource类型的Bean定义信息,实际上的定位过程是由Resource的构建过程来完成的。  
  5.  public XmlBeanFactory(Resource resource) throws BeansException {  
  6.  this(resource, null);  
  7.  }  
  8.  //在初始化函数中使用读取器来对资源进行读取,得到bean定义信息。这里完成整个IOC容器对Bean定义信息的载入和注册过程  
  9.  public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws 
  10.  BeansException {  
  11.  super(parentBeanFactory);  
  12.  this.reader.loadBeanDefinitions(resource);  

我们可以看到IOC容器使用的一些基本过程:

如:DefaultListableBeanFactory

 
 
  1. ClassPathResource res = new ClassPathResource("beans.xml");//读取配置文件  
  2. DefaultListableBeanFactory factory = new DefaultListableBeanFactory();  
  3. XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);  
  4. reader.loadBeanDefinitions(res);  

这些代码演示了以下几个步骤:

1. 创建IOC配置文件的抽象资源

2. 创建一个BeanFactory,这里我们使用DefaultListableBeanFactory;

3. 创建一个载入bean定义信息的读取器,这里使用XmlBeanDefinitionReader来载入XML形式的bean定义信息,配置给BeanFactory;

4. 从定义好的资源位置读入配置信息,具体的解析过程由XmlBeanDefinitionReader来完成,这样完成整个载入和注册bean定义的过程。我们的IoC容器就建立起来了。

再简单的说,我的系统在启动时候,会完成的动作就是:

1.由ResourceLoader获取资源文件,也即bean的各种配置文件;

2.由BeanDefintion对配置文件的定义信息的载入;

3.用BeanDefinitionRegistry接口来实现载入bean定义信息并向IOC容器进行注册。

注意,IOC容器和上下文的初始化一般不包含Bean的依赖注入的实现。

2)AOP这个过程并不是在注册bean的过程实现的。

我们只看到在处理相关的Bean属性的时候,使用了RuntimeBeanReference对象作为依赖信息的纪录。

在IOC容器已经载入了用户定义的Bean信息前提下,这个依赖注入的过程是用户第一次向IOC容器索要Bean的时候触发的,或者是我们可以在Bean定义信息中通过控制lazy-init属性来使得容器完成对Bean的预实例化 - 这个预实例化也是一个完成依赖注入的过程。

我们说明一下过程:

1.用户想IOC容器请求Bean。

2.系统先在缓存中查找是否有该名称的Bean(去各个BeanFactory去查找)

3.没有的话就去创建Bean并进行依赖注入,并且这个请求将被记录起来。

请求Bean具体的实现:

代码入口在DefaultListableBeanFactory的基类AbstractBeanFactory中:

 
 
  1. public Object getBean(String name, Class requiredType, final Object[] args) throwsBeansException {  
  2. ...  
  3.  Object sharedInstance = getSingleton(beanName);//先去缓存取  
  4.  if (sharedInstance != null) {  
  5.  ...  
  6.   if (containsBeanDefinition(beanName)) {  
  7.    RootBeanDefinition mergedBeanDefinition = getMergedBeanDefinition(beanName, false);  
  8.    bean = getObjectForBeanInstance(sharedInstance, name,mergedBeanDefinition);  
  9.   }  
  10.   else {  
  11.    bean = getObjectForBeanInstance(sharedInstance, name, null);  
  12.   }  
  13.  }  
  14.  else {  
  15.    
  16.  }  
  17.  
  18. ...  

注入Bean具体的实现:

具体的bean创建过程和依赖关系的注入在createBean中,这个方法在AbstractAutowireCapableBeanFactory中给出了实现:

 
 
  1. protected Object createBean(String beanName, RootBeanDefinition  
  2. mergedBeanDefinition, Object[] args)  
  3. throws BeanCreationException {  
  4.  // Guarantee initialization of beans that the current one depends on.  
  5.  // 这里对取得当前bean的所有依赖bean,确定能够取得这些已经被确定的bean,如果没有被创建,那么这个createBean会被这些IOC  
  6.  // getbean时创建这些bean  
  7.  if (mergedBeanDefinition.getDependsOn() != null) {  
  8.   for (int i = 0; i < mergedBeanDefinition.getDependsOn().length; i++) {  
  9.    getBean(mergedBeanDefinition.getDependsOn()[i]);  
  10.   }  
  11.  }  
  12.  ........  
  13.  // 这里是实例化bean对象的地方,注意这个BeanWrapper类,是对bean操作的主要封装类  
  14.  if (instanceWrapper == null) {  
  15.   instanceWrapper = createBeanInstance(beanName, mergedBeanDefinition,args);  
  16.  }  
  17.  Object bean = instanceWrapper.getWrappedInstance();  
  18.  ......  
  19.  //这个populate方法,是对已经创建的bean实例进行依赖注入的地方,会使用到在loadBeanDefinition的时候得到的那些propertyValue来对bean进行注入。  
  20.  if (continueWithPropertyPopulation) {  
  21.   populateBean(beanName, mergedBeanDefinition, instanceWrapper);  
  22.  }  
  23.  //这里完成客户自定义的对bean的一些初始化动作  
  24.  Object originalBean = bean;  
  25.  bean = initializeBean(beanName, bean, mergedBeanDefinition);  
  26.  // Register bean as disposable, and also as dependent on specified "dependsOn"beans.  
  27.  registerDisposableBeanIfNecessary(beanName, originalBean,mergedBeanDefinition);  
  28.  return bean;  
  29. }  
  30. .........  

这就是整个依赖注入的部分处理过程,在这个过程中起主要作用的是WrapperImp ,这个Wrapper不是一个简单的对bean对象的封装,因为它需要处理在beanDefinition中的信息来迭代的处理依赖注入。

到这里,这是简单的,大概的对IOC和AOP进行了解,入门先到这一点便已经有了大概的印象了。

参考资料:《Spring_IOC详解》

原文链接:http://blog.csdn.net/achan2090/article/details/7248043

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 电力能耗管理系统是一种能够帮助企业进行能源管理的软件系统,它能够实现用电计量、数据分析、能源消耗分析等功能。在本文中,我们将介绍一款电力能耗管理系统的源代码开源项目:Github中的“Electricity-Consumption-Management-System”。 这个项目的主要开发语言是Java,使用了Spring框架、Mybatis等技术栈。该系统使用Maven进行依赖管理,可以通过运行SpringBoot主类启动Web服务。该系统的前端采用Bootstrap、jQuery等技术实现,使用了Echarts、Datatables等库展示数据。 通过Github中的源代码,我们可以看到该系统具备了以下功能: 1. 用户管理:系统支持管理员、普通用户的管理权限设置,实现用户管理。 2. 用电计量:通过硬件设备获得电表的电压、电流等数据,实现用电计量。 3. 能源数据分析:系统将计量得到的用电数据进行分析,帮助用户了解能源利用情况。 4. 费用分析:根据计量数据和电价信息进行费用分析,帮助用户控制用电成本。 5. 报表统计:系统提供报表统计功能,帮助用户进行用电情况的综合分析。 总之,这个项目的源代码提供了一份基于Java技术栈的电力能耗管理系统实现案例,有助于有志于学习和实践Java技术的人员进行开发和学习。 ### 回答2: 电力能耗管理系统是一项用于监控和管理企业电力能耗的软件系统。其源代码已经上传至GitHub,可以供开发者进行学习和研究。 电力能耗管理系统的源代码主要包括前端和后端两部分。前端代码基于Vue.js框架,实现了用户界面的设计和交互功能。后端代码基于Spring Boot框架,实现了数据存储、计算和管理等后台业务逻辑的功能。 具体地说,电力能耗管理系统的前端代码主要包括如下模块:登录、首页、设备监控、企业能耗分析、能效评估、报表与数据分析等。而后端代码主要包括如下模块:用户管理、能耗数据读取、数据存储、设备管理、能耗计算和报表生成等。 通过学习电力能耗管理系统的源代码,我们可以了解Vue.js和Spring Boot框架的使用方法,理解前后端数据交互的原理,掌握企业能耗监控和管理的具体方法和实现。同时,我们还可以在此基础上进行二次开发,开发出更加适合企业实际需要的定制化系统。 总之,电力能耗管理系统源代码的公开,为企业电力能耗管理带来了更多的可行性和可持续发展的可能性。 ### 回答3: 电力能耗管理系统源代码的 github 页面提供了该系统的全部源代码,这对于要了解或修改该系统的开发者来说是非常有用的。 该系统的源代码使用的编程语言是 Java,使用了Spring Boot作为框架,MyBatis作为ORM工具,并采用了Maven进行构建和管理。 在该 github 页面中,我们可以看到该系统的代码结构,包括多个模块,如控制台、能效分析、用电管理等。每个模块都有自己的目录和源代码文件,使得开发者可以清晰地了解该系统的架构和模块划分。 此外,该系统的 github 页面还提供了完整的文档和指南,使得开发者能够更好地理解和使用该系统。这些文档包括如何构建该系统、如何配置数据库、如何进行测试和部署等内容,非常详细实用。 总之,该 github 页面提供了一个开放、透明、共享的平台,让开发者们可以更好地掌握和发展这个系统,使其更加完善和适用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值