欢迎您访问365答案网,请分享给你的朋友!
生活常识 学习资料

SpringAOP的使用完整代码实现-

时间:2023-07-11

此处做个简单的记录(部分知识点+代码实现)

一:AOP的部分知识点

1、什么是AOP
AOP是面向切面编程,简单来说就是将某些重复出现的内容拎出来复用,抽取出来的这部分功能就是一个切面,在方法需要用到这个切面功能的时候,使⽤代理技术对⽅法进⾏增强。可用于日志记录
2、AOP动态代理的两种方式:
CGLIB动态代理 + JDK动态代理(实现接口)
根据类是否实现接⼝来判断动态代理⽅式:
如果实现接⼝会使⽤ JDK 的动态代理,JDK动态代理通过反射来接收被代理的类,核⼼是 InvocationHandler 接⼝和 Proxy 类。
如果没有实现接⼝会使⽤ CGLib 动态代理,CGLib 是在运⾏时动 态⽣成某个类的⼦类,如果某个类被标记为 fifinal,不能使⽤ CGLib 。

3、AOP的重要术语:(比较书面化,自己玩下代码更容易理解)
Aspect :切⾯。多个类的通用行为封装成可重用的模块,该模块含有一组API提供横切功能。Aspect由PointCut和Advice组成
Joinpoint :连接点,程序执⾏过程中的某⼀⾏为,即业务层中的所有⽅法。
Advice :通知,包括前置通知、后置通知、返回后通知、异常 通知和环绕通知。
Pointcut :切⼊点,指被拦截的连接点,切⼊点⼀定是连接点,但连接点不⼀定是切⼊点。
Proxy :代理,Spring AOP 中有 JDK 动态代理和 CGLib 代理,⽬标对象实现了接⼝时采⽤ JDK 动态代 理,反之采⽤ CGLib 代理。
Target :代理的⽬标对象,指⼀个或多个切⾯所通知的对象。
Weaving :织⼊,指把增强应⽤到⽬标对象来创建代理对象的过程。

二、AOP的使用

可以在网盘取代码:
链接:https://pan.baidu.com/s/1NoioAoSdU8agTUve7QYUmQ
提取码:1234

1、Spring AOP与自定义注解Annotation的使用

简单实现其实就三个类:
a、声明一个切面类
b、声明一个注解。@interface
c、然后就可以使用了,声明一个controller 进行测试就行了

(1)声明一个切面类: AopLogAspect

