Spring概述

Spring介绍

  1. Spring它是一个一站式的分层轻量级框架。

Spring体系结构

![](https://cdn.nlark.com/yuque/0/2019/png/300802/1553673961318-0d05597b-266c-4c22-87fb-5123d2c1c8fa-image1.png#align=left&display=inline&height=549&originHeight=440&originWidth=598&status=done&width=746)
  1. core container
    1. beans与core 它们提供spring框架最基本功能,包含ioc与di
    2. context 上下文对象,基于beans与cores
    3. spel它是spring提供的一个表达式语言
  2. Data access/integration
    1. 数据访问
    2. 集成
  3. Web
    1. Spring本身提供spring mvc
    2. 也可以与其它的web层进行集成
  4. AOP

AOP大部分情况下是使用动态代理来实现的。

  1. Test

使用spring可以方便的进行测试

/1rSpring框架优点

  • 方便解耦,简化开发

Spring就是一个大工厂,可以将所有对象创建和依赖关系维护,交给Spring管理

  • AOP编程的支持

Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能

  • 声明式事务的支持

只需要通过配置就可以完成对事务的管理,而无需手动编程

  • 方便程序的测试

Spring对Junit4支持,可以通过注解方便的测试Spring程序

  • 方便集成各种优秀框架

Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持

  • 降低JavaEE API的使用难度

Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低

IOC与DI

Spring的jar包下载

Spring的官网:spring.io
我们课程中讲解使用的是spring4.2.4
spring - 图1
在spring3.0.2版本后,不在提供依赖jar包
spring - 图2
docs 存在API和规范文档
libs 开发jar包
schema 开发过程中需要的xml的schema约束

spring开发环境搭建

在spring开发中,我们要根据不同的情况来导入不同的jar包,当前我们要讲解的是关于ioc与di
对于ioc与di讲解我们只需要使用spring的核心功能。

  1. beans相关
  2. core相关
  3. context相关
  4. spel相关

spring - 图3
我们使用spring框架也会使用到配置文件,我们需要在src下创建一个关于spring的配置文件,一般情况名称叫applicationContext.xml
问题:applicationContext.xml约束?
spring - 图4
它的路径:
spring-framework-4.2.4.RELEASE-dist\spring-framework-4.2.4.RELEASE\docs\spring-framework-reference\html
spring - 图5

IOC快速入门

Ioc的实现原理:xml配置文件+反射+工厂模式.通过这种操作,就可以将原来new出来的对象通过工厂模式产生
spring - 图6

Ioc它是什么,解决什么问题,它的原理是如何实现。
IOC  inversion of Controller 控制反转。
在程序中所说的IOC其实简单说,就是原来由我们自己实例化的对象交给spring容器来实始化。这时对象的实始化的权利就会反转。

程序运行时报错
spring - 图7
原因:当前环境需要一个commons-loggin的jar包

总结spring使用步骤:

  1. 在applicationContext.xml文件中配置bean

spring - 图8

  1. 创建一个AppliCationContext对象

ApplicationContext它是BeanFactory的一个子接口,我们在使用时使用的是AppliCationContext的实现类ClassPathXmlApplicationContext

spring - 图9
可以通过getBean(配置文件中id名称)来获取指定的对象。

DI

DI:dependency injection 依赖注入<br />        在spring框架负责创建Bean对象时,动态将依赖对象注入到Bean组件。<br />    ![](https://cdn.nlark.com/yuque/0/2019/png/300802/1553673961580-9c49faec-90ab-4829-aa7d-35a81cdfefb6-image11.png#align=left&display=inline&height=119&originHeight=79&originWidth=528&status=done&width=792)

spring - 图10
简单说,这时UserServiceImpl中的info属性值就是ITCAST

面试题:IOC和DI区别?
IOC 控制反转,是指对象实例化权利由spring容器来管理
DI 依赖注入在spring创建对象的过程中,对象所依赖的属性通过配置注入对象中。

Bean获取与实例化

ApplicationContext与BeanFactory关系

spring - 图11
ApplicationContext它是扩展BeanFactory接口。
BeanFactory采取延迟加载的方案只有真正在getBean时才会实例化Bean

在开发中我们一般使用的是ApplicationContext,真正使用的是其实现类,
FileSystemXmlAppliCationContext 根据文件路径获取
ClassPathXmlApplicationContext 根据类路径获取
AppliCationContext它会在配置文件加载时,就会初始化Bean,并且ApplicationContext它提供不同的应用层的Context实现。例如在web开发中可以使用WebApplicationContext.

Bean的实例化方式

无参数构造

对于这种方式,注意Bean类中必须提供无参数构造。(上面三种获取Bean1的方式都是无参构造的方式.)
spring - 图12

静态工厂方法

需要创建一个工厂类,在工厂类中提供一个static返回bean对象的方法就可以。
spring - 图13
spring - 图14
spring - 图15

实例工厂方法

需要创建一个工厂类,在工厂类中提供一个非static的创建bean对象的方法,在配置文件中需要将工厂配置,还需要配置bean
spring - 图16
spring - 图17

Bean的作用域

spring - 图18
在bean声明时它有一个scope属性,它是用于描述bean的作用域。
可取值有:

    • singleton:单例 代表在spring ioc容器中只有一个Bean实例 (默认的scope)
    • prototype多例 每一次从spring容器中获取时,都会返回一个新的实例
    • request 用在web开发中,将bean对象request.setAttribute()存储到request域中
    • session 用在web开发中,将bean对象session.setAttribute()存储到session域中

在开发中常用的值是singleton与prototype

Bean的生命周期

spring - 图19

  1. instantiate bean对象实例化
  2. populate properties 封装属性
  3. 如果Bean实现BeanNameAware执行setBeanName
  4. 如果Bean实现BeanFactoryAwar或ApplicationContextAwar设置工厂setBeanFactory或上下文对象setApplicationContext
  5. 如果存在类实现BeanPostProcessor(后处理Bean),执行postProcessBeforeInitialization
  6. 如果Bean实现InitializingBean执行afterPropertiesSet
  7. 调用自定义的init-method方法
  8. 如果存在类实现BeanPostProcessor(处理Bean),执行postProcessAfterInitialization
  9. 执行业务处理
  10. 如果Bean实现DisposableBean执行destroy
  11. 调用自定义的destroy-method

对于bean的生命周期方法:
第三步与第四步是让Bean了解spring容器。

第五步与第八步 可以针对指定的Bean进行功能增强,这时一般会使用动态代理.

第六步与第十步:通过实现指定的接口来完成init与destroy操作
但是在开发中一般不使用第6步与第10步,原因是我们可以使用第7步与第11步来完成。
第7步与第11步的初始化与销毁操作它无耦合,推荐使用的。但是必须在配置文件中指定初始化与销毁的方法
spring - 图20

总结:
对于bean的生命周期,我们需要关注的主要有两个方法:

  1. 增强bean的功能可以使用后处理Bean, BeanPostProcessor
  2. 如果需要初始化或销毁操作我们可以使用init-method destroy-method

注意:destroy-method只对scope=singleton有效果。

Bean的属性注入

在spring中bean的属性注入有两种

构造器注入

使用方式:
第一,在类中,不用为属性设置setter方法,但是需要生成该类带参的构造方法。
第二,在配置文件中配置该类的bean,并配置构造器,在配置构造器中用到了节点,该节点有四个属性:
· index是索引,指定注入的属性,从0开始;
· type是指该属性所对应的类型;
· ref 是指引用的依赖对象;
· value 当注入的不是依赖对象,而是基本数据类型时,就用value;
spring - 图21

Setter方法注入

spring - 图22
关于ref属性作用
spring - 图23
使用ref来引入另一个bean对象,完成bean之间注入

集合属性的注入

在spring中对于集合属性,可以使用专门的标签来完成注入例如:list set map properties等集合元素来完成集合属性注入.
spring - 图24

List属性注入

spring - 图25

Set属性注入

spring - 图26

Map属性注入

spring - 图27

Properties属性注入

Java.util.Properties是java.utilsMap的实现类,它的key与value都是String类型.
spring - 图28

名称空间p和c的使用

Spring2.0以后提供了xml命名空间。
spring - 图29
P名称空间
C名称空间
首先它们不是真正的名称空间,是虚拟的。它是嵌入到spring内核中的。
使用p名称空间可以解决我们setter注入时简化
使用c名称空间可以解决我们构造器注入时简化

使用setter注入spring - 图30
在applicationContext.xml文件中添加p名称空间简化setter注入
spring - 图31
spring - 图32

使用c名称空间来解决构造器注入
spring - 图33
在applicationContext.xml文件中添加c名称空间
spring - 图34

spring - 图35

注:如果c或p名称空间操作的属性后缀是”-ref”代表要引入另一个已经存在的bean,例如
spring - 图36

SpEl

spring expression language 是在spring3.0以后的版本提供
它类似于ognl或el表达式,它可以提供在程序运行时构造复杂表达式来完成对象属性存储及方法调用等。
Spel表达式的格式 #{表达式}

示例1:完成bean之间的注入
spring - 图37
示例2 支持属性调用及方法调用
spring - 图38

Spring注解开发

在spring中使用注解,我们必须在applicationContext.xml文件中添加一个标签
作用是让spring中常用的一些注解生效。
要使用contex名称空间,必须在applicationContext.xml文件中引入
spring - 图39

完成bean注册操作

@Component

spring - 图40
测试时报错
spring - 图41
原因:如果你使用的是spring3.x那么不会出现这个错误,如果使用的是spring4.x会报错,原因是缺少jar包。
spring - 图42
导入jar后运行还有错误
spring - 图43
我们在applicationContext.xml文件中使用了一个标签 ,它代表的是可以使用spring的注解,但是我们在类上添加的注解,spring不知道位置。
要解决这个问题,我们可以使用

spring - 图44

在spring2.5后为@Component添加了三个衍生的注解
@Repository 用于DAO层
@Service 用于service层
@Controller 用于表现层
对于我们的bean所处在的位置可以选择上述三个注解来应用,如果你的bean不明确位置,就可以使用@Component.

属性依赖注入

  1. 简单的属性注入

spring - 图45

  1. 复杂的属性注入

spring - 图46

注意:如果要扫描多个包下的注解可以写成以下:
spring - 图47

spring - 图48

注意:@Value @Autowired它们可以修饰属性,也可以修饰setter方法,如果写在属性上,就不需要提供setter方法。

@Autowired它默认是根据类型进行注入

spring - 图49
如果单独是有这个属性,虽然指定了位置但是不知道类型,所以会报错
@Qualifier(“ci1”)

如果与@Qualifier一起使用,就可以根据名称来进行注入。
我们也可以使用下面的方式来根据名称进行属性注入
spring - 图50
说一下@Resource的装配顺序:
(1)、@Resource后面没有任何内容,默认通过name属性去匹配bean,找不到再按type去匹配
(2)、指定了name或者type则根据指定的类型去匹配bean
(3)、指定了name和type则根据指定的name和type去匹配bean,任何一个不匹配都将报错
然后,区分一下@Autowired和@Resource两个注解的区别:
(1)、@Autowired默认按照byType方式进行bean匹配,@Resource默认按照byName方式进行bean匹配
(2)、@Autowired是Spring的注解,@Resource是J2EE的注解,这个看一下导入注解的时候这两个注解的包名就一清二楚了
Spring属于第三方的,J2EE是Java自己的东西,因此,建议使用@Resource注解,以减少代码和Spring之间的耦合。

其它注解

@Scope它以描述bean的作用域。
spring - 图51

spring - 图52
spring - 图53
它相当于init-method=”myInit
spring - 图54
它相当于是destroy-method=”myDestroy”
注意:对于销毁的方法它只对bean的scope=singleton有效。

Spring常用注解汇总
本文汇总了Spring的常用注解,以方便大家查询和使用,具体如下:
使用注解之前要开启自动扫描功能,其中base-package为需要扫描的包(含子包)。

@Configuration把一个类作为一个IoC容器,它的某个方法头上如果注册了@Bean,就会作为这个Spring容器中的Bean。
@Scope注解 作用域
@Lazy(true) 表示延迟初始化
@Service用于标注业务层组件、
@Controller用于标注控制层组件(如struts中的action)
@Repository用于标注数据访问组件,即DAO组件。
@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
@Scope用于指定scope作用域的(用在类上)
@PostConstruct用于指定初始化方法(用在方法上)
@PreDestory用于指定销毁方法(用在方法上)
@DependsOn:定义Bean初始化及销毁时的顺序
@Primary:自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常
@Autowired 默认按类型装配,如果我们想使用按名称装配,可以结合@Qualifier注解一起使用。如下:
@Autowired @Qualifier(“personDaoBean”) 存在多个实例配合使用
@Resource默认按名称装配,当找不到与名称匹配的bean才会按类型装配。
@PostConstruct 初始化注解
@PreDestroy 摧毁注解 默认 单例 启动就加载
@Async异步方法调用

Spring整合junit4测试

Spring整合junit4可以方便我们的测试。

  1. 需要导入一个spring-test.jar包

spring - 图55

  1. 可以在测试类上如下操作

spring - 图56

Spring在web开发中的应用

1.,在web项目中要使用spring需要导入一个jar包
spring - 图57

1.5创建一个servlet(这是没整合.整合过的话创建一个Action)

2.在web.xml文件中配置Listener
spring - 图58
这个ContextLoaderListener它实现了ServletContextListener
在这个listener中,当服务器启动时,将ApplicationContext对象,其实是它的一个实现类
WebApplicationContext,对象存入到了ServletContext中。

spring - 图59

3.我们还需要在web.xml文件中配置applicationContext.xml文件的位置
默认情况下会在WEB-INF目录 下查找applicationContext.xmls
如果applicationContext.xml文件不是在默认位置,我们可以在web.xml文件中配置
spring - 图60
Classpath:applicationContext.xml 它代表的是在当前工程的类路径下(可以理解成是在src)下来查找applicationContext.xml文件。
contextConfigLocation它是在listener中声明的一个常量,描述的就是spring配置文件的位置。

Spring AOP

AOP概述

在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
AOP是一个概念,并没有设定具体语言的实现,它能克服那些只有单继承特性语言的缺点,spring2.0之后整合AspectJ第三方AOP技术。
AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法所以它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。

主要功能

日志记录,性能统计,安全控制,事务处理,异常处理等等

主要意图

将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。

AOP与OOP区别
OOP(面向对象编程)针对业务处理过程的实体及其属性和行为进行抽象封装,以获得更加清晰高效的逻辑单元划分。
而AOP则是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。这两种设计思想在目标上有着本质的差异。
换而言之,OOD/OOP面向名词领域,AOP面向动词领域。

AOP相关术语

目标对象target

指的是需要被增强的对象,由于spring aop是通过代理模式实现,从而这个对象永远是被代理对象。

连接点(join point)

所谓连接点是指那些被拦截到的点,在spring中这些点指的是方法,因为spring只支持方法类型的连接点

切入点(pointcut)

表示一组 joint point,这些 joint point 或是通过逻辑关系组合起来,或是通过通配、正则表达式等方式集中起来,它定义了相应的 Advice 将要发生的地方
简单说切入点是指我们要对哪些连接点进行拦截的定义

通知(advice)

所谓通知是指拦截到连接点之后所要做的事情就是通知,通知分为前置通知,后置通知,异常通知,最终通知,环绕通知
Advice 定义了在 pointcut 里面定义的程序点具体要做的操作

引介introduction

引介是一种特殊的通知,在不修改类代码的前提下,introduction可以在运行期为类动态地添加一些方法或属性

切面aspect

是切入点和通知的结合

织入weaving

织入是一个过程,是将切面应用到目标对象从而创建出AOP代理对象的过程,织入可以在编译期,类装载期,运行期进行。
Spring采用动态织入,而aspectj采用静态织入

代理Proxy

一个类被AOP织入增强后,就产生一个结果代理类

AOP底层实现

AOP分为静态AOP和动态AOP。静态AOP是指AspectJ实现的AOP,他是将切面代码直接编译到Java类文件中。动态AOP是指将切面代码进行动态织入实现的AOP。Spring的AOP为动态AOP,实现的技术为: JDK提供的动态代理技术 和 CGLIB(动态字节码增强技术)

JDK动态代理

在运行 ,在JVM内部动态生成class字节码对象(Class对象)
Jdk动态代理只针对于接口操作
spring - 图61
spring - 图62
第一个参数:目标类的类加载器对象
第二个参数:目标类的实现接口的Class[]
第三个参数:InvocationHandler它是一个接口,它的作用是是代理实例的调用处理程序 实现的接口,接口中定义了一个方法
spring - 图63

目标Target
spring - 图64
spring - 图65
代理工厂
spring - 图66

CGLIB动态代理

CGLIB(Code Generation Library)是一个开源项目
是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类
如果你要单独使用CGLIB,那么需要导入cglib的jar包还需要一个asm相关jar包,但是spring框架的spring-core.jar包中已经集成了cglib与asm
spring - 图67
注意:jdk的动态代理只可以为接口去完成操作,而cglib它可以为没有实现接口的类去做代理,也可以为实现接口的类去做代理。

Cglib动态代理
spring - 图68
setCallback传递的参数是Callback类型,我们使用的是MethodInterceptor
spring - 图69

注意:cglib它可以为没有实现接口的类做代理,也可以为接口类做代理.

问题:spring采用的是哪一种动态机制:
如果目标对象,有接口,优先使用jdk动态代理
如果目标对象,无接口,使用cglib动态代理。

Spring AOP编程

Spring的传统aop编程

讲解的目的是为了更好的理解aop。
在传统的spring aop开发中它支持增强(advice)有五种:

  1. 前置通知 目标方法执行前增强 org.springframework.aop.MethodBeforeAdvice
  2. 后置通知 目标方法执行后增强 org.springframework.aop.AfterReturningAdvice
  3. 环绕通知 目标方法执行前后进行增强 org.aopalliance.intercept.MethodInterceptor
  4. 异常抛出通知 目标方法抛出异常后的增强 org.springframework.aop.ThrowsAdvice
  5. 引介通知 在目标类中添加一些新的方法或属性(不讲解)

org.springframework.aop.IntroductionInterceptor

经典的基于代理的AOP开发(了解)

基本的jar包

  1. bean
  2. core
  3. context
  4. expression
  5. aop
  6. 需要aop联盟的依赖jar包

spring - 图70
第一步:编写目标(target)
spring - 图71
第二步增强(advice)
spring - 图72

第三步在applicationContext.xml文件中配置
spring - 图73
spring - 图74
第四 测试
spring - 图75
spring - 图76

基于aspectJ切点传统开发

第一步:在spring的配置文件中定义目标与通知
spring - 图77
第二步:使用标签来完成切面与切点声明
spring - 图78
注意1:需要在xml配置文件中导入aop声明
注意2:因为我们使用aspectj的切面声明方式 需要在导入aspectj的jar包
spring - 图79

传统spring aop开发总结

第一步:编写目标对象(target)
spring - 图80

第二步:编写通知(advice)
传统的aop开发中,通知是需要实现指定接口。
spring - 图81

第三步 在配置文件中配置切面(切面=切点+通知)
来声明要对aop进行配置
它是用于声明切点(简单说就是对哪些方法进行拦截)
定义传统的aop的切面,传统的aop切面它只能包含一个切点与一个增强
定义aspectj框架的切面.,它可以包含多个切点与多个通知
spring - 图82

关于切点表达式写法

spring - 图83
spring - 图84
这个语法源于aspectJ的语法,spring中aop开发,对aspectj不是完全支持,只支持部分语法。
spring - 图85
spring - 图86
在开发中使用的比较多的是execution语法.
关于execution语法常用:

  1. execution(public ()) 所有的public的方法
  2. execution( cn.itheima.aop.(..)) 所有的aop包下的所有类的方法(不包含子包)
  3. execution( cn.itheima.aop..(..)) 所有的aop包及其子包下的所有类的方法
  4. execution( cn.itheima.aop.IOrderService.(..)) IOrderService接口中定义的所有方法
  5. execution( cn.itheima.aop.IOrderService+.(..)) 匹配实现特定接口所有类的方法
  6. execution( save(..)) 区配所有的以save开头的方法

    Spring整合aspectj框架实现的aop

    在现在的开发中使用这种方案比较多.
    在spring2.0以后它支持jdk1.5注解,而整合aspectj后可以使用aspectj语法,可以简化开发。

Aspect:切面 =切点+通知(多个切点与多个通知的组合)
AspectJ 它是一个第三方框架,spring从2.0后可以使用aspectJ框架的部分语法.

AspectJ框架它定义的通知类型有6种

  1. 前置通知Before 相当于BeforeAdvice
  2. 后置通知AfterReturning 相当于AfterReturningAdvice
  3. 环绕通知 Around 相当于MethodInterceptor
  4. 抛出通知AfterThrowing 相当于ThrowAdvice
  5. 引介通知DeclareParents 相当于IntroductionInterceptor
  6. 最终通知After 不管是否异常,该通知都会执行

相比spring 的传统AOP Advice多了一个最终通知
spring - 图87

基于xml配置方案

第一步:创建目标(target)

spring - 图88

第二步:创建通知(增强 advice)

注意:在aspectj中它的增强可以不实现任何接口,只需要定义出增强功能(方法)
spring - 图89

第三步:在spring的xml 配置文件中来配置

下的是aspectJ框架用来声明切面的。
spring - 图90
前置通知
spring - 图91
后置通知
spring - 图92
环绕通知
spring - 图93
spring - 图94
异常抛出
spring - 图95
注意:目标行为只有抛出了异常后才会执行这个增强方法

最终通知
spring - 图96
无论是否有异常,最终通知都会执行.

关于通知上的参数
  1. 在前置通知上可以添加JoinPoint参数

通过它可以获取目标相关的信息
spring - 图97
作用:使用前置通知可以完成日志记录,权限控制

  1. 在后置通知上添加的参数

spring - 图98
作用:第二个参数val它可以获取目标方法的返回值
注意:需要在配置文件中配置
spring - 图99

  1. 环绕通知上的参数

spring - 图100
作用:它是我们开发中应用最多的,可以完成日志操作,权限操作,性能监控,事务管理

  1. 抛出异常通知上的参数

spring - 图101
第二个参数Throwable它是用于接收抛出的异常
注意:需要在配置文件中声明
spring - 图102

  1. 最终通知上的参数

spring - 图103
作用:可以使用最终通知完成资源释放

关于代理方式选择

在spring的aop开发中,它使用的是代理方案,代理实现有两种:

  1. jdk的proxy
  2. cglib

spring框架默认情况下,会对有接口的类使用jdk的proxy代理。没有接口的类使用cglib代理
spring - 图104
Proxy-target-class的值默认是false,它代表有接口使用jdk的proxy代理,没有接口使用cglib代理
问题:如果现在对目标要使用cglib代理(不考虑是否有接口)?(不管什么情况都使用cglib代理)
只需要将proxy-target-class设置为true.

基于annotation方案(注解方案)

第一步:编写目标

spring - 图105
在spring的配置文件中配置扫描注解
spring - 图106

第二步:编写增强(advice)

spring - 图107
使用@Aspect来声明切面(里面有切点和通知)
使用@Before来声明前置通知
注意:必须在spring的配置文件中开启aspectJ注解自动代理功能。
spring - 图108

第三步:测试

spring - 图109

其它通知类型及参数

后置通知
spring - 图110

环绕通知
spring - 图111

异常抛出通知
spring - 图112

最终通知
spring - 图113

使用@Pointcut注解定义切点

在每一个通知中定义切点,工作量大,不方便维护,我们可以使用@Pointcut来声明切点
spring - 图114

切点允许逻辑运算例如mypointcut()||mypointcut1

关于代理方式选择

spring - 图115
Proxy-target-class默认值是false,代表的是如果目标是有接口的使用jdk,proxy代理,如果没有接口使用cglib.
如果将proxy-target-class=true,不管目标是否有接口,都会使用cglib进行代理。

Spring jdbc Template

Spring提供了一个jdbc模板,它类似于dbutils工具。
spring - 图116

问题:如何使用spring jdbc template?
第一:要导入相关的jar包
spring - 图117
在这个基础上我们还需要导入
spring - 图118
spring - 图119
还需要导入相关的数据库驱动jar包。
第二:spring jdbc template快速入门

快速入门

第一步:导入相关jar包,创建了一个JdbcTemplateTest1测试类
spring - 图120
第二步:创建库与表
CREATE DATABASE springtest;

USE springtest;

CREATE TABLE t_user(

id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20),
age INT,
sex VARCHAR(20)
)

INSERT INTO t_user VALUES(NULL,’tom’,20,’男’);
INSERT INTO t_user VALUES(NULL,’fox’,30,’男’);
INSERT INTO t_user VALUES(NULL,’tony’,40,’男’);

SELECT * FROM t_user;

第三步:编码
spring - 图121

配置spring内置的连接池DriverManagerDataSource

spring - 图122
spring - 图123

spring - 图124

C3P0开源连接池配置

  1. 导入c3p0相关的jar包

spring - 图125

  1. 创建一个ComboPoolDataSource对象,设置相关的属性

spring - 图126

引入外部属性文件

Spring支持将经常修改属性,在properties文件中声明,在xml配置文件中引入外部的properties文件的信息。
spring - 图127
在applicationContext.xml文件中引入
spring - 图128
在自己配置中需要从properties文件中引入的信息可以使用${name}方式来获取
spring - 图129

JdbcTemplate CRUD

执行insert update delete操作

spring - 图130
只需要使用JdbcTemplate的update方法就可以执行insert update delete操作
spring - 图131
spring - 图132
spring - 图133

执行select操作

简单数据返回

spring - 图134
spring - 图135

复杂数据返回

spring - 图136
注意:如果只返回一个domain对象,可以使用queryForObject方法,如果返回的是List<?>对象,可以使用query方法,但是都需要使用RowMapper来对ResultSet进行处理。
spring - 图137
spring - 图138
spring - 图139
RowMapper它有一个实现类叫BeanPropertyRowMapper
如果使用BeanPropertyRowmapper,实体类必须提供一个无参数的public构造方法,类中的bean属性名称与表中的列要对应
注意:这个类是在spring2.5后提供。
spring - 图140

Spring 事务管理

案例—转账操作

创建一个关于帐户表

CREATE TABLE account(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20),
money DOUBLE
)

