完美的东西往往有一个致命的缺点,那就是不真实。——《周浩晖精选集》

1、Spring框架概述

1.1 Spring简介

Spring是分层的JavaSE/EE full-stack(一站式) 轻量级开源框架

  • 分层: 来自JavaEE体系结构 (客户端层、 web层、业务层、持久层 )

服务器端三层结构 (web层、业务层、持久层)
Servlet + JSP —- web层技术 —- Struts2框架或SpringMVC框架
JDBC 接口 —- 持久化技术 —- Hibernate框架或Mybatis框架
EJB 框架(复杂) —- 业务层技术 —- Spring 框架 (取代EJB出现 )

  • Spring 出现,就是为了解决常见JavaEE 企业开发问题!
    (1)一站式: Spring框架提供了 web层(表现层) SpringMVC、 业务层 IoC、AOP和事务管理、 持久层JdbcTemplate 各层javaEE软件开发解决方案
    (2)轻量级:相对于EJB框架而言

1.2 Spring优点

(1)方便解耦,简化开发(Spring IoC特性)
(2)AOP编程的支持
(3)声明式事务的支持
(4)方便程序的测试
(5)方便集成各种优秀框架 (整合Struts2 、 Hibernate 、MyBatis 、Struts1 )
(6)降低JavaEE API的使用难度 (Spring 提供大量工具类, 简化代码编写 )

1.3 Spring体系结构

这里写图片描述

图中将spring分为5个部分:core、aop、data access、web、test,图中每个圆角矩形都对应一个jar,如果在maven中配置,所有这些jar的“groupId”都是“org.springframework”,每个jar有一个不同的“artifactId”,另外,“instrumentation”有两个jar,还有一个“spring-context-support”图中没有列出,所以spring4的jar包一共是20个.

1.3.1 核心容器(Core Container)

核心容器包含spring-core、spring-beans、spring-context、spring-context-support和spring-expression (Spring Expression Language,Spring表达式语言)这些模块。

  • spring-core:构成了框架最基础的部分,包括控制反转和依赖注入功能;
  • spring-beans:Bean工厂与bean的装配;
  • spring-context:是基于spring-core和spring-beans构建的,它提供了一种以框架风格来访问对象的方式,类似于JNDI注册。ApplicationContext接口是spring-context的焦点。spring的context上下文即IoC容器;
  • spring-context-support:为集成第三方库(如定时器Quartz)提供支持;
  • spring-expression:提供了一种强大的表达式语言,可以在运行时查询和操作对象。

完整依赖关系:
这里写图片描述

1.3.2 AOP和设备(AOP、Aspects、Instrumentation、Messaging)

核心容器包含spring-core、spring-beans、spring-context、spring-context-support和spring-expression (Spring Expression Language,Spring表达式语言)这些模块。

  • spring-aop模块提供了一个AOP面向切面编程的实现。比如,允许开发者定义方法拦截器和切入点,以此来将业务逻辑和系统服务进行解耦;
  • spring-aspects模块提供与AspectJ的集成;
  • spring-instrument模块提供了在普通应用服务器中使用到的类设备支持和加载器实现;
  • spring-instrument-tomcat模块包含了Spring的Tomcat设备代理。
  • spring-messaging-Spring 4包含了一个spring-messaging模块,它对Spring集成项目Message、MessageChannel和MessageHandler进行了重要的抽象,它是基于消息发送应用的基础。

1.3.3 数据访问/集成(Data Access/Integration)

  • spring-jdbc:对JDBC的简单封装;
  • spring-jms:为简化jms api的使用而做的简单封装;
  • spring-orm:整合第三方的orm实现,如hibernate,ibatis,jdo以及spring 的jpa实现;
  • spring-oxm:Spring对于object/xml映射的支持,可以让JAVA与XML之间来回切换;
  • spring-tx:为JDBC、Hibernate、JDO、JPA等提供的一致的声明式和编程式事务管理。

1.3.4 Web

Web层包含spring-web、spring-webmvc、spring-websocket和spring-webmvc-portlet模块。

  • spring-web:包含Web应用开发时,用到Spring框架时所需的核心类,包括自动载入WebApplicationContext特性的类、Struts与JSF集成类、文件上传的支持类、Filter类和大量工具辅助类。
  • spring-webmvc:包含SpringMVC框架相关的所有类。包含国际化、标签、Theme、视图展现的FreeMarker、JasperReports、Tiles、Velocity、XSLT相关类。当然,如果你的应用使用了独立的MVC框架,则无需这个JAR文件里的任何类;
  • spring-webmvc-portlet模块提供了在Portlet环境下的MVC实现;
  • spring-websocket:为web应用提供的高效通信工具。

