Spring 框架分析

1.Spring 概述

1.1 Spring的优势

  • ⽅便解耦,简化开发
    通过Spring提供的IoC容器,可以将对象间的依赖关系交由Spring进⾏控制,避免硬编码所造成的
    过度程序耦合。⽤户也不必再为单例模式类、属性⽂件解析等这些很底层的需求编写代码,可以更
    专注于上层的应⽤。
  • AOP编程的⽀持
    通过Spring的AOP功能,⽅便进⾏⾯向切⾯的编程,许多不容易⽤传统OOP实现的功能可以通过
    AOP轻松应付。
  • 声明式事务的⽀持
    @Transactional
    可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式⽅式灵活的进⾏事务的管理,提⾼
    开发效率和质量。
  • ⽅便程序的测试
    可以⽤⾮容器依赖的编程⽅式进⾏⼏乎所有的测试⼯作,测试不再是昂贵的操作,⽽是随⼿可做的
    事情。
  • ⽅便集成各种优秀框架
    Spring可以降低各种框架的使⽤难度,提供了对各种优秀框架(Struts、Hibernate、Hessian、
    Quartz等)的直接⽀持。
  • 降低JavaEE API的使⽤难度
    Spring对JavaEE API(如JDBC、JavaMail、远程调⽤等)进⾏了薄薄的封装层,使这些API的使⽤
    难度⼤为降低。
  • 源码是经典的 Java 学习范例
    Spring的源代码设计精妙、结构清晰、匠⼼独⽤,处处体现着⼤师对Java设计模式灵活运⽤以及对
    Java技术的⾼深造诣。它的源代码⽆意是Java技术的最佳实践的范例。

1.2 Spring 的核心结构

Spring是⼀个分层⾮常清晰并且依赖关系、职责定位⾮常明确的轻量级框架,主要包括⼏个⼤模块:数据处理模块、Web模块、AOP(Aspect Oriented Programming)/Aspects模块、Core Container模块和 Test 模块,如下图所示,Spring依靠这些基本模块,实现了⼀个令⼈愉悦的融合了现有解决⽅案的零侵⼊的轻量级框架。

spring rsa分段 spring sowing段落分析_实例化

  • Spring核⼼容器(Core Container) 容器是Spring框架最核⼼的部分,它管理着Spring应⽤中bean的创建、配置和管理。在该模块中,包括了Spring bean⼯⼚,它为Spring提供了DI的功能。基于bean⼯⼚,我们还会发现有多种Spring应⽤上下⽂的实现。所有的Spring模块都构建于核⼼容器之上。
  • ⾯向切⾯编程(AOP)/Aspects Spring对⾯向切⾯编程提供了丰富的⽀持。这个模块是Spring应⽤系统中开发切⾯的基础,与DI⼀样,AOP可以帮助应⽤对象解耦。
  • 数据访问与集成(Data Access/Integration)
    Spring的JDBC和DAO模块封装了⼤量样板代码,这样可以使得数据库代码变得简洁,也可以更专注于我们的业务,还可以避免数据库资源释放失败⽽引起的问题。 另外,Spring AOP为数据访问提供了事务管理服务,同时Spring还对ORM进⾏了集成,如Hibernate、MyBatis等。该模块由JDBC、Transactions、ORM、OXM 和 JMS 等模块组成。
  • Web 该模块提供了SpringMVC框架给Web应⽤,还提供了多种构建和其它应⽤交互的远程调⽤⽅案。 SpringMVC框架在Web层提升了应⽤的松耦合⽔平。
  • Test 为了使得开发者能够很⽅便的进⾏测试,Spring提供了测试模块以致⼒于Spring应⽤的测试。 通过该模块,Spring为使⽤Servlet、JNDI等编写单元测试提供了⼀系列的mock对象实现。

2.核心思想

2.1什么是IOC?

