一. spring入门
1. spring的体系结构
2. 开发环境构建
① 安装JDK
② Web服务器
执行Tomncat 根目录bin文件夹中的satup.bat来启动Tomcat服务器。执行startup.bat会占用一个MS-DOS窗口。
Tomcat服务器启动后,在浏览器的地址栏输入“http://localhost:8080”,将出现 Tomcat 测试页面。
③ 安装Intellj idea
idea学习视频
④ 集成 Tomcat
IDEA 添加 Tomcat
3. 使用idea开发spring入门程序
使用 idea 创建 web应用
① 导入Jar包
使用 idea 创建一个名为ch1的Web应用,并将Spring的四个基础包和第三方依赖包复制到ch1的 WEB-INF/lib 目录中
② 创建接口 TestDao
在src目录下创建一个dao包,并在dao包中创建接口TestDao, 在接口中定义一个sayHello方法,代码如下
③ 创建接口的实现类 TestDaoImpl
· 在dao包下创建 TestDao 的实现类 TestDaoImpl,代码如下:
④ 创建配置文件 applicationContext.xml
在src目录下创建Spring的配置文件applicationContext.xml,并在该文件中使用实现类TestDaoImpl创建-一个id为test的Bean,代码如下:
⑤ 创建测试类
在src目录下创建一个test包,并在test包中创建Test类,代码如下:
在执行上述main方法后将在控制台输出“Hello, Study hard!"。在上述main方法中并没有使用new运算符创建TestDaoImpl类的对象,而是通过Spring容器来获取实现类对象,这就是SpringIoC的工作机制。
二. Spring IoC
1. 基本概念
SpringIOC实现原理
控制反转(Inversion of Control, IoC)是spring框架的核心,用来消减计算机程序的耦合问题。依赖注入(Dependency Injection, DI)是IoC的另一个说法。
当Spring框架出现后,对象的实例不再由调用者来创建,而是由Spring容器(例如面包店)来创建。Spring容器会负责控制程序之间的关系(例如面包店负责控制您与面包的关系),而不是由调用者的程序代码直接控制。这样,控制权由调用者转移到Spring容器,控制权发生了反转,这就是Spring的控制反转。
在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入。
2. Spring IoC容器
实现控制反转的是Spring IoC容器。Spring IoC容器的设计主要是基于BeanFactory和ApplicationContext 两个接口。
ApplicationContext是BeanFactory的子接口,也称为应用上下文,由org.springframework.context.ApplicationContext接口定义。ApplicationContext 接口除了包含BeanFactory 的所有功能以外,还添加了对国际化、资源访问、事件传播等内容的支持。
创建 ApplicationContext 接口实最常用的方法时通过ClassPathXmlApplicationContext 创建
3. 依赖注入的类型
在Spring中实现IoC容器的方法是依赖注入,依赖注入的作用是在使用Spring框架创建对象时动态地将其所依赖的对象(例如属性值)注入Bean组件中。
(1)使用构造方法注入
Spring框架可以采用Java的反射机制,通过构造方法完成依赖注入。下面通过Web应用ch2讲解构造方法注入的实现过程,ch2 应用的目录结构如图。
① 创建 dao 包
在ch2应用中创建dao包,并在该包中创建TestDIDao 接口和接口实现TestDIDaoImpl。创建dao包的目的是在service 中使用构造方法依赖注入TestDIDao接对象。
② 创建 service 包
在ch2应用中创建service 包,并在该包中创建TestDIService 接口和接口实现TestDIServicelmpl。在TestDIServicelmpl中使用构造方法依赖注入TestDIDao接口对象。
③ 编写配置文件
在src根目录下创建Spring配置文件 applicationContext.xml。 在配置文件中首先将dao.TestDIDaolmpl类托管给Spring,让Spring创建其对象,然后将service.TestDIServicelmpl类托管给Spring,让Spring创建其对象,同时给构造方法传递实参。配置文件的具体代码如下:
在配置文件中,constructor-arg 元素用于定义类构造方法的参数,index 用于定义参数的位置,ref指定某个实例的引用,如果参数是常量值,ref由value代替。
④ 创建 test 包
(2)使用属性的setter方法注入
使用setter方法注入是Spring框架中最主流的注入方式,它利用Java Bean规范所定义的setter方法来完成注入,灵活且可读性高。对于setter方法注入,Spring框架也是使用Java的反射机制实现的。
① 创建接口实现类 TestDIServiceImpl1
在service包中创建接口实现类TestDIServiceImpll,在TestDIServicelmpll中使用属性的setter方法依赖注入TestDIDao接口对象,具体代码如下:
② 将 TestDIServiceImpl1 类托管给 Spring
将TestDIServiceImpl1 类托管给Spring ,让Spring 创建其对象,同时TestDIServicelmpl1类的setter方法完成依赖注入。在配置文件中添加如下代码:
③ 在 test 中测试 setter 方法注入
三、Spring Bean
1. Bean 的配置
Spring 可以看作一个大型工厂,用于生产和管理Spring容器中的Bean。如果要使用这个工厂生产和管理Bean,需要开发者将Bean配置在Spring 的配置文件中。Spring 框架支持XML和Properties两种格式的配置文件,在实际开发中常用XML格式的配置文件。
从前面的学习得知XML配置文件的根元素是
2. Bean 的实例化
在面向对象编程中,如果想使用某个对象,需要事先实例化该对象。视 频讲解同样,在Spring框架中,如果想使用Spring容器中的Bean,也需要实例化Bean。
Spring框架实例化Bean有3种方式,即构造方法实例化、静态工厂实例化和实例工厂实例化(其中,最常用的方法是构造方法实例化。
(1)构造方法实例化
在Spring 框架中,Spring 容器可以调用Bean对应类中的无参数构造方法来实例化Bean,这种方式称为构造方法实例化。下面通过ch3应用来演示构造方法实例化的过程。
① 创建 Web 应用 ch3
② 创建 BeanClass 类
在ch3的src目录下创建instance包,并在该包中创建BeanClass类
③ 创建配置文件
在ch3的src目录下创建Spring的配置文件applicationContext.xml,在配置文件中定义一个id为constructorInstance的Bean,代码如下:
④ 创建测试类
在ch3的src目录下创建test包,并在该包下创建测试类TestInstance,代码如下:
(2)静态工厂实例化
(3)实例工厂实例化
3. Bean 的作用域
在Spring中不仅可以完成Bean的实例化,还可以为Bean指定作用域。
① singleton作用域
当将bean的scope设置为singleton 时,Spring IoC容器仅生成和管理一个Bean实例。在使用id或name获取Bean实例时,IoC容器将返回共享的Bean实例。
由于singleton是scope的默认方式,因此有两种方式将bean的scope设置为singleton。配置文件示例代码如下:
测试 singleton 作用域,代码如下:
从所示的运行结果可以得知,在使用id或name获取Bean实例时,IoC 容器仅返回同一个Bean实例。
② prototype 作用域
当将bean的scope设置为prototype 时,Spring IoC容器将为每次请求创建一个新的实例。如果将3.3.1中bean的配置修改如下:
4. Bean 的生命周期
下面通过-一个实例演示Bean的生命周期:
① 创建Bean的实现类
在ch3应用的sre目录中创建life包,在life包下创建BeanLife类。在BeanLife类中有两个方法,一个演示初始化过程,- -个演示销毁过程。具体代码如下:
② 配置Bean
③ 测试生命周期
5. Bean 的装配方式
Bean的装配可以理解为将Bean依赖注入到Spring容器中,Bean的装配方式即Bean依赖注入的方式。Spring 容器支持基于XML配置的装配、基于注解的装配。其中最受青睐的装配方式是基于注解的装配。
在Spring框架中,尽管使用XML配置文件可以很简单地装配Bean,但如果应用中有大量的Bean需要装配,会导致XML配置文件过于庞大,不方便以后的升级与维护,因此更多的时候推荐开发者使用注解(annotation)的方式去装配Bean。
在Spring框架中定义了一系列的注解,下 面介绍几种常用的注解。
(1) @Component
该注解是-一个泛化的概念,仅仅表示一个组件对象(Bean), 可以作用在任何层次上。下面通过一个实例讲解@Component。
① 创建 Bean 的实现类
② 配置注解
现在有了Bean的实现类,但还不能进行测试,因为Spring 容器并不知道去哪里扫描Bean对象,需要在配置文件中配置注解,方式如下:
③ 测试 Bean 实例
注:在Spring 4.0以上的版本,配置注解指定包中的注解进行扫描前需要事先导入Spring AOP的JAR包spring-aop-5.0.2.RELEASE.jar
(2)@ Repository
该注解用于将数据访问层(DAO)的类标识为Bean,即注解数据访问层Bean,其功能与@Component相同。
(3)@ Service
该注解用于标注一个业务逻辑组件类(Service层),其功能与@Component相同。
(4)@Controller
该注解用于标注一个控制器组件类( Spring MVC的Controller), 其功能与@Component相同。
(5)@ Autowired
该注解可以对类成员变量、方法及构造方法进行标注,完成自动装配的工作。通过使用@Autowired来消除setter 和getter方法。默认按照Bean的类型进行装配。
(6)@ Resource
该注解与@Autowired的功能一样, 区别在于该注解默认是按照名称来装配注入的,只有当找不到与名称匹配的Bean时才会按照类型来装配注入;而@Autowired默认按照Bean的类型进行装配,如果想按照名称来装配注入,则需要和@Qualifier注解一起使用。@Resource注解有两个属性一name和type。name属性指定Bean 实例名称,即按照名称来装配注入; type 属性指定Bean类型,即按照Bean的类型进行装配。
(7) @Qualifier
该注解与@Autowired注解配合使用。当@Autowired 注解需要按照名称来装配注入时需要和该注解-起使用,Bean 的实例名称由@Qualifier注解的参数指定。在上面几个注解中,虽然@Repository、@Service 和@Controller等注解的功能与@Component注解相同,但为了使类的标注更加清晰(层次化),在实际开发中推荐使用@Repository标注数据访问层(DAO层)、使用@Service 标注业务逻辑层(Service层)、 使用@Controller标注控制器层( 控制层)。
下面通过一个实例讲解如何使用这些注解:
① 创建 Dao 层
在ch3应用的src中创建annotation.dao包,在该包下创建TestDao接口和TestDaoImpl实现类,并将实现类TestDaolmpl使用@Repository注解标注为数据访问层。
② 创建 Service 层
在ch3应用的sre 中创建annotation.service 包,在该包下创建TestService 接口和TestSevicelmpl实现类,并将实现类TestSevicelmpl使用@Service注解标注为业务逻辑层。
③ 创建 Controller 层
在ch3应用的src中创建annotationcontroller包,在该包下创建TestController类,并将TestController类使用@Controller注解标注为控制器层。
④ 配置注解
由于annotation.dao. annotation.service和annotation.controller包都属于annotation包的子包,因此不需要在配置文件annotationContext.xml中配置注解。
⑤ 测试测试类
四、 Spring AOP
1、 AOP的概念术语
(1)AOP 的概念
AOP (Aspect-Oriented Programming) 即面向切面编程,它与OOP ( Object-Oriented Programming,面向对象编程)相辅相成,提供了与OOP不同的抽象软件结构的视角。在OOP中,以类作为程序的基本单元,而AOP中的基本单元是Aspect (切面)。Struts2的拦截器设计就是基于AOP的思想,是个比较经典的应用。
AOP采取横向抽取机制,即将分散在各个方法中的重复代码提取出来,然后在程序编译或运行阶段将这些抽取出来的代码应用到需要执行的地方。
(2)AOP术语
① 切面
切面(Aspect)是指封装横切到系统功能(例如事务处理)的类。
② 连接点
连接点(Joinpoint) 是指程序运行中的一些时间点, 例如方法的调用或异常的抛出。
③ 切人点
切入点(Pointcut)是指需要处理的连接点。在Spring AOP中,所有的方法执行都是连接点,而切入点是一个描述信息,它修饰的是连接点,通过切入点确定哪些连接点需要被处理。
④ 通知
通知(Advice) 是由切面添加到特定的连接点(满足切入点规则)的段代码,即在定义好的切入点处所要执行的程序代码,可以将其理解为切面开启后切面的方法,因此通知是切面的具体实现。
⑤ 引入
引入( Introduction)允许在现有的实现类中添加自定义的方法和属性。
⑥ 目标对象
目标对象(Target Object)是指所有被通知的对象。如果AOP框架使用运行时代理的方式(动态的AOP)来实现切面,那么通知对象总是一个代理对象。
⑦ 代理
代理(Proxy)代理是通知应用到目标对象之后被动态创建的对象。
⑧ 织入
织入(Weaving)是将切面代码插入到目标对象上,从而生成代理对象的过程。根据不同的实现技术,AOP织入有3种方式:编译期织入,需要有特殊的Java编译器; 类装载期织入,需要有特殊的类装载器: 动态代理织入,在运行期为目标类添加通知生成子类的方式。Spring AOP框架默认采用动态代理织入,而AspectJ (基于Java语言的AOP框架)采用编译期织入和类装载期织入。
2、 动态代理
(1)JDK 动态代理
JDK动态代理是java.lang.reflect.*包提供的方式,它必须借助一个接口才能产生代理对象。因此,对于使用业务接口的类,Spring默认使用JDK动态代理实现AOP。下面通过一个实例演示如何使用JDK动态代理实现Spring AOP,具体步骤如下:
① 创建应用
创建一个名为ch4的Web应用,并导入所需的JAR包。
② 创建接口及实现类
在ch4的src目录下创建一个dynamic,jdk包,在该包中创建接口TestDao和接口实现类TestDaolmpl。该实现类作为目标类,在代理类中对其方法进行增强处理。如下:
③ 创建切面类
在ch4的src目录下创建一个aspect包,在该包中创建切面类MyAspect,注意在该类中可以定义多个通知(增强处理的功能方法)。
④ 创建代理类
在dynamic.jdk包中创建代理类JDKDynamicProxy。在JDK动态代理中代理类必须实现java.lang.reflct.InvocationHandler接口,并编写代理方法,在代理方法中需要通过Proxy实现动态代理。
⑤ 创建测试类
在dynamicjdk包中创建测试类JDKDynamicTest。在主方法中创建代理对象和目标对象,然后从代理对象中获取对目标对象增强后的对象,最后调用该对象的添加、修改和删除方法。
(2)CGLIB 动态代理
JDK 动态代理必须提供接口才能使用,对于没有提供接口的类,只能采用CGLIB动态代理。
CGLIB (Code Generation Library)是一个高性能开源的代码生成包,采用非常底层的字节码技术,对指定的目标类生成一个子类,并对子类进行增强。在Snrina Core句中已经集成了CGLIB所需要的IAR包不需要另外导入JAR包。下面通过一个实例演示CGLIB动态代理的实现过程,具体步骤如下:
① 创建目标类
在ch4的src目录下创建-一个dynamic.cglib包,在该包中创建目标类TestDao,注意该类不需要任何接口。
② 创建代理类
在dynamic.cglib 包中创建代理类CglibDynamicProxy, 该类实现MethodInterceptor接口。如下:
③ 创建测试类
在dynamic.cglib包中创建测试类CglibDynamicTest。在主方法中创建代理对象和目标对象,然后从代理对象中获取对目标对象增强后的对象,最后调用该对象的添加、修改和删除方法。如下:
上述测试类的运行结果与图4.3-样,这里不再赘述。
3、 AOP的实现
从4.2 节可知,在Spring 中默认使用JDK动态代理实现AOP编程。使用org.springframework.aop.framework.ProxvFactorvBean创建代理是Spring AOP实现的最基本方式。
(1) 通知类型
在讲解ProxyFactoryBean之前先了解一下 Spring 的通知类型。根据Spring中通知在目标类方法中的连接点位置,通知可以分为6种类型。
① 环绕通知,
环绕通知(org.aopalliance intercept.MethodInterceptor)是在目标方法执行前和执行后实施增强,可应用于日志记录、事务处理等功能。
② 前置通知
前置通知(org.springframework.aop.MethodBeforeAdvice) 是在目标方法执行前实施增强,可应用于权限管理等功能。
③ 后置返回通知
后置返回通知(org.springframework.aop.AfterReturningAdvice)是在目标方法成功执行后实施增强,可应用于关闭流、删除临时文件等功能。
④ 后置(最终)通知
后置通知(org.springframework.aop.AfterAdvice) 是在目标方法执行后实施增强,与后置返回通知不同的是,不管是否发生异常都要执行该类通知,该类通知可应用于释放资源。
⑤ 异常通知
异常通知(org.springframework aop.ThrowsAdvice)是在方法抛出异常后实施增强,可应用于处理异常、记录日志等功能。
⑥ 引入通知
引入通知(org.springframework. aop,IntroductionInterceptor)是在目标类中添加一些新的方法和属性,可应用于修改目标类(增强类)。
(2)ProxyFactoryBean
ProxyFactoryBean是org.springframework beans. factory.FactoryBean接口的实现类,FactoryBean 负责实例化一个Bean实例,ProxyFactoryBean 负责为其他Bean实例创建代理实例。ProxyFactoryBean 类的常用属性如表所示。
下面通过一个实现环绕通知的实例演示Spring使用ProxyFactoryBean创建AOP代理的过程。
① 导入相关JAR包
在核心JAR包的基础上需要向ch4应用的/WEB-INF/lib目录下导入JAR包spring-aop-5.0.2.RELEASE.jar和aopalliance-1.0.jar.
aopalliance-1.0.jar是AOP联盟提供的规范包
② 创建切面类
由于该实例实现环绕通知,所以切面类需要实现org,apalliance.intercept.MethodInterceptor接口。在src目录下创建一个spring.proxyfactorybean包,并在该包中创建切面类MyAspect。
③ 配置切面并指定代理
切面类需要配置为Bean 实例,这样Spring 容器才能识别为切面对象。在spring.proxyfactorybean包中创建配置文件applicationContext.xml, 并在文件中配置切面和指定代理对象。applicationContext.xml的代码如下:
在上述配置文件中首先通过
④ 创建测试类
在spring.proxyfactorybean 包中创建测试类ProxyFactoryBeanTest, 在主方法中使用Spring容器获取代理对象,并执行目标方法。
.上述测试类的运行结果与图4.3一样,这里不再赘述。
4、 基于XML配置开发AspectJ
AspectJ 是一个基手Java语言的AOP框架。从Spring 2.0以后引入了AspectJ的支持。对于目前的Spring框架,建议开发者使用AspectJ实现SpringAOP。使用AspectI实现SpringAOP的方式有两种,一是基于XML配置开发AspectJ,二是基于注解开发AspectJ。本节讲解基于XML配置开发AspectJ的相关知识,而基于注解开发AspectJ 的相关知识将在4.5节讲解。
基于XML配置开发AspectJ是指通过XML配置文件定义切面、切入点及通知,所有这些定义都必须在
下面通过一个实例演示基于XML配置开发AspectJ的过程
① 导人AspectJ框架相关的JAR包
需要向ch4应用的/WEB-INF/ib目录下导入JAR包 spring aspects-5.0.2.RELEASE.jar 和 aspectijweaver-1.8.13.jar。spring aspects-5.0.2.RELEASE.jar 是Spring为AspectJ提供的实现,在Spring的包中已提供。aspectjweaver-1.8.13.jar 是AspectJ 框架所提供的规范包。
② 创建切面类
在ch4应用的sre目录下创建aspectj.xml包,在该包中创建切面类MyAspect,并在该类中编写各种类型的通知。
③ 创建配置文件,并编写相关配置
在aspectj.xml包中创建配置文件applicationContext.xml,并为 在上述配置文件中,expression="execution(* dynamic.jdk.*.(.))" 是定义切入点表达式,该切入点表达式的意思是匹配dynamic.jdk 包中任意类的任意方法的执行。其中,execution(* dynamic.je.*..)是表达式的主体,第=个*表示的是返回类型,使用*代表所有类型: dynamic,jdk 表示的是需要匹配的包名,后面第二个*表示的是类名,使用*代表匹配包中所有的类;第三个*表示的是方法名,使用*表示所有方法:后面的(..)表示方法的参数,其中的“”表示任意参数。另外,注意第一个*和包名之间有一一个空格。 ④ 创建测试类 在aspectj.xml包中创建测试类XMLAspectJTest,在主方法中使用Spring容器获取代理对象,并执行目标方法。 异常通知得到执行,需要在dynamic jdk. TestDaoImpl类的save方法中添加异常代码,例如“intn= 100/0;”,然后重新运行测试类,运行结果如下图所示。 从上面两张图可以看出各类型通知与目标方法的执行过程,具体过程如下图所示。 5、基于注解开发 AspectJ 基于注解开发AspectJ要比基于XML配置开发AspectJ便捷许多,所以在实际开发中推荐使用注解方式。 下面通过一个实例讲解基于注解开发AspectJ的过程,具体步骤如下: ① 创建切面类,并进行注解 在ch4应用的src目录下创建aspectj.annotation包,在该包中创建切面类MyAspect。在该类中首先使用@Aspect注解定义一一个切面类,由于该类在Spring中是作为组件使用的,所以还需要使用@Component注解:然后使用@Pointcut注解切入点表达式,并通过定义方法来表示切入点名称:最后在每个通知方法上添加相应的注解,并将切入点名称作为参数传递给需要执行增强的通知方法。MyAspect的代码如下: ② 注解目标类 使用注解@Repository将目标类dynamic jdk.TestDaoImpl注解为目标对象,注解代码如下: ③ 创建配置文件 在aspectj. annotation包中创建配置文件applicationContext.xml,并在配置文件中指定需要扫描的包,使注解生效,同时需要启动基于注解的AspectJ支持。applicationContext.xml的代码如下: 五、Spring的事务管理 1、Spring的数据库编程 数据库编程是互联网编程的基础,Spring 框架为开发者提供了JDBC模板模式,即jdbc Template,它可以简化许多代码,但在实际应用中jdbcTemplate并不常用,在工作中更多的时候是使用Hibernate框架和MyBatis框架进行数据库编程。 (1)Spring JDBC 的配置 本节Spring数据库编程主要使用Spring JDBC模块的core和dataSource包。core包是JDBC的核心功能包,包括常用的jdbcTemplate类. dataSource句是访间数据源的工具类包。如果要使用Spring JDBC操作数据库,需要对其进行配置,配置文件的示例代码如下: 在上述示例代码中,配置JDBC模板时需要将dataSource注入到jdbcTemplate.而在数据访问层(Dao类)需要使用jdbcTemplate时也需要将jdbcTemplate注入到对应的Bean中。示例代码如下: (2)Spring JdbcTemplate 的常用方法 获取了JDBC模板,那么如何使用它?这是本节将要讲述的内容。首先需要了解JdbcTemplate类的常用方法,该类的常用方法是update和query。 ●public int update(String sql,Object args[]):该方法可以对数据表进行增加、修改、删除等操作。使用args[]设置 SQL语句中的参数,并返回更新的行数。示例代码如下: ●public List 下面通过一个实例演示Spring JDBC的使用过程,具体步骤如下: ① 创建应用并导人JAR包 创建一个名为ch5的Web应用,将Spring框架的5个基础JAR包、MySQL数据库的驱动JAR包、Spring JDBC的JAR包以及Spring 事务处理的JAR包复制到应用的/WEB-INF/ib目录下。ch5应用所添加的JAR包如图5.1所示。 ② 创建并编辑配置文件 在src目录下创建配置文件applicationContext.xml,在该文件中配置数据源和JDBC模板,具体代码如下: ③ 创建实体类 在src目录下创建com.ch5包,在该包中创建实体类MyUser。注意,该类的属性与数据表user的字段一致。数据表user的结构如图所示。 实体类MyUser代码如下: ④ 创建数据访问层Dao 在com.ch5包中创建TestDao接口和TestDaolmpl实现类。在实现类TestDaolmpl中使用JDBC模块Jdbc Template访问数据库,并将该类注解为@Repository("testDao")。使注解生效,需要在配置文件中扫描( 见第2个步骤)。 ⑤ 创建测试类 在com.ch5包中创建测试类TestSpringJDBC。 在主方法中调用数据访问层Dao中的方 法,对数据表user进行操作。具体代码如下: 运行上述测设类,结果如下: 2、编程式事务管理 在代码中显式调用beginTransaction、 commit、 rollback 等与事务处理视频讲解相关的方法,这就是编程式事务管理。当只有少数事务操作时,编程式事务管理才比较合适。 (1)基于底层API的编程式事务管理 实例: ① 给数据源配置事务管理器 ② 创建数据访问类 在com.ch5包中创建数据访问类CodeTransaction,并注解为@Repository("codeTransaction")。在该类中使用编程的方式进行数据库事务管理。 ③ 创建测试类 上述测试类结果: (2)基于Transaction Template的编程式事务管理 事务处理的代码散落在业务逻辑代码中,破坏了原有代码的条理性,并且每一一个业务方法都包含了类似的启动事务、提交以及回滚事务的样板代码。 TransactionTemplate的execute方法有一个TransactionCallback 接口类型的参数,该接口中定义了一个doInTransaction方法,通常以匿名内部类的方式实现TransactionCallback接口,并在其doInTransaction方法中书写业务逻辑代码。在这里可以使用默认的事务提交和回滚规则,在业务代码中不需要显式调用任何事务处理的API。 doInTransaction 方法有一个TransactionStatus 类型的参数,可以在方法的任何位置调用该参数的setRollbackOonly方法将事务标识为回滚,以执行事务回滚。 根据默认规则,如果在执行回调方法的过程中抛出了未检查异常,或者显式调用了setRollbackOnly 方法,则回滚事务:如果事务执行完成或者抛出了checked 类型的异常,则提交事务。 基于TransactionTemplate的编程式事务管理的步骤如下: ① 为事务管理器添加事务模板 在配置文件applicationContext.xml 的基础上使用org.springframework.transaction.support.TransactionTemplate类为事务管理器添加事务模板,具体代码如下: ② 创建数据访问类 在com.ch5 包中创建数据访问类TransactionTemplateDao, 并注解为@Repository("transactionTemplateDao")。在该类中使用编程的方式进行数据库事务管理。 数据访问类TransactionTemplateDao的代码如下: ③ 创建测试类 3、声明式事务管理 Spring的声明式事务管理是通过AOP技术实现的事务管理,其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。 声明式事务管理最大的优点是不需要通过编程的方式管理事务,因而不需要在业务逻辑代码中掺杂事务处理的代码,只需相关的事务规则声明便可以将事务规则应用到业务逻辑中。通常情况下,在开发中使用声明式事务处理不仅因为其简单,更主要的是因为这样使得纯业务代码不被污染,极大地方便了后期的代码维护。 与编程式事务管理相比,声明式事务管理唯一不足的地方是最细粒度只能作用到方法级别,无法做到像编程式事务管理那样可以作用到代码块级别。但即便有这样的需求,也可以通过变通的方法进行解决,例如可以将需要进行事务处理的代码块独立为方法等。 Spring的声明式事务管理可以通过两种方式来实现,一是基于XML的方式,二是基于@Transactional注解的方式。 (1)基于XML方式的声明式事务管理 基于XML方式的声明式事务管理是通过在配置文件中配置事务规则的相关声明来实现的。Spring 框架提供了tx命名空间来配置事务,提供了 在 ① 导入相关jar包 导入aop相关包 ② 创建Dao层 在ch5 的sre目录下创建com.statement.dao包,并在该包中创建TestDao 接口和TestDaoImpl实现类。数据访问层有两个数据操作方法,即save和delete方法。 TestDao接口的代码如下: TestDaoImpl实现类代码如下: ③ 创建Service层 在ch5的src目录下创建com.statement.service包,并在该包中创建TestService接口和TestServicelmpl实现类。在Service层依赖注入数据访问层。 TestService接口的代码如下: TestServicempl实现类代码如下: ④ 创建Controller层 在ch5的src目录下创建com.statement.controller包,并在该包中创建StatementController控制器类。在控制层依赖注入Service层。 StatementController类的代码如下: ⑤ 创建配置文件 在ch5的src 目录下创建com.statement.xml包,并在该包中创建配置文件XMLstatementapplicationContext.xml。在配置文件中使用 XMLstatementapplicationContext.xml文件的代码如下: ⑥ 创建测试类 在ch5的src目录下创建com.statement.test包,并在该包中创建测试类XMLTest,在测试类中通过访问Controller 测试基于XML方式的声明式事务管理。 测试类XMLTest的代码如下: (2)基于@Transactional注解的声明式事务管理 @Transactional注解可以作用于接口、接口方法、类以及类的方法上。当作用于类上时,该类的所有public方法都将具有该类型的事务属性,同时也可以在方法级别使用该注解来覆盖类级别的定义。虽然@Transactional注解可以作用于接口、接口方法、类以及类的方法.上,但是Spring小组建议不要在接口或者接口方法上使用该注解,因为它只有在使用基于接口的代理时才会生效。 如果不想对某个异常进行事务处理,可以使用如下代码: 下面通过实例演示使用@Transactional注解进行事务管理的过程,该实例的Dao、Service和Contoller层与上节中的相同,具体步骤如下: ① 创建配置文件 在com.statement.xml包中创建配置文件annotationstatementapplicationContext.xml,在配置文件中使用 annotationstatementapplicationContext.xml文件的代码如下: ② 为Service层添加@Transcational注解 在Spring MVC (后续章节讲解)中通常通过Service 层进行事务管理,因此需要为Service层添加@Transactional注解。 添加@Transactional注解后的TestServicelmpl类的代码如下: 本章小结: 基于TransactionDefinition、PlatformTransactionManager、 TransactionStatus 的编程式事务管理是Spring提供的最原始的方式,通常在实际工程中不推荐使用,但了解这种方式对理解Spring事务处理的本质有很大帮助。 基于TransactionTemplate的编程式事务管理是对上一种方式的封装, 使得编码更简单、清晰。基于XML和@Transactional的方式将事务管理简化到了极致,极大地提高了编程开发效率。