1.3.5 测试(Test)

  • spring test:支持Spring组建JUnit和TestNG的单元测试和集成测试。

2、IoC和DI

(1)IoC: 控制反转, 解决程序对象紧密耦合问题(工厂+反射+ 配置文件), 将程序中原来构造对象的权限,交给IoC容器来构造,当程序需要对象,找IoC容器获取;
这里写图片描述
(2)DI : 依赖注入 , IoC容器需要为程序提供依赖对象,返回对象所依赖对象一同可以提供(Servlet需要Service, 找Ioc容器获取Service, Service由容器提供,Service依赖DAO ,IoC容器提供Service对象同时, 将Service依赖DAO 注入到Service中)

IoC容器到底为程序提供了什么? 提供依赖对象
这里写图片描述

2.1 BeanFactory 和 ApplicationContext 接口

ApplicationContext 是 BeanFactory 子接口,BeanFactory 才是Spring框架最核心工厂接口。
ApplicationContext 是对BeanFactory 接口扩展, 企业开发很少直接使用BeanFactory
ApplicationContext 会在容器初始化时,对其中管理Bean对象进行创建, BeanFactory 会在对象获取时才进行初始化 。

BeanFactory 在解析配置文件时并不会初始化对象,只有在使用对象时(getBean())才会对该对象进行初始化
ApplicationContext 在解析配置文件时对配置文件中的所有对象都初始化了,getBean()方法只是获取对象的过程

2.2 IoC容器装配Bean(xml配置)

三种实例化Bean的方式

方式一: 使用类构造器实例化对象 
<!-- 方式一  使用构造器(无参数)实例化对象  -->
    <bean id="bean1" 
class="cn.itcast.spring.b_instance.Bean1" />

方式二: 使用静态工厂 静态方法,对对象实例化
<!-- 方式二 使用静态工厂实例化对象 -->
    <!-- 调用 工厂的 factory-method 返回对象 -->
    <bean id="bean2" 
class="cn.itcast.spring.b_instance.Bean2Factory" factory-method="getBean2" />

方式三: 使用实例工厂 实例方法 对对象实例化 
<!-- 方式三 使用实例工厂实例化对象 -->
    <!-- 先实例化工厂 -->
    <bean id="bean3Factory" class="cn.itcast.spring.b_instance.Bean3Factory" />
    <!-- 再通过工厂对象的实例方法,构造目标对象 -->
    <bean id="bean3" factory-bean="bean3Factory" 
factory-method="getBean3" />

应用场景: 大多数情况,可以通过构造器直接实例化, 只有在对象构造过程非常复杂的情况下,才会采用工厂实例化的方式

2.3 Bean的作用域

Spring为Bean对象,提供五种作用域
这里写图片描述
最常用 singleton 和 prototype 两种
Singleton (单例): 在一个BeanFactory对象中,引用唯一的一个目标实例
Prototype (多例): 每次通过工厂执行getBean时,返回不同实例对象
Request (请求范围) : 创建对象保存在request范围,如果request销毁,对象销毁
Session (会话范围): 创建对象保存Session中, 如果session销毁,对象销毁
* globalSession (全局会话 ) :分布式系统,全局会话的概念, 一次登录,应用多个系统

单例Bean 在容器初始化时,实例化 (只实例化一次 )
多例Bean 在工程执行getBean时 才会实例化 (每调用一次,返回不同对象 )

2.4 Bean的生命周期

可以通过 init-method属性配置 Bean对象初始化执行方法,destory-method属性配置Bean对象销毁的方法
(初始化方法和构造方法 有区别? 构造方法作用申请空间,为对象基本属性初始化 , 初始化方法 对象复杂构造过程 , java语言建议将对象复杂构造过程单独抽取 初始化方法 )
这里写图片描述

配置
这里写图片描述

在对象构造后,立即执行初始化init , 默认没有执行destroy 销毁方法
这里写图片描述

在Spring构造Bean对象过程中,有一个环节对Bean对象进行 后处理操作 (钩子函数) —– Spring 提供 BeanPostProcessor 接口
可以自定义类,实现 BeanPostProcessor 接口,配置到Spring容器中,在构造对象时,spring容器会调用接口中方法 。

3、AOP

3.1 AOP概念

  • AOP Aspect Oriented Programing 面向切面编程
  • AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视、事务管理、安全检查、缓存)
  • Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码
  • AspecJ是一个基于Java语言的AOP框架,Spring2.0开始,Spring AOP引入对Aspect的支持

(1)业界 AOP 实际上 OOP (面向对象编程 ) 延伸 —- OOP编程语言、 AOP设计思想 ;
(2)AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视、事务管理、安全检查、缓存)
(3)横向抽取代码复用,基于代理技术,在不修改原有对象代码情况下,对原有对象方法功能进行增强! ———- AOP 思想