INSERT INTO account VALUES(NULL,’tom’,1000);
INSERT INTO account VALUES(NULL,’fox’,1000);

创建service与dao

对于数据的操作使用spring jdbc template
spring - 图141

spring - 图142

关于service与dao的配置

spring - 图143
我们让dao去extends JdbcDaoSupport类,这个类中它创建了JdbcTempate,前提是我们需要注入一个dataSource.
spring - 图144
spring - 图145
在dao中在获取JdbcTemplate可以使用父类提供的getJdbcTemplate方法来获取。
spring - 图146

转账操作的问题

spring - 图147
如果在转账操作过程中出现问题,那么转账会出现问题,结果如下
spring - 图148
也就是我们程序需要事务控制。

Spring事务管理机制

Spring事务管理的四个优点:

  1. 提供一致的对于不同的事务管理的API
  2. 支持声明式事务管理(重点)
  3. 编程事务管理(在开发中应用比较少)
  4. 优秀的整合与Spring的数据访问

我们重点讲解spring的事务管理的相关的API,还有声明式事务管理
Spring事务管理主要提供了三个接口来完成

  1. org.springframework.transaction.PlatformTransactionManager

这是一个事务管理器,可以来选择相关的平台(jdbc hibernate jpa…)

  1. TransactionDefinition

