SpringBoot - 实现AOP与声明式事务

1.实现声明式事务

低版本在启动类(@SpringBootApplication)上加上@EnableTransactionManagement注解

@EnableTransactionManagement注解其实在大多数情况下,不是必须的,因为SpringBoot在
TransactionAutoConfiguration类里为我们自动配置启用了@EnableTransactionManagement注
解。

不过自动启用该注解有两个前提条件,分别是:
@ConditionalOnBean(PlatformTransactionManager.class)和@ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)

而一般情况下,这两个条件都是满足的,所以一般的,我们在启动类上写不写
@EnableTransactionManagement都行。本人这里还是建议写出来。

所以SpringBoot使用声明式事务只需要导入驱动,JDBC连接池,在需要使用事务的业务层类或方法上添加@Transactional注解

 

脏读:一个事务读取到另外一个事务未提交的数据

不可重复读:同一个事务多次读取数据 读取到的结果都是一样的,表示读取不到其它事务已提交的更新数据

可重复读:同一个事务多次读取数据 读取到的结果可能不一样,表示读取不到其它事务已提交的更新数据

幻读:一个事务读取到另外一个事务已提交的插入数据


2.实现AOP

导入AOP start

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

SpringBoot帮我们自动装配了AOP所以我们直接用就行了

@Component
@Aspect/*生成代理对象*/
@Order(0)
public class LogProxy {
    @Pointcut(value="execution(* com.levi..*.*(..))")
    public void pointcut1(){}

    @Before("pointcut1()")
    public void before(){} //方法执行之前执行

    @AfterReturning("pointcut1()")
    public void afterReturning(){} //返回值之后执行,有异常不会执行

    @AfterThrowing("pointcut1()")
    public void afterThrowing(){} //方法异常之后执行

    @After("pointcut1()")
    public void after(){} //方法执行之后,总是执行的

    @Around("pointcut1()")
    public void around(ProceedingJoinPoint pjp){
        System.out.println("方法执行之前执行");
        try{
            pjp.proceed(); //执行方法
            System.out.println("方法执行之后执行");
        }catch(Throwable e){
            System.out.println("异常执行");
        }finally{
            System.out.println("总是执行的");
        }
    }
}

打印日志

AOP 日志:需引入aop-start,lombok或任何一个日志框架

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;

@Aspect
@Component
@Slf4j
public class ProxyLog {
    /** 以 controller 包下定义的所有请求为切入点 */
    @Pointcut("execution(public * com.example.blog.controller..*.*(..))")
    public void webLog() {}

    /**
     * 环绕
     * @param
     * @return
     * @throws Throwable
     */
    @Around("webLog()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        String[] logArray=new String[6];
        Object result=null;
        //记录开始时间
        long startTime = System.currentTimeMillis();
        try{
            //before
            // 开始打印请求日志
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            // 打印请求 url
            logArray[0]=request.getRequestURL().toString();
            // 打印 Http method
            logArray[1]=request.getMethod();
            // 打印请求的 IP
            logArray[2]=request.getRemoteAddr();
            // 打印调用 controller 的全路径以及执行方法
            logArray[3]=pjp.getSignature().getDeclaringTypeName()+"."+pjp.getSignature().getName();
            // 打印请求入参
            logArray[4]=pjp.getArgs().toString();
            //执行方法
            result = pjp.proceed();

            //afterReturning
        }catch (Exception e){
            //afterThrowing

        }finally {
            //after
            // 执行耗时
            logArray[5]=String.valueOf(System.currentTimeMillis() - startTime).toString();
            log.info("\nURL            : {}\nHTTP Method    : {}\nIP             : {}\nClass Method   : {}\nRequest Args   : {}\nTime-Consuming : {} ms\n",
                    logArray[0],logArray[1],logArray[2],logArray[3],logArray[4],logArray[5]);
        }
        return result;
    }
}

可以获取到的参数:JoinPoint,ProceedingJoinPoint

1.Joinpoint:

Signature getSignature():获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的Class等信息

Object[] getArgs();获取传入目标方法的参数对象

Object getTarget();获取被代理的对象(对象的声明类型)

Object getThis();获取代理对象(对象的实例类型)

2.ProceedingJoinpoint:

只能用在around通知里

Object proceed() throws Throwable:执行目标方法

Object proceed(Object[] var1) throws Throwable:传入参数执行目标方法

连接点:可以被增强的方法,切入点:实际被正真增强的方法,通知:实际增强的逻辑部分

posted on 2022-12-27 19:58  Mikasa-Ackerman  阅读(134)  评论(0编辑  收藏  举报

导航