这里写图片描述

3.2 AOP相关术语

  • Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点.
  • Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义.
  • Advice(通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
  • Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field.
  • Target(目标对象):代理的目标对象
  • Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程.
    spring采用动态代理织入,而AspectJ采用编译期织入和类装在期织入
  • Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类
  • Aspect(切面): 是切入点和通知(引介)的结合

这里写图片描述

3.3 AOP底层实现

Spring AOP 代理实现有两种: JDK动态代理和Cglib框架动态代理

(1)JDK动态代理
JDK API 内置 —- 通过 Proxy类,为目标对象创建代理 (必须面向接口代理 )

public class JdkProxyFactory implements InvocationHandler {
    // 被代理对象
    private Object target;

    // 在构造方法对象时,传入被代理对象
    public JdkProxyFactory(Object target) {
        this.target = target;
    }

    // 创建代理
    public Object createProxy() {
        // 三个参数: 类加载器、 实现接口、 invocationhandler
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("记录日志!!!!!!");
        // 调用目标真实方法
        // target 被代理对象, args 方法参数 , method 被调用的方法
        return method.invoke(target, args);
    }
}

缺点: 使用Jdk动态代理,必须要求target目标对象,实现接口 ,如果没有接口,不能使用Jdk动态代理

(2)Cglib 动态代理
CGLIB(Code Generation Library)是一个开源项目!是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。

Cglib 不但可以对接口进行代理,也可以对目标类对象,实现代理 (解决了 Jdk 只能对接口代理问题 )
下载网址: http://sourceforge.net/projects/cglib/files/
——- 在spring3.2版本 core包中内置cglib 类

public class CglibProxyFactory implements MethodInterceptor {
    // 被代理目标对象
    private Object target;

    // 在构造工厂时传入被代理对象
    public CglibProxyFactory(Object target) {
        this.target = target;
    }

    // 创建代理对象方法
    public Object createProxy() {
        // 1、 创建Enhancer对象
        Enhancer enhancer = new Enhancer();

        // 2、 cglib创建代理,对目标对象,创建子类对象
        enhancer.setSuperclass(target.getClass());

        // 3、传入 callback对象,对目标增强
        enhancer.setCallback(this);

        return enhancer.create();
    }

    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("记录日志......");
        // 按照JDK编程
        return method.invoke(target, args);
    }
}

Cglib 创建代理思想: 对目标类创建子类对象设置 superClass 对哪个类创建子类 (类似 JDK代理 接口)设置 callback 实现增强代码 (类似 JDK代理 InvocationHandler )在cglib的callback函数中,要执行被代理对象的方法 method.invoke(target, args); 等价于 methodProxy.invokeSuper(proxy, args);

4、事务管理和框架整合

4.1 事务的概念

理解事务之前,先讲一个日常生活中最常干的事:取钱。

比如你去ATM机取1000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉1000元钱;然后ATM出1000元钱。这两个步骤必须是要么都执行要么都不执行。如果银行卡扣除了1000块但是ATM出钱失败的话,你将会损失1000元;如果银行卡扣钱失败但是ATM却出了1000块,那么银行将损失1000元。所以,如果一个步骤成功另一个步骤失败对双方都不是好事,如果不管哪一个步骤失败了以后,整个取钱过程都能回滚,也就是完全取消所有操作的话,这对双方都是极好的。
事务就是用来解决类似问题的。事务是一系列的动作,它们综合在一起才是一个完整的工作单元,这些动作必须全部完成,如果有一个失败的话,那么事务就会回滚到最开始的状态,仿佛什么都没发生过一样。
在企业级应用程序开发中,事务管理必不可少的技术,用来确保数据的完整性和一致性。

  • 事务有四个特性:ACID

