.
3ss.cn

如何通过AOP环绕通知实现事务控制

1、导入相关的依赖

<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
 <groupId>c3p0</groupId>
 <artifactId>c3p0</artifactId>
 <version>0.9.1.2</version>
 </dependency>
 <dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.7</version>
</dependency>
</dependencies>

2、配置连接池和开启AOP注解

以下采用的是xml配置方式,当然也可以使用纯注解配置

<!-- 配置数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!--连接数据库的必备信息-->
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>
<property name="user" value="root"></property>
<property name="password" value="root"></property>
</bean>
<!--开启spring对注解AOP的支持-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

2、创建链接工具类

package com.gzl.utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
import java.sql.Connection;
/**
 * 连接的工具类,它用于从数据源中获取一个连接,并且实现和线程的绑定
 */
@Component("connectionUtils")
public class ConnectionUtils {
private ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
@Autowired
private DataSource dataSource;
/**
 * 获取当前线程上的连接
 * @return
 */
public Connection getThreadConnection() {
try{
//1.先从ThreadLocal上获取
Connection conn = tl.get();
//2.判断当前线程上是否有连接
if (conn == null) {
//3.从数据源中获取一个连接,并且存入ThreadLocal中
conn = dataSource.getConnection();
tl.set(conn);
}
//4.返回当前线程上的连接
return conn;
}catch (Exception e){
throw new RuntimeException(e);
}
}
/**
 * 把连接和线程解绑
 */
public void removeConnection(){
tl.remove();
}
}

3、AOP环绕事务类

package com.gzl.utils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
 * 和事务管理相关的工具类,它包含了,开启事务,提交事务,回滚事务和释放连接
 */
@Component("txManager")
@Aspect
public class TransactionManager {
@Autowired
private ConnectionUtils connectionUtils;
/**
 * 需要进行事务控制的类或者方法,EL表达式配置
 */
@Pointcut("execution(* com.gzl.service.impl.*.*(..))")
private void pt1(){}
/**
 * 开启事务
 */
publicvoid beginTransaction(){
try {
connectionUtils.getThreadConnection().setAutoCommit(false);
}catch (Exception e){
e.printStackTrace();
}
}
/**
 * 提交事务
 */
publicvoid commit(){
try {
connectionUtils.getThreadConnection().commit();
}catch (Exception e){
e.printStackTrace();
}
}
/**
 * 回滚事务
 */
publicvoid rollback(){
try {
connectionUtils.getThreadConnection().rollback();
}catch (Exception e){
e.printStackTrace();
}
}
/**
 * 释放连接
 */
publicvoid release(){
try {
connectionUtils.getThreadConnection().close();//还回连接池中
connectionUtils.removeConnection();
}catch (Exception e){
e.printStackTrace();
}
}
@Around("pt1()")
public Object aroundAdvice(ProceedingJoinPoint pjp){
Object rtValue = null;
try {
//1.获取参数
Object[] args = pjp.getArgs();
//2.开启事务
this.beginTransaction();
//3.执行方法
rtValue = pjp.proceed(args);
//4.提交事务
this.commit();
//返回结果
returnrtValue;
}catch (Throwable e){
//5.回滚事务
this.rollback();
throw new RuntimeException(e);
}finally {
//6.释放资源
this.release();
}
}
}

spring AOP 环绕通知的思路

环绕通知Around Advice就是在指定的程序前后均执行相关的服务,设计思路如下:

1、设计一个接口

package com.spring.service;
public interface IComponent { 
public void bussiness1();
public void bussiness2();
public void bussiness3();
}

2、编写这个接口的实现

package com.spring.service;
public class Component implements IComponent{
 @Override
 public void bussiness1() {
// TODO Auto-generated method stub
System.out.println("这是业务1");
 }
 @Override
 public void bussiness2() {
// TODO Auto-generated method stub
System.out.println("这是业务2");
 }
 @Override
 public void bussiness3() {
// TODO Auto-generated method stub
System.out.println("这是业务3");
 }
}

3、编写前置通知的逻辑代码

该代码必须实现org.aopalliance.intercept.Method Interceptor接口,需要的服务都写在这里。

4、编写XML配置文件

通过代理来实现AOP的环绕通知,看一下org.aopalliance.intercept.MethodInterceptor接口的源代码。该接口不是Spring内部的接口,而是AOP Alliance标准所指定的,不过Spring对这个接口有一个具体的实现过程,同时该接口相融所有遵守AOP Alliance标准的所有AOP框架。

环绕通知相当于前置通知和后置通知的结合,不同的是在MethodInterceptor的invoke()方法中,可以自由地使用MethodInvocation提供的proceed()方法来执行目标对象的方法,同时proceed()方法将会返回目标方法执行后的返回结果,在invoke方法结束前还可以修改该结果,下面还是以上面的那个例子来示范一下环绕通知的应用。

编写一个环绕通知的类,该类实现MethodInterceptor接口。这里调用了MethodInvocation的proceed()方法,也就是说,调用了目标对象Component中的business1等方法,在这个方法的前后分别增加了验证和通知执行,接着修改一下配置文件,去掉前置通知和后置通知的配置,只需要将这个环绕通知添加进去就可以了,具体代码如下:

这里只需要配置一个环绕通知的Bean,并且将这个Bean配置到interceptorNames中就完成了所有的工作,测试代码与前面的相同,可以看到结果也与前面的相同。

赞(0)
未经允许不得转载:互联学术 » 如何通过AOP环绕通知实现事务控制

评论 抢沙发