package cn.hsa.ips.admin.annotation;import cn.hutool.json.JSONUtil;import lombok.extern.slf4j.Slf4j;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.*;import org.aspectj.lang.reflect.MethodSignature;import org.springframework.stereotype.Component;import java.lang.reflect.Method;@Aspect@Component@Slf4jpublic class AopLogAspect { //切点表达式,表示加了ApiLog注解的都是切点,路径是自定义注解的全路径 @Pointcut("@annotation(ApiLog)") public void pointcut() { } @Before("pointcut()") public void checkBefore() { log.info("我是前置通知===========>");// System.out.println("我是前置通知===========>"); } @Around("@annotation(apiLog)") public Object logAround(ProceedingJoinPoint joinPoint, ApiLog apiLog) { //获取执行方法的类的名称(包名加类名) String className = joinPoint.getTarget().getClass().getName(); //获取实例 MethodSignature signature = (MethodSignature) joinPoint.getSignature(); //获取方法 Method method = signature.getMethod(); //获取方法名 String methodName = method.getName(); //获取入参 Object[] args = joinPoint.getArgs(); //转换json String argsJsonStr = JSONUtil.toJsonStr(args); //获取当前时间 long start = System.currentTimeMillis(); //2、执行方法获取返回值 try { Object proceed = joinPoint.proceed(); //计算耗时 long costTime = System.currentTimeMillis() - start; //请求参数打印 if (apiLog.params()){ log.info("{}方法请求参数 ===> {}", methodName, argsJsonStr); } if (apiLog.cost()) { //打印耗时 log.info("{}方法执行耗时 ===> {}ms", methodName, costTime); } //转换json String proceedJsonStr = JSONUtil.toJsonStr(proceed); //打印回参 if (apiLog.result()) { log.info("{}方法返回参数 ===> {}", methodName, proceedJsonStr); } //此处可以保存方法日志信息:方法名称,入参,回参,耗时等 log.info("{}方法保存日志信息 ===> {}", methodName,"保存成功"); } catch (Throwable throwable) { throwable.printStackTrace(); } return true; } @After("pointcut()") public void checkAfter() { log.info("我是后置通知===========>"); }}

(2)声明一个自定义注解:
注解里面的属性可以根据需要自定义:下面的值在切面中并没有完全用到

package cn.hsa.ips.admin.annotation;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;import java.lang.annotation.*;@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@documentedpublic @interface ApiLog { String business() default ""; String module() default ""; boolean params() default true; boolean result() default true; boolean cost() default false; boolean exception() default true; long slow() default -1;}

(3)声明一个controller ,使用自定义注解。

package cn.hsa.ips.admin.annotation;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping(value = "/test")public class OperationLogController { @RequestMapping(value = "/add", method = RequestMethod.POST) @ApiLog(business = "测试业务", module = "某个模块", cost = true) public Object recordLogOfAop(@RequestBody String user, String content) { return "AOP+Annotation自定义注解测试回参"; }}

(4)执行结果:

2、AOP的第二个使用实例(用测试类)

a、定义一个业务逻辑类:定义里面的方法逻辑等。
b、定义一个切面类:定义这个切面做什么功能。Pointcut(切点)+Advice (通知:前置通知,后置通知等等)
c、给目标方法标志何时何地运行。
d、Bean注入,切面类和业务逻辑类(目标方法所在类)都加入到容器中
e、测试

(1)定义一个业务逻辑类:定义里面的方法逻辑等。

package cn.hsa.AOP.test;public class MathCalculator { public int testMethod(int i, int j) { System.out.println("testMethod入参 >> div"); return i + j; }}

(2)定义一个切面类
定义这个切面做什么功能。Pointcut(切点)+Advice (通知:前置通知,后置通知等等)

package cn.hsa.AOP.test;import java.util.Arrays;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.annotation.After;import org.aspectj.lang.annotation.AfterReturning;import org.aspectj.lang.annotation.AfterThrowing;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.aspectj.lang.annotation.Pointcut;@Aspectpublic class LogAspects {//抽取公共的切入点表达式@Pointcut("execution(public int MathCalculator.*(..))")private void pointCut(){};//JoinPoint一定要出现在参数列表的第一位@Before(value = "cn.hsa.AOP.test.LogAspects.pointCut()")public void logStart(JoinPoint joinpoint) {System.out.println("我是前置通知>>>>"+joinpoint.getSignature().getName()+">>>>"+Arrays.toString(joinpoint.getArgs()));}@After(value ="cn.hsa.AOP.test.LogAspects.pointCut()")public void logEnd(JoinPoint joinpoint) {System.out.println("我是后置通知>>>>>"+joinpoint.getSignature().getName()+">>>>"+Arrays.toString(joinpoint.getArgs()));}@AfterReturning(value ="execution(public int MathCalculator.*(..))",returning="object")public void logReturn(Object object) {System.out.println("logReturn>>>>"+object);}@AfterThrowing(value = "execution(public int MathCalculator.*(..))",throwing = "object")public void logException(Exception object) {System.out.println("logException>>>>"+object);}}

(3)Bean注入,将切面类和业务逻辑类(目标方法所在类)都加入到容器中

package cn.hsa.AOP.test;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.EnableAspectJAutoProxy;@EnableAspectJAutoProxy@Configurationpublic class ApiLogOfAop { //业务逻辑类加入到容器中 @Bean public MathCalculator mathCalculator() { System.out.println("mathCalculator bean"); return new MathCalculator(); } //切面类加入到容器中 @Bean public AopLogAspect aopLogAspect() { return new AopLogAspect(); }}

(4)测试

package cn.hsa.AOP.test;import lombok.extern.slf4j.Slf4j;import org.springframework.context.annotation.AnnotationConfigApplicationContext;import org.springframework.stereotype.Component;@Slf4j@Componentpublic class AopTest1 { public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ApiLogOfAop.class); MathCalculator mathCalculator = applicationContext.getBean(MathCalculator.class); mathCalculator.testMethod(1, 1); applicationContext.close(); }}

(5)结果

Copyright © 2016-2020 www.365daan.com All Rights Reserved. 365答案网 版权所有 备案号:

部分内容来自互联网,版权归原作者所有,如有冒犯请联系我们,我们将在三个工作时内妥善处理。