它定义事务的一些相关信息 例如 隔离 传播 超时 只读

  1. TransactionStatus

它主要描述事务具体的运行状态

PlatformTransactionManager

平台事务管理器
在不同的持久化层解决技术它的事务代码不一样。
JDBC开发
Connection con=……;
con.setAutoCommit(false);//开启事务
con.rollback();
con.commit();
Hibernate开发
Session session=….;
Transaction t=session.beginTransaction();
t.commit();
t.rollback();
PlatformTransactionManager接口API
spring - 图149
spring - 图150
DataSourceTransactionManager 主要针对于JdbcTemplate开发 MyBatis开发
HibernateTransactionManasger主要针对于Hibernate开发
JpaTransactionManager 主要针对于JPA开发。

TransactionDefinition

它描述的是事务的定义信息。
spring - 图151

在TransactionDefinition中定义了大量的常量

隔离

以下是关于隔离性相关信息
spring - 图152
事务的四个特性 ACID 原子性 一致性 隔离性 持久性。
不考虑事务隔离性有什么问题?
脏读,不可重复读 虚读。

  • ISOLATION_DEFUALT 它使用后端数据库的默认隔离级别(spring中的默认选项)
  • ISOLATION_READ_UNCOMMITTED 不能解决问题,会发生脏读 不可重复读 虚读
  • ISOLATION_READ_COMMITTED 可以解决脏读 会产生不可重复读与虚读。
  • ISOLATION_REPEATABLE_READ 可以解决脏读,不可重复读 解决不了虚读
  • ISOLATION_SERIALIZABLE 串行化,可以解决所有问题
  • 对于不现的数据库,它的底层默认事务隔离级别不一样。

