day14SpringBootWeb事务&AOP 8.7

本文围绕Spring Boot Web事务与AOP展开。介绍了Spring事务管理,包括@Transactional注解的使用、事务进阶配置及事务传播行为。还阐述了AOP基础,如面向切面编程概念、执行流程、核心概念,包括通知类型、执行顺序、切点表达式和链接点等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

day14SpringBootWeb事务&AOP 8.7

  1. Spring事务管理

@Transactionl   (service层的方法上、类上、接口上)(增删改)

作用:成功自动提交,失败自动回滚

配置文件中写(固定的)

logging:

  level:

    org.springframework.jdbc.support.JdbcTransactionManager: debug

  1. 事务进阶

@TransactionlrollerbackFor=Exception.class)//加了,所有异常都回滚

(默认只有出现 RuntimeException(运行异常) 才回滚异常。而如果出现编译时异常,则不回滚。)

Propagation:(事务传播行为:指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行事务控制。)

@Transactional(propagation=Propagation.属性值)

属性值

含义

说明

REQUIRE

【默认值】需要事务,有则加入,无则创建新事务

大部分情况下都是用该传播行为即可

REQUIRE_NEW

需要新事务,无论有无,总是创建新事务

在被调用的方法上添加(如下订单,不论成功与否,都要保证日志成功记录)

SUPPORTS

支持事务,有则加入,无则在独立的连接中运行 SQL

结合 Hibernate、JPA  时有用,配在查询方法上

NOT_SUPPORTED

不支持事务,不加入,在独立的连接中运行 SQL

MANDATORY

必须有事务,否则抛异常

NEVER

必须有事务,否则抛异常

NESTED

嵌套事务

仅对DataSourceTransactionManager有效

AOP基础:Aspect Oriented Programming(面向切面编程),将重复的逻辑剥离出来,在不修改原始逻辑的基础上对原始功能进行增强或改变

  1. pom.xml中引入依赖

 <dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-aop</artifactId>

</dependency>

2.定义类抽取公共代码,标识当前类是一个AOP类,并被Spring容器管理,配置公共代码作用于哪些目标方法(切面类

@Component  //被IOC容器管理

@Aspect     //标识为AOP类

@Slf4j   //日志

public class TimeAspect {

    @Around("execution(* com.itheima.service.impl.DeptServiceImpl.*(..))")//切入点表达式,所作用的位置,改位置的方法每一执行,此AOP文件也执行

    public Object recordTime(ProceedingJoinPoint joinPoint) throws Throwable {//运行joinPoint.proceed()方法可能有异常所以抛

        long begin = System.currentTimeMillis();//记录方法运行开始的时间

        Object result = joinPoint.proceed(); //调用原始操作

        long end = System.currentTimeMillis();//记录方法运行结束的时间

        log.info("执行耗时 : {} ms", (end-begin));//日志信息显示:

        return result; } }

执行流程:

当目标对象(ServiceImpl实现类)功能需要被增强时,并且我们使用AOP方式定义了增强逻辑(在Aspect类中)

Spring会为目标对象自动生成一个代理对象,并在代理对象对应方法中,结合我们定义的AOP增强逻辑完成功能增强

AOP核心概念

●  连接点:JoinPoint,可以被AOP控制的方法执行(包含方法信息)

●  通知:Advice ,重复逻辑代码

●  切入点:PointCut ,匹配连接点的条件

●  切面:Aspect,通知+切点

●  目标对象:Target,通知所应用的对象

通知类型

@Around:

此注解标注的通知方法在目标方法前、后都被执行

@Before:

此注解标注的通知方法在目标方法被执行

@After

此注解标注的通知方法在目标方法被执行,无论是否有异常

@AfterReturning

此注解标注的通知方法在目标方法被执行,有异常不会执行

@AfterThrowing

此注解标注的通知方法发生异常后执行

可将切入点表达式保证成一个方法(若设成公共的,其他类也可以使用)

@Pointcut(“execution(com.各级包名....ServiceImpl.*(..))”)

Public void 方法名(){}

在需要的AOP方法上写 :@通知类型(“方法名()”)

通知执行顺序:默认按照切面类的名称字母排序

在AOP类上加注解:@Order(数字)排序(数字小的先执行)

切点表达式:execution主要根据方法的返回值、包名、类名、方法名、方法参数等信息来匹配

execution(访问修饰符?  返回值  包名.类名?.方法名(方法参数) throws 异常?)

访问修饰符:

包名.类名:

throws 异常:

可省略(没啥用,仅能匹配 public、protected、包级,private 不能增强)

可省略

可省略(注意是方法上声明抛出的异常,不是实际抛出的异常)

*  :单个独立的任意符合,可以统配任意返回值,包名,类名,方法名,任意类型的一个参数,也可以统配包,类,方法名的一部分

execution( *com.*.service.*.updat*(*))

..  :多个连续的任意符号,可以统配任意层级的包,或任意类型,任意个数的参数

Execution(*com.itheima..DeptService.*(..))

根据业务需要,可以使用 &&  ||  ! 来组合比较复杂的切入点表示式

包名和类名不建议省略  @Pointcut(“executino(* *(..))”)  最统配的写法

@annotation (注解全类名)

1.(创建一个Annotationl类,注解名自定义)

2.在创建的注解上加@Retention(RetentionPolicay.RUTIME)//什么时间生效:运行时

                  @Target(ElementType.METHOD)  //生效的位置:方法上

3.在需要的方法名上加  @创建的注解名

4.改造切点表达式:Pointcut(@annotation(com.itheima.aop.创建的注解名))   //(注解的位置)

链接点:是目标方法,在Spring 中用 JoinPoint 抽象了连接点,用它可以获得方法执行时的相关信息,如方法名、方法参数类型、方法实际参数等等

对于 @Around 通知,获取连接点信息只能使用 ProceedingJoinPoint

对于其他四种通知,获取连接点信息只能使用 JoinPoint,是 ProceedingJoinPoint 的父类型

public void 方法名(JoinPoint joinPoint){

//获取目标对象的类名

String className =joinPoint.getTarget().getClass().getName();

 //获取目标方法名

String methodName =joinPoint.getSignature().getName();

//获取目标方法运算时传入的参数,是一个数数组,输出时有Arrays.toString(args)

//一种输出写法:Arrays.asList(joinPoint.getArgs()).toString()

Object[] args =joinPoint.getArgs();    

//获取返回值

Object result=joinPoint.proceed();//调用方法运行

//在日志中显示

Log.info(“内容”)      }}

