好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

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

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

1、导入相关的依赖

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

< 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配置方式,当然也可以使用纯注解配置

?

1

2

3

4

5

6

7

8

9

10

<!-- 配置数据源 -->

< 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、创建链接工具类

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

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环绕事务类

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

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(){}

     /**

      * 开启事务

      */

     public   void beginTransaction(){

         try {

             connectionUtils.getThreadConnection().setAutoCommit( false );

         } catch (Exception e){

             e.printStackTrace();

         }

     }

     /**

      * 提交事务

      */

     public   void commit(){

         try {

             connectionUtils.getThreadConnection().commit();

         } catch (Exception e){

             e.printStackTrace();

         }

     }

     /**

      * 回滚事务

      */

     public   void rollback(){

         try {

             connectionUtils.getThreadConnection().rollback();

         } catch (Exception e){

             e.printStackTrace();

         }

     }

     /**

      * 释放连接

      */

     public   void 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();

             //返回结果

             return   rtValue;

         } catch (Throwable e){

             //5.回滚事务

             this .rollback();

             throw new RuntimeException(e);

         } finally {

             //6.释放资源

             this .release();

         }

     }

}

spring AOP 环绕通知的思路

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

1、设计一个接口

?

1

2

3

4

5

6

package com.spring.service;

public interface IComponent {

public void bussiness1();

public void bussiness2();

public void bussiness3();

}

2、编写这个接口的实现

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

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中就完成了所有的工作,测试代码与前面的相同,可以看到结果也与前面的相同。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。

原文链接:https://blog.csdn.net/weixin_43888891/article/details/109323679

查看更多关于通过AOP环绕通知如何实现事务控制的详细内容...

  阅读:16次