• Spring AOP及事务配置三种模式详解


    Spring AOP简述

    Spring AOP的设计思想,就是通过动态代理,在运行期对需要使用的业务逻辑方法进行增强。

    使用场景如:日志打印、权限、事务控制等。

    默认情况下,Spring会根据被代理的对象是否实现接口来选择使用JDK还是CGLIB。当被代理对象没有实现接口时,Spring会选择CGLIB。当实现了接口,Spring会选择JDK官方的代理技术,不过我们也可以通过配置的方式,让Spring强制使用CGLIB。

    配置方式有两种:

    • 使⽤aop:config标签配置
    <aop:config proxy-target-class="true">
    
    • 使⽤aop:aspectj-autoproxy标签配置
    <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-
    autoproxy>
    

    Spring中AOP的实现

    2.1 XML模式

    1. 引入依赖(如果项目里没有的话)
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>5.1.12.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.4</version>
    </dependency>
    
    1. xml配置

    主要看下面的aop部分

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xmlns:tx="http://www.springframework.org/schema/tx"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
           https://www.springframework.org/schema/context/spring-context.xsd
           http://www.springframework.org/schema/tx
           https://www.springframework.org/schema/tx/spring-tx.xsd
             http://www.springframework.org/schema/aop
           https://www.springframework.org/schema/aop/spring-aop.xsd
    ">
    

    xml相关切面配置

    <bean id="logUtil" class="com.mmc.ioc.utils.LogUtil"></bean>
    
        <!--aop的配置-->
           <!--aop的配置-->
        <aop:config>
            <!--配置切面-->
            <aop:aspect id="logAdvice" ref="logUtil">
                <aop:pointcut id="logAspect" expression="execution(public * com.mmc.ioc.service.impl.TransferServiceImpl.transfer(..))"></aop:pointcut>
    
                <!--前置通知-->
                <aop:before method="printLog" pointcut-ref="logAspect"></aop:before>
                <!--后置通知,无论业务是否正常执行-->
                <aop:after method="after" pointcut-ref="logAspect"></aop:after>
                <!--正常执行-->
                <aop:after-returning method="afterReturn" pointcut-ref="logAspect"></aop:after-returning>
                <!--异常执行-->
                <aop:after-throwing method="afterException" pointcut-ref="logAspect"></aop:after-throwing>
                <!--环绕通知-->
                <!--<aop:around method="around" pointcut-ref="logAspect" arg-names="proceedingJoinPoint"></aop:around>-->
            </aop:aspect>
        </aop:config>
    
    

    环绕通知可以实现上面的4种通知,并且可以控制业务方法是否执行。通过如下代码控制:

     proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
    
    public class LogUtil {
    
        public void printLog(){
            System.out.println("打印日志");
        }
    
        public void after(){
            System.out.println("后日志打印,不管业务是否正常");
        }
    
        public void afterReturn(){
            System.out.println("正常执行完毕打印日志");
        }
    
        public void afterException(){
            System.out.println("异常执行打印日志");
        }
    
        public void around(ProceedingJoinPoint proceedingJoinPoint){
            System.out.println("环绕前置");
            try {
                Object result = proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
                System.out.println("环绕正常执行");
            } catch (Throwable throwable) {
                throwable.printStackTrace();
                System.out.println("环绕异常执行");
            }
        }
    }
    
    1. 切入点表达式

    举例:

    public void
    com.lagou.service.impl.TransferServiceImpl.updateAccountByCardNo(c
    om.lagou.pojo.Account)
    
    • 访问修饰符可以省略,也就是public可以不用写
    void com.mmc.ioc.service.impl.TransferServiceImpl.transfer(String,String,int)
    
    • 返回值可以用*代替,表示返回任意值
    * com.mmc.ioc.service.impl.TransferServiceImpl.transfer(String,String,int)
    
    • 包名可以使用..表示当前包及其子包
    * com..TransferServiceImpl.transfer(String,String,int)
    
    • 类名和方法名,都可以使用*表示任意类,任意方法
    * com..*(String,String,int))
    
    • 参数列表,如果是基本类型可以直接写名称,如int。引用类型必须用全限定名称
    • 参数列表可以使用*代替任意参数类型,但必须有参数
    * com..*(*)
    
    • 参数列表可以使用..代替任意参数类型,有无参数均可
    * com..*(*)
    
    • 全通配方式:
    * *..*.*(..)
    

    2.2 XML+注解模式

    1. XML中开启Spring对注解AOP的支持
    <!--开启spring对注解aop的⽀持-->
    <aop:aspectj-autoproxy/>
    
    1. 注解配置
    @Component
    @Aspect
    public class LogUtil {
    
        @Pointcut("execution(* com.mmc.ioc.service.impl.TransferServiceImpl.transfer(..))")
        public void pointcut(){}
    
        @Before("pointcut()")
        public void printLog(){
            System.out.println("打印日志");
        }
    
        @After("pointcut()")
        public void after(){
            System.out.println("后日志打印,不管业务是否正常");
        }
    
        @AfterReturning("pointcut()")
        public void afterReturn(){
            System.out.println("正常执行完毕打印日志");
        }
    
        @AfterThrowing("pointcut()")
        public void afterException(){
            System.out.println("异常执行打印日志");
        }
    
    //    @Around("pointcut()")
        public void around(ProceedingJoinPoint proceedingJoinPoint){
            System.out.println("环绕前置");
            try {
                Object result = proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
                System.out.println("环绕正常执行");
            } catch (Throwable throwable) {
                throwable.printStackTrace();
                System.out.println("环绕异常执行");
            }
        }
    }
    

    2.3 纯注解模式

    只需要用注解@EnableAspectJAutoProxy替换掉

    <aop:aspectj-autoproxy/>
    

    Spring事务配置

    也分为3种模式

    3.1 XML模式

    1. 引入pom依赖
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.1.12.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.4</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.1.12.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>5.1.12.RELEASE</version>
    </dependency>
    
    1. xml配置
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
        </bean>
        <tx:advice id="txAdice" transaction-manager="transactionManager">
            <!--定制事务细节-->
            <tx:attributes>
                <tx:method name="*" read-only="false" propagation="REQUIRED" isolation="DEFAULT"/>
                <tx:method name="query*" read-only="true" propagation="SUPPORTS"></tx:method>
            </tx:attributes>
        </tx:advice>
    
        <!--事务衡器逻辑-->
        <aop:config>
            <aop:advisor advice-ref="txAdice" pointcut="execution(* com.mmc.ioc.service.impl.TransferServiceImpl.transfer(..))"></aop:advisor>
        </aop:config>
    

    3.2 基于XML+注解

    1. xml配置:
     <!--spring声明式事务配置-->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
        </bean>
        
        <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
    
    1. 在类或方法上面添加@Transactional注解
    @Transactional(readOnly = true,propagation = Propagation.SUPPORTS)
    

    3.3 纯注解

    用@EnableTransactionManagement 注解替换掉

     <tx:annotation-driven transaction-
    manager="transactionManager"/> 
    

    即可

    书山有路勤为径,学海无涯苦作舟
  • 相关阅读:
    最全Pycharm教程
    Django系列:(1)PyCharm下创建并运行我们的第一个Django工程
    用pycharm+django开发web项目
    python在不同层级目录import模块的方法
    Android GetTimeAgo(时间戳转换几天前,几分钟前,刚刚等)
    Fresco简单的使用—SimpleDraweeView
    django常用命令
    Android 浅谈 RxAndroid + Retrofit + Databinding
    云计算之路-阿里云上:负载均衡从七层换成四层后的意外发现团队
    云计算之路-阿里云上:因为网络问题,物理机换回虚拟机团队
  • 原文地址:https://www.cnblogs.com/javammc/p/15569761.html
Copyright © 2020-2023  润新知