实例:

1.在数据库中创建一个表,来存放日志信息 和对应信息的pojo类

  1. 创建AOP类,和注解类
  2. 切点表达式  (在需要的方法上加@注解名)
  3. @Component
  4. @Aspect
  5. public class LogAspect {
  6.     @Autowired
  7.     private OperateLogMapper operateLogMapper;//..Mapper对象
  8.     @Autowired
  9.     private HttpServletRequest request;//Request对象
  10.     @Around("@annotation(com.itheima.anno.Log)")
  11.     public Object recordLog(ProceedingJoinPoint joinPoint) throws Throwable {
  12.         long begin = System.currentTimeMillis(); //记录开始时间
  13.         String token = request.getHeader("token");//获取令牌对象
  14.         Integer operateUser  = (Integer) JwtUtils.parseJWT(token).get("id");//令牌中的Id,并强转
  15.         String className = joinPoint.getTarget().getClass().getName(); //操作类名
  16.         String methodName = joinPoint.getSignature().getName(); //操作方法名
  17.         Object[] args = joinPoint.getArgs();//一个参数数组
  18.         String methodParams = Arrays.toString(args); //操作方法参数
  19.         Object result = joinPoint.proceed(); //放行原始方式,返回值
  20.         String returnValue = JSONObject.toJSONString(result);//转化为Json对象
  21.         long end = System.currentTimeMillis(); //记录结束时间
  22.         long costTime = end - begin;//计算运算时间
  23.         OperateLog operateLog = new OperateLog(null,operateUser, LocalDateTime.now(),className,methodName,methodParams,returnValue,costTime);//封装成对应的pojod对象,此次为OPerateLog
  24.         operateLogMapper.insert(log);//添加进数据库表格
  25.         log.info(“”)   //在日志中输出
  26.         return result;  //返回值     }

around先执行原始方法前的代码,在运行原始代码,在运行原始代码后的代码

获取当前登录用户:获取request对象,从请求头中获取jwt令牌,解析令牌获取出当前用户的id

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值