什么是AOP?
AOP有什么用?
怎么运用AOP ?
相信是很多入门同学普遍存在的疑问,今天我就这些问题对AOP来一个通俗易懂的实操。首先AOP是一种编程思想,中文意思是 面向切面编程和面向对象编程(OOP)是一类。不过这里我不想讲干货,因为太无聊了,直接场景+实操,马上安排。
场景:
使用springboot框架开发的一个项目中,我们想记录用户每个接口请求log。具体log记录什么内容,这里简单设置,只记录请求时间和请求的接口名称。
实操:
1 )首先准备一个基于 Springboot框架的工程,不清楚的同学可以看我上一篇《Springboot入门》。
这里我创建一个工程名称为 lengfeng-03的工程,创建过程和工程目录如下:
2)创建一个简单接口
第一步、创建包,先在src下的主包“com.nc,lengfeng-03”下新增一个 名字为“controller”的包;
第二步、创建类,在“controller”中创建一个名为“MyController”的类;
第三步、添加注解,在类中类名字上方添加注解 @RestContoller ,这样这个类就是一个控制类了;
第四步、创建接口方法,在类中添加一个名字为"myApi01"的方法,返回类型随意,这里为String。
第五步、为接口添加请求标记,在方法上方添加
@RequestMapping(value = "/myapi",method = RequestMethod.GET)
其中"/myapi"为该接口的请求路径,请求方法为GET。
到这里,请求接口已经完成,完整代码如下:
package com.nc.lengfeng03.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; @RestController public class MyController { @RequestMapping(value = "/myapi",method = RequestMethod.GET) public String myApi01() { return "OK"; } }
目录如下:
在浏览器中访问接口结果如下:
3)重点来了,创建一个Aspect类 “LogAspect”
第一步、添加AOP相关依赖,在pom.xml中添加依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
第二步、创建aspect包和创建LogAspect类。
package com.nc.lengfeng03.aspect; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; @Component @Aspect public class LogAspect { @Pointcut("execution(* com.nc.lengfeng03.controller.*.*(..))") /* 第一个“*” 系 任意修饰词和 任意返回类型 第二个“*” 系 该包下的任意类 第三个“*” 系 该包所以类下的任意方法 “(..)” 系 方法的任意参数 */ public void log(){ } /* 开始执行前需要处理的事情 */ @Before("log()") public void before(JoinPoint joinPoint){ System.out.println("------------Before Log----------------"); } /* 执行后需要处理的事情,无论执行成功与失败,相当于finally */ @After(value="log()") public void afterExecution(JoinPoint joinPoint ) { System.out.println("------------After Log----------------"); } /* 正常执行后需要处理的事情 */ @AfterReturning(value="log()") public void afterReturningExecution(JoinPoint joinPoint ) { System.out.println("------------afterReturning Log----------------"); } /* 异常执行后需要处理的事情 */ @AfterThrowing(value="log()") public void afterThrowingExecution(JoinPoint joinPoint) { System.out.println("------------AfterThrowing Log----------------"); } /* 回环通知,贯穿整个执行过程 */ @Around(value = "log()") public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("------------before aroundAdvice Log----------------"); // 在原始方法执行前执行的逻辑 //doSomethingBefore(); try { // 执行原始方法,并捕获返回值 Object result = joinPoint.proceed(); System.out.println("------------After aroundAdvice Log----------------"); // 在原始方法执行后执行的逻辑 // doSomethingAfter(); // 返回原始方法的结果 return result; } catch (Exception e) { // 在原始方法抛出异常时执行的逻辑 System.out.println("------------Exception aroundAdvice Log----------------"); //doSomethingOnException(e); throw e; } finally { // 最终的清理逻辑 System.out.println("------------Finally aroundAdvice Log----------------"); // doFinally(); } } } /* * 执行顺序 *------------before aroundAdvice Log---------------- ------------Before Log---------------- ------------afterReturning Log---------------- ------------After Log---------------- ------------After aroundAdvice Log---------------- ------------Finally aroundAdvice Log---------------- * * */
到这一个Aspect类创建完成了。
重点看,这个切入点配置,意思是在 com.nc.lengfeng03.controller这个包下的所以类和所有方法均会被切入。具体解析如下
@Pointcut("execution(* com.nc.lengfeng03.controller.*.*(..))")
/* 第一个“*” 系 任意修饰词和 任意返回类型
第二个“*” 系 该包下的任意类
第三个“*” 系 该包所以类下的任意方法
“(..)” 系 方法的任意参数 */
4)测试结果
启动程序,在浏览器访问 "http://localhost:8080/myapi"
在Idea输出结果:
结果代表我请求 /myapi接口会执行 LogAAspect。
Before\After \Around的注解自行学习。具体也可以跟进代码注释和自己实操来学习。
5)记录Log
这个时候可以在LogAspect的 对应位置进行写log操作即可(可把log存文档或数据库,这里略)
结语
*AOP编程思想 简化了我们编程代码量:
如上述例子,原本需要再每个请求方法中都要添加写log代码的,现在执行声明一个 切入点(pointCut)就能实现。目标位置不需要任何代码。
*定义一个Acspect类两个注意点
1、添加依赖 spring-boot-starter-aop ,aop的依赖有很多,请认准
2、类上方添加@Aspect注解和@Component注解( Component注解会在项目启动时候把该类注册到spring容器中)
* 建议小白同学可以直接实操代码,从看到的结果中不断去解惑。不要一上来就看原理,看理论。