Oracle数据库它默认的是read_committed
Mysql数据库它默认的是repeatable_read.

超时

spring - 图153
默认值是-1 它使用的是数据库默认的超时时间。

只读

它的值有两个true/false,如果选择true一般是在select操作时<br />    

传播

它解决的是两个被事务管理的方法互相调用问题。它与数据库没关系,是程序内部维护的问题。
以下定义了事务的传播行为
spring - 图154
以上操作中最常用的三种:
PROPAGATION_REQUIRED 默认值 两个操作处于同一个事务,如果之前没有事务,新建一个事务
PROPAGATION_REQUIRES_NEW
两个操作处于不同的事务
PROPAGATION_NESTED
它是一种嵌套事务,它是使用SavePoint来实现的。事务回滚时可以回滚到指定的savepoint,注意:它只对DataSourceTransactionManager有作用

以下了解
PROPAGATION_SUPPORTS 支持当前事务,如果不存在,就不使用事务
PROPAGATION_MANDATORY 支持当前事务,如果不存在,抛出异常
PROPAGATION_NOT_SUPPORTED 以非事务运行,如果有事务存在,挂起当前事务
PROPAGATION_NEVER 以非事务运行,如果有事务存在,抛出异常

TransactionStatus

它定义了事务状态信息,在事务运行过程中,得到某个时间点的状态
spring - 图155