IOC:Inversion Of Control (控制反转/反转控制),注意IOC描述的是一个技术思想,并非具体实现。
IOC描述的事情是 面向对象语言开发领域 对象的创建,管理的问题。
传统开发方式:比如类A依赖于类B,我们会在类A中new一个类B的对象。
IOC思想下开发方式:我们不用再代码中去new对象了,而是引入一个IOC容器(Spring 框架实现),由这个IOC框架来帮助我们去实例化并且管理对象,当类A需要使用类B对象的时候,由IOC容器将这个B对象注入到A对象中。
为什么称作控制反转?
控制:指的是对象创建(实例化,管理)的权利
反转:控制权不在我们手中,而是交给IOC容器了。

spring rsa分段 spring sowing段落分析_spring rsa分段_02

2.2 IOC解决了什么问题?

解决对象之间的耦合度过高的问题

spring rsa分段 spring sowing段落分析_spring rsa分段_03

2.3 IOC和DI(Dependancy Injection)的区别

IOC和DI其实描述的都是同一件事情(对象的实例化,管理,依赖关系维护),只是角度不一样罢了。
IOC是站在对象的角度,对象的实例化,管理,依赖关系维护反转给了IOC容器。
DI是站在容器的角度,容器会把对象依赖的其他对象注入

2.4 什么是AOP?

AOP:Aspect Oriented Programming 面向切面编程

AOP是OOP(Object Oriented Programming)的延续,从OOP先说起.

OOP三大特征:封装,继承,多态。

spring rsa分段 spring sowing段落分析_实例化_04


以上图为例,可以看出OOP是一种垂直纵向的继承体系。OOP编程思想可以解决绝大多数的代码重复的问题,但是有一些情况是处理不了的。比如在下图的顶级父类Animal中的多个方法中的相同位置出现了重复代码,OOP就无法解决。

spring rsa分段 spring sowing段落分析_实例化_05


横切逻辑代码:在多个顺序流程中出现的相同子代码流程,我们称之为横切逻辑代码。

比入上图的性能监控。

横切逻辑代码的使用场景比较有限:一般是事务控制,权限校验,日志。

横切逻辑代码存在的问题:

  • 横切逻辑代码重复的问题。
  • 横切逻辑代码与业务代码混杂在一起,维护非常不方便。

此时AOP出场,AOP思想提出横向抽取机制,将横切逻辑代码和业务代码进行拆分。如下图

spring rsa分段 spring sowing段落分析_AOP_06


代码拆分是很容易的,但是如何在不改变原有业务逻辑的条件下,实现将横切逻辑代码织入到业务逻辑代码中,达到和未拆分前一致的效果,这个是比较难的。后面我们会在分析源码时继续探讨Spring是如何优雅实现AOP的。

2.5 AOP解决了什么问题?

解决在不改变原有业务逻辑的条件下,实现将横切逻辑代码织入到业务逻辑代码中,在根本上解耦合,避免了横切逻辑代码重复。

2.6 为什么叫做面向切面编程?

将切面二字拆开理解:
切:指的是横切逻辑。
面:被横切逻辑代码影响的往往是多个方法的多个连接点,多点成线,线再组成面。

3.Spring IOC应用

3.1 Spring IOC基础

spring rsa分段 spring sowing段落分析_spring rsa分段_07


Spring实现IOC的配置有三种情形:

1.纯XML:

bean信息的定义和依赖全部配置在xml中

2.XML+注解:

部分bean(通常是引入第三方jar包的bean并将其加入到IOC容器)使用xml定义,部分bean(通常是SpringBean)使用注解

3.纯注解模式:

所有的bean都用注解来定义。

通常实际开发中,使用较多的是2和3.
以上3种场景下,对应JAVASE和JAVAWEB应用启动IOC容器时需要使用不同的容器类。

3.2 BeanFactory 和 ApplicationContext的区别

BeanFactory是Spring框架中IOC容器的顶层接口,也称之为基础容器,它只用来定义一些容器的基础功能,定义一些基础规范。

