Spring框架
spring介绍
spring是一个设计层面框架,它解决的是业务逻辑层和其他各层的耦合问题,它将面向接口的编程思想贯穿整个系统应用
spring特点
- 方便解耦,简化开发
- AOP编程的支持
- 声明时事务的支持
- 方便程序的测试
- 方便集成各种优秀框架
- 降低Java EE API的使用难道
spring组织结构
ORM —— object relation mapping
OXM —— object xml mapping
JMS —— Java消息服务(Java Message Service , JMS)
WebSocket protocol是HTML5一种新的协议,它实现了浏览器与服务器全双工通信。一开始的握手需要借助HTTP请求完成。Socket是传输控制层协议,WebSocket是应用层协议
Portlet是一种Web组件——就像servlet——是专为将合成页面里的内容聚集在一起而设计的。通常请求一个portal页面会引发多个portlets被调用。每个portlet都会生成标记段,并于别的portlets生成的标记段组合在一起嵌入到portal页面的标记内
spring的核心模块
spring-core:依赖注入IOC与DI的最基本实现
spring-beans:Bean工厂与bean的装配
spring-context:spring的context上下文即IOC容器
spring-context-support
spring-expression:spring表达式语言
sping中的IOC
IOC是Inverse of Control,意思是控制反转,是降低对象之间的耦合关系的设计思想。
DI是Dependency Injection,意思依赖注入,创建对象实例时,同时为这个对象注入它所依赖的属性
实现过程
步骤1:添加jar包
<!-- Spring的核心工具包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<!--在基础IOC功能上提供扩展服务,还提供许多企业级服务的支持,有邮件服务、
任务调度、远程访问、缓存以及多种视图层框架的支持-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<!-- Spring IOC的基础实现,包含访问配置文件、创建和管理bean等 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<!-- Spring context的扩展支持,用于MVC方面 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<!-- Spring表达式语言 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
步骤二:创建配置文件applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
步骤三:在配置文件中创建对象
<bean id="对象名" class="类的完整路径">
<property name="属性名" ref="对象的id"></property>
</bean>
步骤四:加载配置文件,获取对象
ApplicationContext app = new ClassPathXmlApplicationContext("spring.xml");
User user = (User)app.getBean("u1");
属性用set方法得到对象,方法用加载配置文件来得到对象
1.bean标签属性
属性 | 说明 |
---|---|
class | 指定bean对应类的全路径 |
name | name是bean对应对象的一个标识 |
scope | 执行bean对象创建模式和生命周期,scope=“singleton”和scope=“prototype” |
id | id是bean对象的唯一标识,不能添加特别字符 |
lazy-init | 是否延时加载默认:false。true延迟加载对象,当对象被调用的时候才会加载,测试的时候,通过getBean()方法获取对象。lazy-init=“false”默认值,不延迟,无论对象是否被调用,都会立即创建对象,测试时只需要加载配置文件即可。注意:测试的时候只留下id,class属性 |
init-method | 只需要加载配置文件即可调用对象初始化方法 |
destroy-method | 对象消耗方法 |
(给属性赋值时,对象类型选择ref,非对象类型选择value
选用构造方法可以用name指定,多参可以用index指定)
2.对象创建的方式
(1)无参构造
(2)有参构造
public Person(String name, Car car){
this.name = name;
this.car = car;
System.out.println("Person的有参构造方法:"+name+car);
}
<bean name="person" class="com.xzk.spring.bean.Person">
<constructor-arg name="name" value="rose"/>
<constructor-arg name="car" ref="car"/>
</bean>
(3)静态工厂模式
public class PersonFactory {
public static Person createPerson(){
System.out.println("静态工厂创建Person");
return new Person();
}
}
<bean name="pf" class="com.xzk.PersonFactory" factory-method="createPerson" />
(4)非静态工厂方法
public class Users{
public Person createPerson1(){
System.out.println("非静态工厂创建Person");
return new Person();
}
}
<bean id="u2" class="com.bean.Users"></bean>
<bean id="u3" factory-method="createPerson1" factory-bean="u2"></bean>
springBean的生命周期
Bean生命周期的整个执行过程
DI注入值
属性赋值有两种:一种是调取属性的set方法赋值,一种是使用构造方法赋值
1.set注入值
基本类型值注入
<property name="name" value="zhangsan" />
引用类型值注入
<bean id="stu" class="com.zhq.bean.Student"></bean>
<property name="car" ref="stu" />
2.构造注入
通过name属性,按照参数名赋值
public Person(String name, Car car){
this.name = rose;
this.car = car;
System.out.println("Person的有参构造方法:"+name+car);
}
<bean name="person" class="com.zhq.bean.Person">
<constructor-arg name="name" value="rose"/>
<constructor-arg name="car" value="car"/>
</bean>
通过index属性,按照参数索引注入
<bean name="person2" class="com.zhq.bean.Person">
<constructor-arg index="0" value="rose"/>
<constructor-arg index="1" value="car"/>
</bean>
使用type注入
3.spel spring表达式
<bean name="car" class="com.zhq.bean.Car">
<property name="name" value="mine"/>
<property name="color" value="白色"/>
</bean>
<!--利用spel引入car的属性-->
<bean name="person1" class="com.zhq.bean.Person">
<property name="name" value="#{car.name}"/>
<property name="age" value="#{person.name}"/>
</bean>
4.p命名空间注入值
使用p:属性名 完成注入,走set方法
-基本类型值:p:属性名 = “值”
-引用类型值:p:属性名-ref = “bean名称”
//配置文件 添加命名空间p
xmlns:p="http://www.springframework.org/schema/p"
<bean id="u6" class="com.zhq.bean.User" p:age="30" p:name="李四" p:student-ref="stu1"></bean>
5.复杂类型注入
数组、list、set、map、Java.util.Properties
<bean id="stu" class="com.zhq.bean.User">
<constructor-arg name="age" value="15"></constructor-arg>
<constructor-arg name="name" value="11111"></constructor-arg>
</bean>
<!--复杂类型注入-->
<bean id="teacher" class="com.zhq.bean.Teacher">
<property name="objects" >
<list>
<value>object[]类型注入</value>
<value>张三</value>
<value>15</value>
<value>男</value>
<ref bean="stu"></ref>
</list>
</property>
<property name="list">
<list>
<value>List类型注入</value>
<value>李四</value>
<value>45</value>
<value>女</value>
<ref bean="stu"></ref>
</list>
</property>
<property name="set">
<set>
<value>Set类型注入</value>
<value>王五</value>
<value>22</value>
<value>男</value>
<ref bean="stu"></ref>
</set>
</property>
<property name="map">
<map>
<entry key="type" value="Map类型注入"></entry>
<entry key="name" value="赵六"></entry>
<entry key="age" value="16"></entry>
<entry key="sex" value="男"></entry>
<entry key="other" value-ref="stu"></entry>
</map>
</property>
<property name="properties">
<props>
<prop key="username">root</prop>
<prop key="password">123456</prop>
</props>
</property>
</bean>
6.自动注入(由程序自动给属性赋值)
autowire:
no 不自动配置(默认值)
byName 属性名=id名,调用set方法赋值
byType 属于的类型和id对象的类型相同,当找到多个同类型的对象时报错,调取set方法赋值
constructor 构造方法的参数类型和id对象的类型相同,当没有找到时,报错。调取构造方法赋值
注解实现IOC
//注解的依赖包,jdk应该是有的,可能是有多个包冲突了,找不到显示NoSuchMethodError,修改默认配置文件
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.1</version>
</dependency>
(1)配置文件添加约束(添加命名空间)
(2)配置注解扫描:指定扫描包下所有类中的注解,扫描包时,会扫描包中的所有子包
(3)注解
1.添加在类名上
@Component("对象名")
@Service("person") //service层
@Controller("person") //controller层
@Repository("person") //dao层
@Scope(scopeName="singleton") //单例对象
@Scope(scopeName="prototype") //多例对象
2.添加在属性上
@Value("属性值")
private String name;
@Autowired //默认是byType注入方式,如果一个接口有多个实现类,则会报错,需要用@Quelifier("实现类名")去指定
@Quelifier("bean name")
private Person person
//@Resource是java的注释,但是spring框架支持,可以指定注入那个名称的对象
//@Resource(name="对象名") == @Autowired + @Qualifier("name")
@Resource(name="baoma")
private Car car;
3.添加在方法上
@PostConstruct //等价于init-method属性
public void init(){
System.out.println("初始化方法");
}
@PreDestroy //等价于destroy-method属性
public void destroy(){
System.out.println("销毁方法");
}
AOP介绍
oop面向对象纵向
AOP(Aspect Oriented Programming)面向切面编程。即在不改变原程序的基础上为代码段增加新的功能,应用在权限认证、日志、事务。
AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Py00Dv8W-1600177548642)(C:\Users\zhqsocool\Desktop\课件与笔记\文档\img\aop.png)]
AOP的实现机制
JDK动态代理:针对实现接口的类产生代理。实现InvocationHandler接口
CGlib的动态代理:针对没有实现接口的类产生代理,应用的是底层的字节码增强技术,生成当前类的子类对象,MethodInterceptor接口
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EGOWH9Go-1600177548645)(C:\Users\zhqsocool\Desktop\课件与笔记\文档\img\代理.png)]
JDK动态代理实现(一定要实现接口的类)
1.创建接口和对应实现类
2.创建动态代理类,实现InvocationHandler接口
CGLib实现代理
CGLib采用底层的字节码技术,可以为一个类创建子类,在子类中采用方法拦截拦截住所有父类方法的调用并顺势植入横切逻辑
1.添加依赖:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.5</version>
</dependency>
2.创建CGLib代理器
class CGProxy implements MethodIntercepter{
public Object intercept(Oject o, Method method, Object[] objects, MethodProxy methodProxy){
System.out.println("输入语句1");
//Object由CGLib动态生成的代理类实例,Method为实体类所调用的被代理的方法
//Object[]为参数值列表,MethodProxy为生成的代理类对方法的代理引用
Object obj = methodProxy.invokeSuper(o,object);
System.out.println("输入语句2");
return obj;
}
}
测试:
public static void main(String[] args) {
//1.创建真实对象
Users users = new Users();
//2.创建代理对象
Enhancer enhancer = new Enhancer();
//获取超类
enhancer.setSuperclass(users.getClass());
//回调函数
enhancer.setCallback(new CglibProxy());
Users o = (Users) enhancer.create();//代理对象
o.test();
}
spring同时使用了两种方法,底层会自行判断应该使用哪种
两种代理方法的区别
1、jdk动态代理生成的代理类和委托类实现了相同的接口
2、cglib动态代理中生成的字节码,生成的代理类是委托类的子类,且不能处理被final关键字修饰的方法
3、jdk采用反射机制调用委托类的方法,cglib采用类似索引的方式直接调用委托类方法
Spring中使用aop
(1)添加jar依赖包
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
(2)添加项目原有的调取过程
(3)创建增强类(本质上就是一个普通类)
前置增强:目标方法运行前调用aop:before
后置增强:在目标方法运行之后调用aop:after-returning(如果出现异常不会调用)
环绕增强:在目标方法之前和之后都会调用aop:around
最终增强:在目标方法运行之后调用aop:after(无论是否出现异常,都会被调用)
异常增强:程序出现异常时执行aop:after-throwing(程序出现异常时执行,而且程序代码中不要处理异常)
(4)添加aop命名空间
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
(5)设置配置文件
环绕增强需要传入切点ProceedingJoinPoint、注意标签顺序注入顺序
切入点方法的定义
表达式匹配:
public * addUser(com.zhq.bean.User):“*”表示匹配所有类型的返回值
public void * (com.zhq.bean.UserDao):“*”表示匹配所有方法名
public void insert (…):“…”表示匹配所有参数个数和类型
*com.zhq.service.*.*(…):匹配com.zhq.service包下所有类的所有方法。
*com.zhq.service…*(…):匹配com.zhq.service包及子包下所有类的所有方法
如何获取切入点信息
通过JoinPoint对象获取信息:
System.out.println("切入点对象:"+jp.getTarget().getClass().getSimpleName());
System.out.println("切入点方法:"+jp.getSignature());
System.out.println("切入点的参数:"+jp.getArgs()[0]); //如果没有参数,就不能通过索引进行访问,有超出下标
特殊的前置增强——>Advisor前置增强实现步骤
1.创建增强类,要求该类实现MethodBeforeAdvice接口
2.修改applicationContext.xml文件
(1)创建增强类对象
(2)定义增强和切入点的关系:
<aop:config>
<!--表达式是被切入的方法的表达式-->
<aop:poincut expression="execution(*biz.impl.*.*(..))" id="mypoint"/>
<aop:advisor advice-ref="增强类对象的id" pointcut-ref="切入点对象的id"/>
</aop:config>
如何获取切入点信息
通过JoinPoint对象获取信息:
System.out.println("切入点对象:"+jp.getTarget().getClass().getSimpleName());
System.out.println("切入点方法:"+jp.getSignature());
System.out.println("切入点的参数:"+jp.getArgs()[0]); //如果没有参数,就不能通过索引进行访问,有超出下标
特殊的前置增强——>Advisor前置增强实现步骤
1.创建增强类,要求该类实现MethodBeforeAdvice接口
2.修改applicationContext.xml文件
(1)创建增强类对象
(2)定义增强和切入点的关系:
<aop:config>
<!--表达式是被切入的方法的表达式-->
<aop:poincut expression="execution(*biz.impl.*.*(..))" id="mypoint"/>
<aop:advisor advice-ref="增强类对象的id" pointcut-ref="切入点对象的id"/>
</aop:config>
使用AspectJ依赖注解开发
使用AspectJ依赖注解开发
spring AOP的注解方式:
-
增强类也需要创建对象(使用@Component)
-
要启动扫描spring注解包的代码:
<context:component-scan base-package="com.xzk"></context:component-scan>
1.除了启动spring的注解之外,还要启动aspectJ的注解方式
<aop:aspectj-autoproxy/>
2.在切面类(增强类)上添加:@Aspect
3.定义一个任意方法**(因为@Pointcut要放在一个方法中)**
@Pointcut("execution(* com.*.*(..))")
public void anyMethod(){}
实例:
@Pointcut("execution(* com.*.*(..))")
public void anyMethod(){}
@Before("anyMethod()")
public void log(JoinPoint){
System.out.println("myAspect....log....before");
}
@Around("anyMethod()")
public void aroundTest(ProceedingJoinPoint pjp){
System.out.println("around...before....");
try {
pjp.proceed();//执行目标方法
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("around...after....");
}
//注解方式中注解的顺序问题
-
没有异常情况下
环绕开始
前置增强开始执行
insert
环绕结束
最终增强
后置增强开始执行
相对顺序固定,注解换位置时不影响结果顺序
-
有异常
前置增强开始执行
insert
最终增强
异常增强
不要使用环绕增强,使用的话,异常增强不执行
aop的应用场景:事务底层实现,日志,权限控制,mybatis中sql绑定,性能检测
Spring-JDBC数据访问
1.使用spring-jdbc操作数据库
使用JdbcTemplate API和使用Spring管理JdbcTemplate
步骤1:引入jar包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
测试:
public void test1() throws Exception {
//TODO 测试jdbcTemplate简单使用
//1.创建c3p0链接池
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/springjdbc");
dataSource.setUser("root");
dataSource.setPassword("111");
//创建jdbcTemplate对象
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
//创建sql语句
String sql = "insert into role (rid , rname ,alias) value (? , ?,?);";
jdbcTemplate.update(sql,"3","visitor","游客");
}
2.Spring管理JdbcTemplate
可以自己在RoleDaoImpl中添加JdbcTemplate变量,如果不自动装载要添加变量的set方法,标准的操作,让RoleDaoImpl继承JdbcDaoSupport
实例:
public class RoleDaoImpl extends JdbcDaoSupport implements RoleDao {
public void save(Role role) {
String sql = "INSERT INTO role (rname,alias) value (?,?) ;";
getJdbcTemplate().update(sql,role.getRname(),role.getAlias());
}
}
配置文件:需要创建数据源和RoleDaoImpl中的JdbcTemplate赋值
Spring事务管理
事务的嵌套->传播行为propagation
事务的传播机制
事务的第一个方面时传播行为(propagation behavior)
当事务方法被另一个事务方法调用时,必须指定事务应该如何传播
规定了事务方法和事务方法发生嵌套调用时事务如何进行传播
Spring定义了七种传播行为:
事务传播行为类型 | 说明 |
---|---|
PROPAGATION_REQUIRED | 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中 |
PROPAGATION_SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务方式执行 |
PROPAGATION_MANDATORY | 使用当前的事务,如果当前没有事务,就抛出异常 |
PROPAGATION_REQUIRED_NEW | 新建事务,如果当前存在事务,把当前事务挂起 |
PROPAGATION_NOT_SUPPORTED | 以非事务方式执行,如果当前存在事务,就把当前事务挂起 |
PROPAGATION_NEVER | 以非事务方式执行,如果当前存在事务,则抛出异常 |
PROPAGATION_NESTED | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作 |
propagtion_nested:
嵌套的事务可以独立于当前事务进行单独地提交或回滚。
如果当前事务不存在,那么其行为与PROPAGATION_REQUIRED一样。
注意各厂商对这种传播行为的支持是有所差异的。可以参考资源管理器的文档来确认它们是否支持嵌 套事务
事务传播行为失效的情况
spring事务是基于代理来实现的,所以:
(1)private、final、static 方法无法被代理,所以添加事务无效
(2)当绕过代理对象, 直接调用添加事务管理的方法时, 事务管理将无法生效。比如直接new出的对 象。
(3)在同一个类下,有2个方法,A、B,A没有事务,B有事务,但是A调用B时,方法B被标记的事务 无效。 究其原因,因为此类的调用对象为代理对象,代理方法A调用真正的被代理方法A后,在被代理 方法A中才会去调用方法B,此时this对象为被代理的对象,所以是不会通知到代理对象,也就变成了第 二种情况,绕过了代理对象。所以无效
事务的实现
Spring XML配置声明事务
- TransactionManager
在不同平台,操作事务的代码各不相同,因此spring提供了一个 TransactionManager 接口:
- DateSourceTransactionManager 用于 JDBC 的事务管理
- HibernateTransactionManager 用于 Hibernate 的事务管理
2 .接口的定义
事务的属性介绍:这里定义了传播行为、隔离级别、超时时间、是否只读
package org.springframework.transaction;
public interface TransactionDefinition {
int PROPAGATION_REQUIRED = 0; //支持当前事务,如果不存在,就新建一个
int PROPAGATION_SUPPORTS = 1; //支持当前事务,如果不存在,就不使用事务
int PROPAGATION_MANDATORY = 2; //支持当前事务,如果不存在,就抛出异常
int PROPAGATION_REQUIRES_NEW = 3;//如果有事务存在,挂起当前事务,创建一个新的事物
int PROPAGATION_NOT_SUPPORTED = 4;//以非事务方式运行,如果有事务存在,挂起当前事务
int PROPAGATION_NEVER = 5;//以非事务方式运行,如果有事务存在,就抛出异常
int PROPAGATION_NESTED = 6;//如果有事务存在,则嵌套事务执行
int ISOLATION_DEFAULT = -1;//默认级别,MYSQL: 默认为REPEATABLE_READ级别
SQLSERVER: 默认为READ_COMMITTED
int ISOLATION_READ_UNCOMMITTED = 1;//读取未提交数据(会出现脏读, 不可重复读) 基本不
使用
int ISOLATION_READ_COMMITTED = 2;//读取已提交数据(会出现不可重复读和幻读)
int ISOLATION_REPEATABLE_READ = 4;//可重复读(会出现幻读)
int ISOLATION_SERIALIZABLE = 8;//串行化
int TIMEOUT_DEFAULT = -1;//默认是-1,不超时,单位是秒
//事务的传播行为
int getPropagationBehavior();
//事务的隔离级别
int getIsolationLevel();
//事务超时时间
int getTimeout();
//是否只读
boolean isReadOnly();
String getName();
}
3.添加tx命名空间
4.添加事务相关配置
修改applicationContext.xml
<!-- 平台事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 传播行为:propagation 不是必须的,默认值是REQUIRED -->
<!-- REQUIRED:如果有事务,则在事务中执行;如果没有事务,则开启一个新的事务 -->
<tx:method name="save*" propagation="REQUIRED" />
<!-- SUPPORTS:如果有事务,则在事务中执行;如果没有事务,则不会开启事务 -->
<tx:method name="find*" propagation="SUPPORTS" read-only="true" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="txPointCut" expression="execution(* com.service.*.*
(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
注解方式实现添加事务
使用@Transactional注解-添加tx命名空间
@Transactional //对业务类进行事务增强的标注
@Service("accountService")
public class AccountServiceImpl implements AccountService {}
配置xml
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--① 对标注@Transactional注解的Bean进行加工处理,以织入事物管理切面 -->
<tx:annotation-driven transaction-manager="transactionManager" />
在默认情况, 中transaction-manager属性会自动使用名为 “transactionManager” 的事务管理器.
所以,如果用户将事务管理器的id定义为 transactionManager , 则可以进一步将①处的配置简化为 .