声明式事务管理

事务管理方式

  1. 编码方案 不建议使用,它具有侵入性。在原有的业务代码基础上去添加事务管理代码
  2. 声明式事务控制,基于AOP对目标进行代理,添加around环绕通知。

这种方案,它不具有侵入性,不需要修改原来的业务代码

基于xml配置声明式事务管理方案

第一步:在application Context.xml文件中添加aop与tx的名称空间
spring - 图156
第二步:在applicationContext.xml文件中配置
Spring提供的advice是传统的spring advice

  1. 声明事务管理器

spring - 图157

  1. 配置通知

Spring为我们提供了一个TransactionInterceptor来完成增强
spring - 图158
对于这个增强,我们可以使用spring为我们提供的一个标签来完成操作 spring - 图159

  1. 配置切面

因为使用的是传统的spring的advice,需要使用
spring - 图160

基于annotation声明式事务管理方案

可以使用@Transaction来在类或方法上添加声明式事务管理
注意:需要在applicationContext.xml文件中使用
spring - 图161
相当于开启注解事务控制
spring - 图162

问题:关于xml方式与annotation方式的优缺点?
从简单上来说,使用注解更方便。
使用配置的方案,可以对事务配置进行集中维护。
spring - 图163

SSH框架整合

SSh=struts2+spring+hibernate
struts2 2.3.24
spring 4.2.4
hibernate 5.0.7

