Spring介绍
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)
- core container
- beans与core 它们提供spring框架最基本功能,包含ioc与di
- context 上下文对象,基于beans与cores
- spel它是spring提供的一个表达式语言
- Data access/integration
- 数据访问
- 集成
- Web
- Spring本身提供spring mvc
- 也可以与其它的web层进行集成
- AOP
AOP大部分情况下是使用动态代理来实现的。
- 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
在spring3.0.2版本后,不在提供依赖jar包
docs 存在API和规范文档
libs 开发jar包
schema 开发过程中需要的xml的schema约束
spring开发环境搭建
在spring开发中,我们要根据不同的情况来导入不同的jar包,当前我们要讲解的是关于ioc与di
对于ioc与di讲解我们只需要使用spring的核心功能。
- beans相关
- core相关
- context相关
- spel相关
我们使用spring框架也会使用到配置文件,我们需要在src下创建一个关于spring的配置文件,一般情况名称叫applicationContext.xml
问题:applicationContext.xml约束?
它的路径:
spring-framework-4.2.4.RELEASE-dist\spring-framework-4.2.4.RELEASE\docs\spring-framework-reference\html
IOC快速入门
Ioc的实现原理:xml配置文件+反射+工厂模式.通过这种操作,就可以将原来new出来的对象通过工厂模式产生
Ioc它是什么,解决什么问题,它的原理是如何实现。
IOC inversion of Controller 控制反转。
在程序中所说的IOC其实简单说,就是原来由我们自己实例化的对象交给spring容器来实始化。这时对象的实始化的权利就会反转。
程序运行时报错
原因:当前环境需要一个commons-loggin的jar包
总结spring使用步骤:
- 在applicationContext.xml文件中配置bean
- 创建一个AppliCationContext对象
ApplicationContext它是BeanFactory的一个子接口,我们在使用时使用的是AppliCationContext的实现类ClassPathXmlApplicationContext
可以通过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)
简单说,这时UserServiceImpl中的info属性值就是ITCAST
面试题:IOC和DI区别?
IOC 控制反转,是指对象实例化权利由spring容器来管理
DI 依赖注入在spring创建对象的过程中,对象所依赖的属性通过配置注入对象中。
Bean获取与实例化
ApplicationContext与BeanFactory关系
ApplicationContext它是扩展BeanFactory接口。
BeanFactory它采取延迟加载的方案,只有真正在getBean时才会实例化Bean
在开发中我们一般使用的是ApplicationContext,真正使用的是其实现类,
FileSystemXmlAppliCationContext 根据文件路径获取
ClassPathXmlApplicationContext 根据类路径获取
AppliCationContext它会在配置文件加载时,就会初始化Bean,并且ApplicationContext它提供不同的应用层的Context实现。例如在web开发中可以使用WebApplicationContext.
Bean的实例化方式
无参数构造
对于这种方式,注意Bean类中必须提供无参数构造。(上面三种获取Bean1的方式都是无参构造的方式.)
静态工厂方法
需要创建一个工厂类,在工厂类中提供一个static返回bean对象的方法就可以。
实例工厂方法
需要创建一个工厂类,在工厂类中提供一个非static的创建bean对象的方法,在配置文件中需要将工厂配置,还需要配置bean
Bean的作用域
在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的生命周期
- instantiate bean对象实例化
- populate properties 封装属性
- 如果Bean实现BeanNameAware执行setBeanName
- 如果Bean实现BeanFactoryAwar或ApplicationContextAwar设置工厂setBeanFactory或上下文对象setApplicationContext
- 如果存在类实现BeanPostProcessor(后处理Bean),执行postProcessBeforeInitialization
- 如果Bean实现InitializingBean执行afterPropertiesSet
- 调用自定义的init-method方法
- 如果存在类实现BeanPostProcessor(处理Bean),执行postProcessAfterInitialization
- 执行业务处理
- 如果Bean实现DisposableBean执行destroy
- 调用自定义的destroy-method
对于bean的生命周期方法:
第三步与第四步是让Bean了解spring容器。
第五步与第八步 可以针对指定的Bean进行功能增强,这时一般会使用动态代理.
第六步与第十步:通过实现指定的接口来完成init与destroy操作
但是在开发中一般不使用第6步与第10步,原因是我们可以使用第7步与第11步来完成。
第7步与第11步的初始化与销毁操作它无耦合,推荐使用的。但是必须在配置文件中指定初始化与销毁的方法
总结:
对于bean的生命周期,我们需要关注的主要有两个方法:
- 增强bean的功能可以使用后处理Bean, BeanPostProcessor
- 如果需要初始化或销毁操作我们可以使用init-method destroy-method
注意:destroy-method只对scope=singleton有效果。
Bean的属性注入
构造器注入
使用方式:
第一,在类中,不用为属性设置setter方法,但是需要生成该类带参的构造方法。
第二,在配置文件中配置该类的bean,并配置构造器,在配置构造器中用到了
· index是索引,指定注入的属性,从0开始;
· type是指该属性所对应的类型;
· ref 是指引用的依赖对象;
· value 当注入的不是依赖对象,而是基本数据类型时,就用value;
Setter方法注入
关于ref属性作用
使用ref来引入另一个bean对象,完成bean之间注入
集合属性的注入
在spring中对于集合属性,可以使用专门的标签来完成注入例如:list set map properties等集合元素来完成集合属性注入.
List属性注入
Set属性注入
Map属性注入
Properties属性注入
Java.util.Properties是java.utilsMap的实现类,它的key与value都是String类型.
名称空间p和c的使用
Spring2.0以后提供了xml命名空间。
P名称空间
C名称空间
首先它们不是真正的名称空间,是虚拟的。它是嵌入到spring内核中的。
使用p名称空间可以解决我们setter注入时
使用c名称空间可以解决我们构造器注入时
使用setter注入
在applicationContext.xml文件中添加p名称空间简化setter注入
使用c名称空间来解决构造器注入
在applicationContext.xml文件中添加c名称空间
注:如果c或p名称空间操作的属性后缀是”-ref”代表要引入另一个已经存在的bean,例如
SpEl
spring expression language 是在spring3.0以后的版本提供
它类似于ognl或el表达式,它可以提供在程序运行时构造复杂表达式来完成对象属性存储及方法调用等。
Spel表达式的格式 #{表达式}
示例1:完成bean之间的注入
示例2 支持属性调用及方法调用
Spring注解开发
在spring中使用注解,我们必须在applicationContext.xml文件中添加一个标签
要使用contex名称空间,必须在applicationContext.xml文件中引入
完成bean注册操作
@Component
测试时报错
原因:如果你使用的是spring3.x那么不会出现这个错误,如果使用的是spring4.x会报错,原因是缺少jar包。
导入jar后运行还有错误
我们在applicationContext.xml文件中使用了一个标签
要解决这个问题,我们可以使用
在spring2.5后为@Component添加了三个衍生的注解
@Repository 用于DAO层
@Service 用于service层
@Controller 用于表现层
对于我们的bean所处在的位置可以选择上述三个注解来应用,如果你的bean不明确位置,就可以使用@Component.
属性依赖注入
- 简单的属性注入
- 复杂的属性注入
注意:如果要扫描多个包下的注解可以写成以下:
或
注意:@Value @Autowired它们可以修饰属性,也可以修饰setter方法,如果写在属性上,就不需要提供setter方法。
@Autowired它默认是根据类型进行注入。
如果单独是有这个属性,虽然指定了位置但是不知道类型,所以会报错
@Qualifier(“ci1”)
如果与@Qualifier一起使用,就可以根据名称来进行注入。
我们也可以使用下面的方式来根据名称进行属性注入
说一下@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的作用域。
它相当于init-method=”myInit
它相当于是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可以方便我们的测试。
- 需要导入一个spring-test.jar包
- 可以在测试类上如下操作
Spring在web开发中的应用
1.,在web项目中要使用spring需要导入一个jar包
1.5创建一个servlet(这是没整合.整合过的话创建一个Action)
2.在web.xml文件中配置Listener
这个ContextLoaderListener它实现了ServletContextListener
在这个listener中,当服务器启动时,将ApplicationContext对象,其实是它的一个实现类
WebApplicationContext,对象存入到了ServletContext中。
3.我们还需要在web.xml文件中配置applicationContext.xml文件的位置
默认情况下会在WEB-INF目录 下查找applicationContext.xmls
如果applicationContext.xml文件不是在默认位置,我们可以在web.xml文件中配置
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动态代理只针对于接口操作
第一个参数:目标类的类加载器对象
第二个参数:目标类的实现接口的Class[]
第三个参数:InvocationHandler它是一个接口,它的作用是是代理实例的调用处理程序 实现的接口,接口中定义了一个方法
CGLIB动态代理
CGLIB(Code Generation Library)是一个开源项目
是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类
如果你要单独使用CGLIB,那么需要导入cglib的jar包还需要一个asm相关jar包,但是spring框架的spring-core.jar包中已经集成了cglib与asm
注意:jdk的动态代理只可以为接口去完成操作,而cglib它可以为没有实现接口的类去做代理,也可以为实现接口的类去做代理。
Cglib动态代理
setCallback传递的参数是Callback类型,我们使用的是MethodInterceptor
注意:cglib它可以为没有实现接口的类做代理,也可以为接口类做代理.
问题:spring采用的是哪一种动态机制:
如果目标对象,有接口,优先使用jdk动态代理
如果目标对象,无接口,使用cglib动态代理。
Spring AOP编程
Spring的传统aop编程
讲解的目的是为了更好的理解aop。
在传统的spring aop开发中它支持增强(advice)有五种:
- 前置通知 目标方法执行前增强 org.springframework.aop.MethodBeforeAdvice
- 后置通知 目标方法执行后增强 org.springframework.aop.AfterReturningAdvice
- 环绕通知 目标方法执行前后进行增强 org.aopalliance.intercept.MethodInterceptor
- 异常抛出通知 目标方法抛出异常后的增强 org.springframework.aop.ThrowsAdvice
- 引介通知 在目标类中添加一些新的方法或属性(不讲解)
org.springframework.aop.IntroductionInterceptor
经典的基于代理的AOP开发(了解)
基本的jar包
- bean
- core
- context
- expression
- aop
- 需要aop联盟的依赖jar包
第一步:编写目标(target)
第二步增强(advice)
第三步在applicationContext.xml文件中配置
第四 测试
基于aspectJ切点传统开发
第一步:在spring的配置文件中定义目标与通知
第二步:使用
注意1:需要在xml配置文件中导入aop声明
注意2:因为我们使用aspectj的切面声明方式 需要在导入aspectj的jar包
传统spring aop开发总结
第一步:编写目标对象(target)
第二步:编写通知(advice)
传统的aop开发中,通知是需要实现指定接口。
第三步 在配置文件中配置切面(切面=切点+通知)
关于切点表达式写法
这个语法源于aspectJ的语法,spring中aop开发,对aspectj不是完全支持,只支持部分语法。
在开发中使用的比较多的是execution语法.
关于execution语法常用:
- execution(public ()) 所有的public的方法
- execution( cn.itheima.aop.(..)) 所有的aop包下的所有类的方法(不包含子包)
- execution( cn.itheima.aop..(..)) 所有的aop包及其子包下的所有类的方法
- execution( cn.itheima.aop.IOrderService.(..)) IOrderService接口中定义的所有方法
- execution( cn.itheima.aop.IOrderService+.(..)) 匹配实现特定接口所有类的方法
- execution( save(..)) 区配所有的以save开头的方法
Spring整合aspectj框架实现的aop
在现在的开发中使用这种方案比较多.
在spring2.0以后它支持jdk1.5注解,而整合aspectj后可以使用aspectj语法,可以简化开发。
Aspect:切面 =切点+通知(多个切点与多个通知的组合)
AspectJ 它是一个第三方框架,spring从2.0后可以使用aspectJ框架的部分语法.
AspectJ框架它定义的通知类型有6种
- 前置通知Before 相当于BeforeAdvice
- 后置通知AfterReturning 相当于AfterReturningAdvice
- 环绕通知 Around 相当于MethodInterceptor
- 抛出通知AfterThrowing 相当于ThrowAdvice
- 引介通知DeclareParents 相当于IntroductionInterceptor
- 最终通知After 不管是否异常,该通知都会执行
相比spring 的传统AOP Advice多了一个最终通知
基于xml配置方案
第一步:创建目标(target)
第二步:创建通知(增强 advice)
注意:在aspectj中它的增强可以不实现任何接口,只需要定义出增强功能(方法)
第三步:在spring的xml 配置文件中来配置
前置通知
后置通知
环绕通知
异常抛出
注意:目标行为只有抛出了异常后才会执行这个增强方法
关于通知上的参数
- 在前置通知上可以添加JoinPoint参数
通过它可以获取目标相关的信息
作用:使用前置通知可以完成日志记录,权限控制
- 在后置通知上添加的参数
作用:第二个参数val它可以获取目标方法的返回值
注意:需要在配置文件中配置
- 环绕通知上的参数
作用:它是我们开发中应用最多的,可以完成日志操作,权限操作,性能监控,事务管理
- 抛出异常通知上的参数
第二个参数Throwable它是用于接收抛出的异常
注意:需要在配置文件中声明
- 最终通知上的参数
关于代理方式选择
在spring的aop开发中,它使用的是代理方案,代理实现有两种:
- jdk的proxy
- cglib
spring框架默认情况下,会对有接口的类使用jdk的proxy代理。没有接口的类使用cglib代理
Proxy-target-class的值默认是false,它代表有接口使用jdk的proxy代理,没有接口使用cglib代理
问题:如果现在对目标要使用cglib代理(不考虑是否有接口)?(不管什么情况都使用cglib代理)
只需要将proxy-target-class设置为true.
基于annotation方案(注解方案)
第一步:编写目标
第二步:编写增强(advice)
使用@Aspect来声明切面(里面有切点和通知)
使用@Before来声明前置通知
注意:必须在spring的配置文件中开启aspectJ注解自动代理功能。
第三步:测试
其它通知类型及参数
后置通知
环绕通知
异常抛出通知
使用@Pointcut注解定义切点
在每一个通知中定义切点,工作量大,不方便维护,我们可以使用@Pointcut来声明切点
切点允许逻辑运算例如mypointcut()||mypointcut1
关于代理方式选择
Proxy-target-class默认值是false,代表的是如果目标是有接口的使用jdk,proxy代理,如果没有接口使用cglib.
如果将proxy-target-class=true,不管目标是否有接口,都会使用cglib进行代理。
Spring jdbc Template
Spring提供了一个jdbc模板,它类似于dbutils工具。
问题:如何使用spring jdbc template?
第一:要导入相关的jar包
在这个基础上我们还需要导入
还需要导入相关的数据库驱动jar包。
第二:spring jdbc template快速入门
快速入门
第一步:导入相关jar包,创建了一个JdbcTemplateTest1测试类
第二步:创建库与表
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内置的连接池DriverManagerDataSource
C3P0开源连接池配置
- 导入c3p0相关的jar包
- 创建一个ComboPoolDataSource对象,设置相关的属性
引入外部属性文件
Spring支持将经常修改属性,在properties文件中声明,在xml配置文件中引入外部的properties文件的信息。
在applicationContext.xml文件中引入
在自己配置中需要从properties文件中引入的信息可以使用${name}方式来获取
JdbcTemplate CRUD
执行insert update delete操作
只需要使用JdbcTemplate的update方法就可以执行insert update delete操作
执行select操作
简单数据返回
复杂数据返回
注意:如果只返回一个domain对象,可以使用queryForObject方法,如果返回的是List<?>对象,可以使用query方法,但是都需要使用RowMapper来对ResultSet进行处理。
RowMapper它有一个实现类叫BeanPropertyRowMapper
如果使用BeanPropertyRowmapper,实体类必须提供一个无参数的public构造方法,类中的bean属性名称与表中的列要对应
注意:这个类是在spring2.5后提供。
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
关于service与dao的配置
我们让dao去extends JdbcDaoSupport类,这个类中它创建了JdbcTempate,前提是我们需要注入一个dataSource.
在dao中在获取JdbcTemplate可以使用父类提供的getJdbcTemplate方法来获取。
转账操作的问题
如果在转账操作过程中出现问题,那么转账会出现问题,结果如下
也就是我们程序需要事务控制。
Spring事务管理机制
Spring事务管理的四个优点:
- 提供一致的对于不同的事务管理的API
- 支持声明式事务管理(重点)
- 编程事务管理(在开发中应用比较少)
- 优秀的整合与Spring的数据访问
我们重点讲解spring的事务管理的相关的API,还有声明式事务管理
Spring事务管理主要提供了三个接口来完成
- org.springframework.transaction.PlatformTransactionManager
这是一个事务管理器,可以来选择相关的平台(jdbc hibernate jpa…)
- TransactionDefinition
它定义事务的一些相关信息 例如 隔离 传播 超时 只读
- 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
DataSourceTransactionManager 主要针对于JdbcTemplate开发 MyBatis开发
HibernateTransactionManasger主要针对于Hibernate开发
JpaTransactionManager 主要针对于JPA开发。
TransactionDefinition
它描述的是事务的定义信息。
在TransactionDefinition中定义了大量的常量
隔离
以下是关于隔离性相关信息
事务的四个特性 ACID 原子性 一致性 隔离性 持久性。
不考虑事务隔离性有什么问题?
脏读,不可重复读 虚读。
- ISOLATION_DEFUALT 它使用后端数据库的默认隔离级别(spring中的默认选项)
- ISOLATION_READ_UNCOMMITTED 不能解决问题,会发生脏读 不可重复读 虚读
- ISOLATION_READ_COMMITTED 可以解决脏读 会产生不可重复读与虚读。
- ISOLATION_REPEATABLE_READ 可以解决脏读,不可重复读 解决不了虚读
- ISOLATION_SERIALIZABLE 串行化,可以解决所有问题
- 对于不现的数据库,它的底层默认事务隔离级别不一样。
Oracle数据库它默认的是read_committed
Mysql数据库它默认的是repeatable_read.
超时
默认值是-1 它使用的是数据库默认的超时时间。
只读
它的值有两个true/false,如果选择true一般是在select操作时<br />
传播
它解决的是两个被事务管理的方法互相调用问题。它与数据库没关系,是程序内部维护的问题。
以下定义了事务的传播行为
以上操作中最常用的三种:
PROPAGATION_REQUIRED 默认值 两个操作处于同一个事务,如果之前没有事务,新建一个事务
PROPAGATION_REQUIRES_NEW
两个操作处于不同的事务
PROPAGATION_NESTED
它是一种嵌套事务,它是使用SavePoint来实现的。事务回滚时可以回滚到指定的savepoint,注意:它只对DataSourceTransactionManager有作用
以下了解
PROPAGATION_SUPPORTS 支持当前事务,如果不存在,就不使用事务
PROPAGATION_MANDATORY 支持当前事务,如果不存在,抛出异常
PROPAGATION_NOT_SUPPORTED 以非事务运行,如果有事务存在,挂起当前事务
PROPAGATION_NEVER 以非事务运行,如果有事务存在,抛出异常
TransactionStatus
它定义了事务状态信息,在事务运行过程中,得到某个时间点的状态
声明式事务管理
事务管理方式
- 编码方案 不建议使用,它具有侵入性。在原有的业务代码基础上去添加事务管理代码
- 声明式事务控制,基于AOP对目标进行代理,添加around环绕通知。
这种方案,它不具有侵入性,不需要修改原来的业务代码
基于xml配置声明式事务管理方案
第一步:在application Context.xml文件中添加aop与tx的名称空间
第二步:在applicationContext.xml文件中配置
Spring提供的advice是传统的spring advice
- 声明事务管理器
- 配置通知
Spring为我们提供了一个TransactionInterceptor来完成增强
对于这个增强,我们可以使用spring为我们提供的一个标签
- 配置切面
基于annotation声明式事务管理方案
可以使用@Transaction来在类或方法上添加声明式事务管理
注意:需要在applicationContext.xml文件中使用
相当于开启注解事务控制
问题:关于xml方式与annotation方式的优缺点?
从简单上来说,使用注解更方便。
使用配置的方案,可以对事务配置进行集中维护。
SSH框架整合
SSh=struts2+spring+hibernate
struts2 2.3.24
spring 4.2.4
hibernate 5.0.7
关于xml配置文件的整合方式
SSH整合jar包
Struts2框架需要jar包
Asm 是关于字节码操作
Commons-fileupload 关于文件上传
Commons-io 关于io流操作工具
Commons-lang 也是一个工具,包含了关于数据与字符串操作
Freemaker 标签库模板文件
Javassist 它也是关于字节码操作,动态代理可以使用它实现(类似于cglib)
Log4j关于日志
Ognl 关于ognl表达式
Struts2-core xwork-cor struts2框架底层是使用xwork
Struts2与spring整合还需要这个包
如果需要使用struts2提供的json处理
注意:如果使用注解方案,我们还需要导入一个jar包
Hibernate框架需要的jar包
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包
C3p0连接池
还需要数据库相关的驱动jar包
Spring框架需要的jar包
Spring最基本jar包:
AOP开发:
Spring jdbc:
Spring 事务管理需要tx
Spring整合hibernate :
Spring整合web开发:
如果使用到junit测试:
还需要commons-loggin jar包:
创建工程完成整合前期准备
需要的配置文件:
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管理hibernate配置)
不在需要hibernate.cfg.xml文件,所有关于hibernate.cfg.xml文件中的配置都在spring的配置文件中来配置。
首先要配置数据源
接下来引入properties文件
创建LocalSessionFactoryBean来完成spring管理hibernate中的SessionFactory
上述的props可以简化成下面方案
加载hbm.xml配置文件
mappingResources它类似于我们之前
mappingLocations它加载时是根据类路径加载 classpath:路径
mappingJarLocations它会加载jar文件中的hbm.xml文件
mappingDirectoryLocations 它加载的目录
spring整合hibernate后的DAO
spring整合hiberante后,我们的dao只需要继承HibernateDaoSupport类
在HibernateDaoSupport中只需要注入SessionFactory就可以获得到HibernateTemplate,它是对hibernate操作的一个简单封装,可以让我们方便使用原来hibernate的操作.
编写service及测试
测试
事务管理
HibernateTemplate API介绍
保存操作 session.save()
修改操作 session.update()
删除操作 session.delete()
类似于session.saveOrUpdate()根据持久化对象的状态来判断执行save或update
获取操作 get() load()
Find操作 类似于session.createQuery().setParameter().list()
类似于hibernate中的QBC查询,完全的面向对象方案
下面这个可以执行命名查询
可以在User.hbm.xml文件中定义hql或sql
Spring整合struts2框架
前期准备
创建一个addUser.jsp页面
创建UserAction类
Struts.xml文件中配置
Spring整合struts2原理分析
- spring整合struts2框架必须导入一个jar包
struts2-spring-plugin.jar
- struts2框架配置文件加载顺序
- default.properties
- struts-default.xml
- strtus-plugin.xml
- 在struts2框架中所有的action interceptor result全是bean,在struts2框架中默认是使用strtus2自己bean初化操作.
- 当我们在工程中导入struts2-spring-plugin.jar文件
就会加载这个包下的strtus-plugin.xml
这时bean的创建由spring来管理。
- 这时在创建Action时它执行的代码
上述代码,在执行时,首先会从spring容器中来获取,如果获取不到,会buildBean
通过上述分析,spring整合struts2框架它的方式有两种
- spring管理action(简单说就是在applicationContext.xml文件中来声明action)
- action自动装配service
spring整合struts2框架方式一(掌握)
这种方案是基于spring管理action
- 在applicationContext.xml文件中配置
- 在action类中
- 在struts.xml文件
Class的值就是bean的id值
注意:必须在web.xml文件中配置struts2框架的Filter
Spring整合struts2框架方式二(action中自动注入service)
Struts.xml文件中
Class还是类的全名
这时就会将action类中需要的注入servcie自动注入
在default.properties中有一段配置
这时就会根据名称进行autoWires
我们可以修改注入的方式
我们在struts.xml文件中修改了注入的方式,根据type进行注入
Spring整合struts2框架总结
- 如果在struts.xml文件中
如果写的是全类名,我们使用action自动装配service方案 - 如果在struts.xml文件中
这时,在applicationContext.xml文件中要配置 - 以上操作的前提是必须导入struts2-spring-plugin.xml文件
在这个文件中它改变struts2的bean工厂
- 默认情况下如果采用action自动装配service方案,这时每一次请求都会新创建一个action,并且service的装配类型是by name
- 如果我们采用的是spring管理action这种方案我们必须在
声明中添加scope=prototype”,原因是struts2框架的action每一次请求都应该是一个新的action 关于annotation整合方式
Jar包导入
在原来的xml基础上在多导入一个jar包
只有导入这个jar包后,我们才能使用struts2框架的注解 @Namespace @Action
配置文件
Web.xml文件中要配置
Spring的配置文件 applicationContext.xml
Struts2的配置文件 struts.xml
使用JPA注解来定义PO类
@Entity 定义实体类
@Table 定义表
@Id 主键
@GeneratedValue 生成主键策略
@Column 定义列
Spring整合hibernate
Dao编写
如何在dao中得到HibernateTemplate对象,原来是在applicationContext.xml文件中通过配置方案注入了一个SessionFactory对象,UserDao的父类HibernateDaoSupport,会帮助我们根据SessionFactory来得到HibernateTemplate
Service编写
问题:service需要事务管理,怎样处理?
Action编写
使用@Controller @Scope
以上注解的作用是由spring管理action,它是一个多例的。
问题:如何完成struts2框架的流程?
基于annotation的ssh整合总结
在ssh的annotation整合时,必须要多导入的一个包
对于dao,service,action我们使用
@Repository @Service @Controller来完成bean注册。
在dao中我们使用以下方案将SessionFactory注入,在dao中就可以使用HibernateTemplate
在service及action中使用@Autowire来注入dao及service
一定要在applicationContext.xml文件中开启注解扫描
对于PO类我们使用JPA的注解 @Entiry @Table @Id @GeneratedValue @Column
要在applicationContext.xml文件中配置SessionFactory时来确定扫描包
对于Struts2框架,我们需要@Namespace @Action @ParentPakcage @Result来定义struts2流程
要求action类必须是在action actions struts struts2这样的包中才会扫描struts2相关注解
SSH整合延迟加载问题解决
- 修改UserDao中的findById
- 添加一个user.jsp页面
- 在UserAction中处理user_findById请求
以上程序在执行后,报错
解决no session问题:
- 不使用延迟加载
- 手动将延迟加载初始化 Hibernate.initialize(延迟对象)
- 使用spring提供的一个OpenSessionInViewFilter来解决
基本的原理就是将session的关闭操作不在service层完成,而是在web层才关闭session.
注意:openSessionInViewFilter一定要在Struts2 Filter前配置.