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 阅读(182) 评论(0) 编辑 收藏 举报