关于xml配置文件的整合方式

SSH整合jar包

Struts2框架需要jar包

spring - 图164
Asm 是关于字节码操作
Commons-fileupload 关于文件上传
Commons-io 关于io流操作工具
Commons-lang 也是一个工具,包含了关于数据与字符串操作
Freemaker 标签库模板文件
Javassist 它也是关于字节码操作,动态代理可以使用它实现(类似于cglib)
Log4j关于日志
Ognl 关于ognl表达式
Struts2-core xwork-cor struts2框架底层是使用xwork

spring - 图165
Struts2与spring整合还需要这个包

如果需要使用struts2提供的json处理
spring - 图166

注意:如果使用注解方案,我们还需要导入一个jar包
spring - 图167

Hibernate框架需要的jar包

spring - 图168
Antlr 语法解析包
Dom4j 解析xml
Geronimo-jta apache geronimo它是一个开源javaEE服务器 Geronimo-jta是这个开源项目提供jar包,在hibernate中是关于jta事务相关
Hibernate-commoins-annotations
这个包是我们在hibernate下来使用jpa相关的注解,这样它不依赖于hibernate
Hibernate-core 开发hibernate必须
Hibernate-jpa 它是关于hibernate对jpa的支持
Jandex 用于索引annotation
Javassist 关于字节码操作(注意:strtus2中也引入这个jar包了)
Jboss-logging 它是关于jboss统一日志处理