(1)原子性(Atomicity):事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用。
(2)一致性(Consistency):一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。在现实中的数据不应该被破坏。
(3)隔离性(Isolation):可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。
(4)持久性(Durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。通常情况下,事务的结果被写到持久化存储器中。

4.2 事务管理器

  • Spring事务管理涉及的接口的联系如下:

这里写图片描述
Spring事务管理高层抽象主要包括3个接口

  • PlatformTransactionManager
    事务管理器
  • TransactionDefinition
    事务定义信息(隔离、传播、超时、只读)
  • TransactionStatus
    事务具体运行状态

4.2.1 PlatformTransactionManager事务管理器

       Spring并不直接管理事务,而是提供了多种事务管理器,他们将事务管理的职责委托给Hibernate或者JTA等持久化机制所提供的相关平台框架的事务来实现。
       Spring事务管理器的接口是org.springframework.transaction.PlatformTransactionManager,通过这个接口,Spring为各个平台如JDBC、Hibernate等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了。
这里写图片描述

  • 对Jdbc、ApacheDbUtils、JdbcTemplate、MyBatis 进行事务管理
    —- DataSourceTransactionManager
  • 对Hibernate 进行事务管理
    —- HibernateTransactionManager

  • 平台事务管理器API
    这里写图片描述
    commit 提交事务
    rollback 回滚事务
    TransactionStatus getTransaction(TransactionDefinition) 根据事务定义信息获取事务状态信息

4.2.2 TransactionDefinition事务定义信息(隔离、传播、超时、只读)

上面讲到的事务管理器接口PlatformTransactionManager通过getTransaction(TransactionDefinition definition)方法来得到事务,这个方法里面的参数是TransactionDefinition类,这个类就定义了一些基本的事务属性。
那么什么是事务属性呢?事务属性可以理解成事务的一些基本配置,描述了事务策略如何应用到方法上

(1)ISOLATION_* 事务隔离级别
事务特性(ACID 原子性、一致性、隔离性、持久性 ) ,事务隔离性引发问题(脏读、不可重复读、 虚读 ), 数据库为了解决事务隔离性导致问题,引入四个隔离级别
这里写图片描述

DEFAULT 每种数据库提供默认隔离级别 mysql REPEATABLE_READ、oracle READ_COMMITTED
READ_UNCOMMITTED:引发所有隔离问题(脏读、不可重复读、虚读)
READ_COMMITTED:解决脏读, 引发(不可重复读、虚读)
REPEATABLE_READ : 解决脏读、不可重复读、 引发虚读
SERIALIZABLE :事务不存在并发性,阻止所有并发问题发生 (不推荐)
(2)PROPAGATION_* 事务的传播行为
传播行为不是数据库特性, 解决企业实际开发中事务隔离问题 —- 解决两个事务互相调用的问题
这里写图片描述
这里写图片描述

REQUIRED : 删除用户,删除订单, 使用同一个事务 ,删除订单必须存在事务
SUPPRTS :删除用户,删除订单, 使用同一个事务,如果删除用户没有事务,删除订单不使用事务
MANDATORY:删除用户,删除订单, 使用同一个事务,如果删除用户没有事务,删除订单直接抛出异常

REQUIRES_NEW: ATM取款后,打印凭条必须开启一个新的事务
NOT_SUPPORT:ATM取款后,打印凭条不使用事务运行
NEVER : 如何ATM取款,开启事务,打印凭条直接事务

NESTED : 嵌套事务 (只对DataSourceTransactionManager 起效), ATM取款和打印凭条处于同一个事务,在ATM取款后,设置SavePoint保存点,如果打印凭条出现问题,可以回滚到保存点
重点学习: REQUIRED、REQUIRES_NEW、NESTED

TIMEOUT_DEFAULT 超时时间
Read-Only 是否只读 (如果只读事务,不能执行 insert、update、delete操作)

4.2.3 TransactionStatus事务具体运行状态

事务状态信息(事务在执行过程中,某一个时间点状态)
这里写图片描述

public interface TransactionStatus{
    boolean isNewTransaction(); // 是否是新的事物
    boolean hasSavepoint(); // 是否有恢复点
    void setRollbackOnly();  // 设置为只回滚
    boolean isRollbackOnly(); // 是否为只回滚
    boolean isCompleted; // 是否已完成
} 

可以发现这个接口描述的是一些处理事务提供简单的控制事务执行和查询事务状态的方法,在回滚或提交的时候需要应用对应的事务状态。

4.2.4编程式事务管理 和 声明式事务管理

1、 编程式事务,需要代码侵入 ,使用TransactionTemplate 模板类 (企业不用)

transactionTemplate.execute(new TransactionCallbackWithoutResult(){
        T doInTransaction(){
            // 数据库操作代码
        }
});

doInTransaction方法只要发生异常,事务回滚,没有异常,事务提交

2、 声明式事务管理 ,无需要修改原来代码,只需要配置,为目标代码添加事务管理 , AOP底层实现 — 企业推荐

为何使用Spring?
Spring的IOC和AOP两大核心功能可以大大降低应用系统的耦合性、简化开发流程。
Spring框架技术可在不同层次上起作用,比如IOC管理普通的POJO对象、AOP增强了系统服务和其它组件(事务、MVC、JDBC、ORM和远程调用等)。Spring的一大特点就是基于接口编程,它是非侵入式的服务。用户端绑定接口使用Java EE服务,而非直接绑定服务,而且应用也可以使用不同的服务(hibernate、MyBatis等)。我们可以根据自己的需要,使用Spring的一部分服务,而不必使用完整的Spring系列项目。

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