而ApplicationContext 是BeanFactory的子接口,也称之为高级容器,它具备BeanFactory 定义的全部功能,比如说国际化支持和资源访问等等。

spring rsa分段 spring sowing段落分析_实例化_08

3.3 启动IOC容器方式

启动IOC容器的方式:
Java环境下启动IoC容器
ClassPathXmlApplicationContext:从类的根路径下加载配置⽂件(推荐使⽤)
FileSystemXmlApplicationContext:从磁盘路径上加载配置⽂件
AnnotationConfigApplicationContext:纯注解模式下启动Spring容器

Web环境下启动IoC容器
从xml启动容器

<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
 <display-name>Archetype Created Web Application</display-name>
 <!--配置Spring ioc容器的配置⽂件-->
 <context-param>
 <param-name>contextConfigLocation</param-name>
 <param-value>classpath:applicationContext.xml</param-value>
 </context-param>
 <!--使⽤监听器启动Spring的IOC容器-->
 <listener>
 <listenerclass>org.springframework.web.context.ContextLoaderListener</listenerclass>
 </listener>
</web-app

从配置类启动容器

<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
 <display-name>Archetype Created Web Application</display-name>
 <!--告诉ContextloaderListener知道我们使⽤注解的⽅式启动ioc容器-->
 <context-param>
 <param-name>contextClass</param-name>
 <paramvalue>org.springframework.web.context.support.AnnotationConfigWebAppli
cationContext</param-value>
 </context-param>

 <!--配置启动类的全限定类名-->
 <context-param>
 <param-name>contextConfigLocation</param-name>
 <param-value>com.lagou.edu.SpringConfig</param-value>
 </context-param>
 <!--使⽤监听器启动Spring的IOC容器-->
 <listener>
 <listenerclass>org.springframework.web.context.ContextLoaderListener</listenerclass>
 </listener>
</web-app>

3.4 Spring实例化bean的方式

spring实例化bean的四种方式:

  • 使用构造器实例化Bean
    无参构造
  • spring rsa分段 spring sowing段落分析_AOP_09

  • 有参构造
  • spring rsa分段 spring sowing段落分析_Web_10

  • 使用静态工厂方式实例化Bean
  • spring rsa分段 spring sowing段落分析_实例化_11


  • spring rsa分段 spring sowing段落分析_AOP_12

  • 使用实例工厂方法实例化Bean
  • spring rsa分段 spring sowing段落分析_AOP_13


  • spring rsa分段 spring sowing段落分析_spring rsa分段_14

  • 使用setter 方式
  • spring rsa分段 spring sowing段落分析_AOP_15

3.5 Bean的作用域及生命周期

下图是Spring 官方对框架支持的bean作用域介绍:

spring rsa分段 spring sowing段落分析_spring rsa分段_16


需要注意的是,Spring框架在默认配置下创建的bean对象都是singleton(单例)。

  • singleton 单例模式,spring IOC容器中仅存在一个,容器初始化时就会加载(懒加载除外)。
  • prototype 原型模式,也叫作多例模式。每次从容器中请求bean时,都会返回一个新的实例。容器初始化时不会加载,只有在请求容器时才会创建。
  • 剩下4种都是应用于WebApplicationContext环境。

根据经验,对有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域

生命周期:

  • 单例模式:singleton
    对象出生:当容器创建时,对象就被创建了(除懒加载)
    对象生存:只有容器存在时,对象一直存在。
    对象死亡:当销毁容器时,对象也被销毁。
    一句话概括:单例模式对象的bean生命周期与容器相同。
  • 多例模式:prototype
    对象出生:当使用对象时,创建新的对象实例。
    对象生存:只有对象在使用中,对象一直存在。
    对象死亡:当对象长时间不用时,对象也被GC回收。
    一句话概括:多例模式对象的bean对象,spring只负责创建,不负责销毁。