如果使用关于jpa相关操作需要导入jpa依赖jar包
spring - 图169

C3p0连接池
spring - 图170
还需要数据库相关的驱动jar包
spring - 图171

还需要静态日志处理
spring - 图172

Spring框架需要的jar包

Spring最基本jar包:
spring - 图173
spring - 图174
AOP开发:
spring - 图175
spring - 图176
Spring jdbc:
spring - 图177
Spring 事务管理需要tx
Spring整合hibernate :
spring - 图178
Spring整合web开发:
spring - 图179
如果使用到junit测试:
spring - 图180

还需要commons-loggin jar包:
spring - 图181

创建工程完成整合前期准备

需要的配置文件:
Strtsu2框架 src/strtus.xml
Hibernate框架 src/hibernate.cfg.xml 在domain有 Xxx.hbm.xml
Spring框架 src/applicationContext.xml
关于日志 log4j.properties
关于数据库连接 db.properties

Spring整合hibernate

基本原理:就是由spring来管理hibernate的SessionFactory 

方式一:零障碍整合(了解)

我们只需要使用spring中提供的一个LocalSessionFacotry来加载Hibernate的配置文件。<br />    ![](https://cdn.nlark.com/yuque/0/2019/png/300802/1553673966078-c51493fb-eed7-467e-9aef-4b91edc701ea-image186.png#align=left&display=inline&height=89&originHeight=84&originWidth=780&status=done&width=831)

Ssh-xml工程加载到服务器后,如果可以自动创建表,就代表spring整合hibernate ok.
注意:我们必须配置spring的ContextLoaderListener
spring - 图182

方式二(spring管理hibernate配置)

不在需要hibernate.cfg.xml文件,所有关于hibernate.cfg.xml文件中的配置都在spring的配置文件中来配置。

首先要配置数据源
spring - 图183
接下来引入properties文件
spring - 图184
spring - 图185
创建LocalSessionFactoryBean来完成spring管理hibernate中的SessionFactory
spring - 图186
上述的props可以简化成下面方案
spring - 图187

加载hbm.xml配置文件
spring - 图188
mappingResources它类似于我们之前
mappingLocations它加载时是根据类路径加载 classpath:路径
spring - 图189
mappingJarLocations它会加载jar文件中的hbm.xml文件
mappingDirectoryLocations 它加载的目录

spring整合hibernate后的DAO

spring整合hiberante后,我们的dao只需要继承HibernateDaoSupport类
在HibernateDaoSupport中只需要注入SessionFactory就可以获得到HibernateTemplate,它是对hibernate操作的一个简单封装,可以让我们方便使用原来hibernate的操作.
spring - 图190

spring - 图191

编写service及测试

spring - 图192

测试
spring - 图193
事务管理
spring - 图194

HibernateTemplate API介绍

保存操作 session.save()
spring - 图195
修改操作 session.update()
spring - 图196
删除操作 session.delete()
spring - 图197
类似于session.saveOrUpdate()根据持久化对象的状态来判断执行save或update
spring - 图198
获取操作 get() load()
spring - 图199
spring - 图200

Find操作 类似于session.createQuery().setParameter().list()
spring - 图201
类似于hibernate中的QBC查询,完全的面向对象方案
spring - 图202
spring - 图203
spring - 图204
下面这个可以执行命名查询
可以在User.hbm.xml文件中定义hql或sql
spring - 图205

spring - 图206
spring - 图207

Spring整合struts2框架

前期准备

创建一个addUser.jsp页面

spring - 图208

创建UserAction类

spring - 图209

Struts.xml文件中配置

spring - 图210

Spring整合struts2原理分析

  1. spring整合struts2框架必须导入一个jar包

struts2-spring-plugin.jar

  1. struts2框架配置文件加载顺序
  2. default.properties
  3. struts-default.xml
  4. strtus-plugin.xml
  5. 在struts2框架中所有的action interceptor result全是bean,在struts2框架中默认是使用strtus2自己bean初化操作.

spring - 图211
spring - 图212

  1. 当我们在工程中导入struts2-spring-plugin.jar文件

就会加载这个包下的strtus-plugin.xml
spring - 图213
这时bean的创建由spring来管理。

  1. 这时在创建Action时它执行的代码

spring - 图214
上述代码,在执行时,首先会从spring容器中来获取,如果获取不到,会buildBean

通过上述分析,spring整合struts2框架它的方式有两种

  1. spring管理action(简单说就是在applicationContext.xml文件中来声明action)
  2. action自动装配service

spring整合struts2框架方式一(掌握)

这种方案是基于spring管理action

  1. 在applicationContext.xml文件中配置

spring - 图215

  1. 在action类中

spring - 图216

  1. 在struts.xml文件

spring - 图217
Class的值就是bean的id值

注意:必须在web.xml文件中配置struts2框架的Filter
spring - 图218

Spring整合struts2框架方式二(action中自动注入service)

Struts.xml文件中
spring - 图219
Class还是类的全名

这时就会将action类中需要的注入servcie自动注入
spring - 图220
在default.properties中有一段配置
spring - 图221
这时就会根据名称进行autoWires

我们可以修改注入的方式
spring - 图222
我们在struts.xml文件中修改了注入的方式,根据type进行注入

Spring整合struts2框架总结

  1. 如果在struts.xml文件中如果写的是全类名,我们使用action自动装配service方案
  2. 如果在struts.xml文件中这时,在applicationContext.xml文件中要配置
  3. 以上操作的前提是必须导入struts2-spring-plugin.xml文件

在这个文件中它改变struts2的bean工厂

  1. 默认情况下如果采用action自动装配service方案,这时每一次请求都会新创建一个action,并且service的装配类型是by name
  2. 如果我们采用的是spring管理action这种方案我们必须在声明中添加scope=prototype”,原因是struts2框架的action每一次请求都应该是一个新的action

    关于annotation整合方式

    Jar包导入

    在原来的xml基础上在多导入一个jar包
    spring - 图223
    只有导入这个jar包后,我们才能使用struts2框架的注解 @Namespace @Action

配置文件

Web.xml文件中要配置
spring - 图224
Spring的配置文件 applicationContext.xml
Struts2的配置文件 struts.xml

使用JPA注解来定义PO类

@Entity 定义实体类
@Table 定义表
@Id 主键
@GeneratedValue 生成主键策略
@Column 定义列
spring - 图225

Spring整合hibernate

spring - 图226

Dao编写

如何在dao中得到HibernateTemplate对象,原来是在applicationContext.xml文件中通过配置方案注入了一个SessionFactory对象,UserDao的父类HibernateDaoSupport,会帮助我们根据SessionFactory来得到HibernateTemplate

spring - 图227

Service编写

spring - 图228

spring - 图229

问题:service需要事务管理,怎样处理?
spring - 图230

spring - 图231

spring - 图232

Action编写

spring - 图233
使用@Controller @Scope
以上注解的作用是由spring管理action,它是一个多例的。

问题:如何完成struts2框架的流程?
spring - 图234

基于annotation的ssh整合总结

在ssh的annotation整合时,必须要多导入的一个包
spring - 图235
对于dao,service,action我们使用
@Repository @Service @Controller来完成bean注册。
在dao中我们使用以下方案将SessionFactory注入,在dao中就可以使用HibernateTemplate
spring - 图236
在service及action中使用@Autowire来注入dao及service
spring - 图237
spring - 图238
一定要在applicationContext.xml文件中开启注解扫描
spring - 图239
对于PO类我们使用JPA的注解 @Entiry @Table @Id @GeneratedValue @Column
要在applicationContext.xml文件中配置SessionFactory时来确定扫描包
spring - 图240

对于Struts2框架,我们需要@Namespace @Action @ParentPakcage @Result来定义struts2流程
spring - 图241
要求action类必须是在action actions struts struts2这样的包中才会扫描struts2相关注解

SSH整合延迟加载问题解决

  1. 修改UserDao中的findById

spring - 图242

  1. 添加一个user.jsp页面

spring - 图243

  1. 在UserAction中处理user_findById请求

spring - 图244

以上程序在执行后,报错
spring - 图245

解决no session问题:

  1. 不使用延迟加载
  2. 手动将延迟加载初始化 Hibernate.initialize(延迟对象)
  3. 使用spring提供的一个OpenSessionInViewFilter来解决

spring - 图246
基本的原理就是将session的关闭操作不在service层完成,而是在web层才关闭session.
注意:openSessionInViewFilter一定要在Struts2 Filter前配置.