读Spring源码之前,你要先清楚,为什么你要用Spring...

Spring最基本的功能是做为管理bean的容器,所以我以为应该先从org.springframework.context包了解咯,包括org.springframework.web.context;

然后是org.springframework.beans

org.springframework.aop

你看那个从core开始看就可以了

从ApplicationContext

Spring中文手册是必须的~~

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

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

一、我们从哪里开始

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

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

  1. <listener>
  2. <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  3. </listener>

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

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

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

该类继续了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);
  19. }

实现:

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);
  13. }

我们可以看到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. }

注入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. ; 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. .........
  31. }

这就是整个依赖注入的部分处理过程,在这个过程中起主要作用的是WrapperImp ,这个Wrapper不是一

个简单的对bean对象的封装,因为它需要处理在beanDefinition中的信息来迭代的处理依赖注入。

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

Spring源代码解析(一):IOC容器:http://www.javaeye.com/topic/86339

Spring源代码解析(二):IoC容器在Web容器中的启动:http://www.javaeye.com/topic/86594

Spring源代码解析(三):Spring JDBC:http://www.javaeye.com/topic/87034

Spring源代码解析(四):Spring MVC:http://www.javaeye.com/topic/87692

Spring源代码解析(五):Spring AOP获取Proxy:http://www.javaeye.com/topic/88187

Spring源代码解析(六):Spring声明式事务处理:http://www.javaeye.com/topic/88189

Spring源代码解析(七):Spring AOP中对拦截器调用的实现:http://www.javaeye.com/topic/107785

Spring源代码解析(八):Spring驱动Hibernate的实现:http://www.javaeye.com/topic/110801

Spring源代码解析(九):Spring Acegi框架鉴权的实现:http://www.javaeye.com/topic/112979

Spring源代码解析(十):Spring Acegi框架授权的实现:http://www.javaeye.com/topic/113436

阅读spring源码的更多相关文章

  1. IDEA阅读spring源码并调试

    目标:搭建起Spring源码阅读和代码调试跟踪的环境,顺便建立一个简单的Demo,能够调试Spring的源代码 本节,主要介绍一下Spring源码阅读和调试的相关环境搭建,并使用MVN创建一个非常简单 ...

  2. CRUD搬砖两三年了,怎么阅读Spring源码?

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! ‍连读同事写的代码都费劲,还读Spring? 咋的,Spring 很难读! 这个与我们码农朝夕 ...

  3. Spring源码阅读笔记

    前言 作为一个Java开发者,工作了几年后,越发觉力有点不从心了,技术的世界实在是太过于辽阔了,接触的东西越多,越感到前所未有的恐慌. 每天捣鼓这个捣鼓那个,结果回过头来,才发现这个也不通,那个也不精 ...

  4. Spring源码阅读学习一

    昨天抽时间阅读Spring源码,先从spring 4.x的core包开始吧,除了core和util里,首当其冲的就是asm和cglib. 要实现两个类实例之间的字段的复制功能: 多年之前用C#,因为阅 ...

  5. Sping学习笔记(一)----Spring源码阅读环境的搭建

    idea搭建spring源码阅读环境 安装gradle Github下载Spring源码 新建学习spring源码的项目 idea搭建spring源码阅读环境 安装gradle 在官网中下载gradl ...

  6. Spring源码阅读笔记01:源码阅读环境准备

    1. 写在前面 对于做Java开发的同学来说,Spring就像是一条绕不过去的路,但是大多数也只是停留在对Spring的简单使用层面上,对于其背后的原理所知不多也不愿深究,关于这个问题,我在平时的生活 ...

  7. Spring源码阅读一

    引导: 众所周知,阅读spring源码最开始的就是去了解spring bean的生命周期:bean的生命周期是怎么样的呢,见图知意: 大致流程: 首先后通过BeanDefinitionReader读取 ...

  8. Spring源码之SimpleAliasRegistry解读(一)

    Spring源码之SimpleAliasRegistry解读(一) 阅读spring源码中org.springframework.core.SimpleAliasRegistry类时发现该类主要是使用 ...

  9. Spring源码学习-容器BeanFactory(一) BeanDefinition的创建-解析资源文件

    写在前面 从大四实习至今已一年有余,作为一个程序员,一直没有用心去记录自己工作中遇到的问题,甚是惭愧,打算从今日起开始养成写博客的习惯.作为一名java开发人员,Spring是永远绕不过的话题,它的设 ...

随机推荐

  1. 03_MyBatis基本查询,mapper文件的定义,测试代码的编写,resultMap配置返回值,sql片段配置,select标签标签中的内容介绍,配置使用二级缓存,使用别名的数据类型,条件查询ma

     1 PersonTestMapper.xml中的内容如下: <?xmlversion="1.0"encoding="UTF-8"?> < ...

  2. Android开发学习之路--网络编程之xml、json

    一般网络数据通过http来get,post,那么其中的数据不可能杂乱无章,比如我要post一段数据,肯定是要有一定的格式,协议的.常用的就是xml和json了.在此先要搭建个简单的服务器吧,首先呢下载 ...

  3. MySQl数据库必会sql语句加强版

    这篇承接上一篇<mysql必会sql语句>:http://blog.csdn.net/qq_32059827/article/details/51763950 这一篇属于加强版,问题和sq ...

  4. Java-IO之BufferedOutputStream(缓冲输出流)

    BufferedOutputStream是缓冲输出流,继承于FilterOutputStream,作用是为另外一个输出流提供换从功能. 主要函数列表: BufferedOutputStream(Out ...

  5. A*寻路算法入门(七)

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交流 ...

  6. 存储那些事儿(五):BTRFS文件系统之Btree结构详解

    Btree数据结构可以说是BTRFS文件系统的基础.它提供了一个通用的方式去存储不同的数据类型.它仅仅存储3个数据类型:key, item和block header. btrfs_header的定义如 ...

  7. iOS学习新知识-加速计和陀螺仪

    一.CoreMotion框架介绍 我们知道有一些iOS的应用,会有一些特殊的要求,比如: 电子罗盘指南针之类的应用:让我们知道方向. 运动类型软件:让我们知道我们跑步多少公里. 社交软件中的摇一摇功能 ...

  8. Leetcode_67_Add Binary

    本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/40480151 Given two binary strin ...

  9. MongoDB分组

    MongoDB三种分组方式 group(先筛选再分组,不支持分片,对数据量有所限制,效率不高) [简单分组实测150W 12.5s] mapreduce(基于js引擎,单线程执行,效率较低,适合用做后 ...

  10. Chapter 2 User Authentication, Authorization, and Security(2):创建登录帐号

    原文出处:http://blog.csdn.net/dba_huangzj/article/details/38705965,专题目录:http://blog.csdn.net/dba_huangzj ...