本文主要是介绍Springboot如何正确使用AOP问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
《Springboot如何正确使用AOP问题》:本文主要介绍Springboot如何正确使用AOP问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教...
一、AOP概念
切面(ASPect)
- 一个关注点的模块化,这个关注点可能会横切多个对象。
- 事务管理是J2EE应用中一个关于横切关注点的很好的例子。
- 在Spring AOP中,切面可以使用基于模式或者基于@Aspect注解的方式来实现
连China编程接点(JoinPoint)
在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。在SpringAOP中,一个连接点总是表示一个方法的执行
通知(Advice)
- 在切面的某个特定的连接点上执行的动作。
- 其中包括了Around、Before和After等不同类型的通知。
- 许多AOP框架(包括Spring)都是以拦截器做通知模型,并维护一个以连接点为中心的拦截器链
切入点(PointCut)
- 匹配连接点的断言。
- 通知和一个切入点表达式关联,并在满足这个切入点的连接点上运行(例如,当执行某个特定名称的方法时),切入点表达式如何和连接点匹配是AOP的核心:Spring缺省使用AspectJ切入点语法
引入(Intorduction)
- 用来给一个类型声明额外的方法或属性(也被称为连接类型声明)。
- Spring允许引入新的接口(以及一个对应的实现)到任何被代理的对象。
- 例如,你可以使用引入来使一个bean实现接口,以便简化缓存机制
目标对象(Target Object)
- 被一个或者多个切面所通知的对象。也被称做被通知对象。
- 既然Spring AOP是通过运行时代理实现的,这个对象永远是一个被代理对象
AOP代理(Aop proxy)
- AOP框架创建的对象,用来实现切面契约(例如通知方法执行等等)。
- 在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理
植入(weaving)
- 把切面连接到其它的应用程序类型或者对象上,并创建一个被通知的对象。
- 这些可以在编译时(例如使用AspectJ编js译器),类加载时和运行时完成。
- Spring和其他纯Java AOP框架一样,在运行时完成织入
二、切点表达式
execution表达式
用于匹配方法执行的连接点,属于方法级别
语法:
execution(修饰符 返回值类型 方法名(参数)异常)
语法参数 | 描述 |
---|---|
修饰符 | 可选,如public,protected,写在返回值前,任意修饰符填*号就可以 |
返回值类型 | 必选,可以使用*来代表任意返回值 |
方法名 | 必选,可以用*来代表任意方法 |
参数 | ()代表是没有参数,(..)代表是匹配任意数量,任意类型的参数,当然也可以指定类型的参数进行匹配,如要接受一个String类型的参数,则(java.lang.String), 任意数量的String类型参数:(java.lang.String..) |
异常 | 可选,语法:throws 异常,异常是完整带包名,可以是多个,用逗号分隔 |
符号:
符号 | 描述 |
---|---|
* | 匹配任意字符 |
… | 匹配多个包或者多个参数 |
+ | 表示类及其子类 |
条件符:
符号 | 描述 |
---|---|
&&、and | 与 |
|| | 或 |
! | 非 |
案例
拦截com.gj.web包下的所有子包里的任意类的任意方法
execution(* com.gj.web..*.*(..))
拦截com.gj.web.api.Test2Controller下的任意方法
execution(* com.gj.web.api.Test2Controller.*(..))
拦截任何修饰符为public的方法
execution(public * * (..))
拦截com.gj.web下的所有子包里的以ok开头的方法
execution(* com.gj.web..*.ok*(..))
三、AOP通知
在切面类中需要定义切面方法用于响应响应的目标方法,切面方法即为通知方法,通知方法需要用注解标识,AspectJ支持5种类型的通知注解
注解 | 描述 |
---|---|
@Before | 前置通知, 在方法执行之前执行 |
@After | 后置通知, 在方法执行之后执行 |
@AfterReturn | 返回通知, 在android方法返回结果之后执行 |
@AfterThrowing | 异常通知, 在方法抛出异常之后 |
@Around | 环绕通知,围绕方法的执行 |
@Before
@Before("testCut()") public void cutProcess(JoinPoint joinPoint) { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); System.out.println("注解方式AOP开始拦截, 当前拦截的方法名: " + method.getName()); }
@After
@After("testCut()") public void after(JoinPoint joinPoint) { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); System.out.println("注解方式AOP执行的方法 :"+method.getName()+" 执行完了"); }
@AfterReturn:其中value
表示切点方法,returning
表示返回的结果放到result这个变量中
/** * returning属性指定连接点方法返回的结果放置在result变量中 * @param joinPoint 连接点 * @param result 返回结果 */ @AfterReturning(value = "testCut()",returning = "result") public void afterReturn(JoinPoint joinPoint, Object result) { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); System.out.println("注解方式AOP拦截的方法执行成功, 进入返回通知拦截, 方法名为: "+method.getName()+", 返回结果为: "+result.toString()); }
@AfterThrowing:其中value
表示切点方法,throwing
表示异常放到e这个变量
@AfterThrowing(value = "testCut()", throwing = "e") public void afterThrow(JoinPoint joinPoint, Exception e) { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); System.out.println("注解方式AOP进入方法异常拦截, 方法名为: " + method.getName() + ", 异常信息为: " + e.getMessage()); }
@Around
@Around("testCut()") public Object testCutAround(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("注解方式AOP拦截开始进入环绕通知......."); Object proceed = joinPoint.proceed(); System.out.println("准备退出环绕......"); return proceed; }
四、springboot中使用AOP
导出依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
自定义注解
package com.hl.springbootrunner.aop; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface AOPAnnotations { }
创建切面类
package com.hl.springbootrunner.aop; import org.aspectj.lang.JoinPoint; 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 public class TestAspect { /** * 这里的路径填自定义注解的全路径 */ @Pointcut("@annotation(com.hl.springbootrunner.aop.AOPAnnotations)") public void testCut() { } @Before("testCut()") public void cutProcess(JoinPoint joinPoint) { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); System.out.println("注解方式AOP开始拦截, 当前拦截的方法名: " + method.getName()); } @After("testCut()") public void after(JoinPoint joinPoint) { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); System.out.println("注解方式AOP执行的方法 :" + method.getName() + " 执行完了"); } @Around("testCut()") public Ojsbject testCutAround(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("注解方式AOP拦截开始进入环绕通知......."); Object proceed = joinPoint.proceed(); System.out.println("准备退出环绕......"); return proceed; } /** * returning属性指定连接点方法返回的结果放置在result变量中 * * @param joinPoint 连接点 * @param result 返回结果 */ @AfterReturning(value = "testCut()", returning = "result") public void afterReturn(JoinPoint joinPoint, Object result) { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); System.out.println("注解方式AOP拦截的方法执行成功, 进入返回通知拦截, 方法名为: " + method.getName() + ", 返回结果为: " + result.toString()); } @AfterThrowing(value = "testCut()", throwing = "e") public void afterThrow(JoinPoint joinPoint, Exception e) { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); System.out.println("注解方式AOP进入方法异常拦截, 方法名为: " + method.getName() + ", 异常信息为: " + e.getMessage()); } } php
自定义一个接口
@RestController public class TestController { @GetMapping("/ok") @AOPAnnotations public String test2() { return "ok"; } }
测试
总结
这篇关于Springboot如何正确使用AOP问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!