一.spring aop基本信息
AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
在spring AOP中业务逻辑仅仅只关注业务本身,将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。
@Aspect:作用是把当前类标识为一个切面供容器读取 @Pointcut:Pointcut是植入Advice的触发条件。每个Pointcut的定义包括2部分,一是表达式,二是方法签名。方法签名必须是 public及void型。可以将Pointcut中的方法看作是一个被Advice引用的助记符,因为表达式不直观,因此我们可以通过方法签名的方式为 此表达式命名。因此Pointcut中的方法只需要方法签名,而不需要在方法体内编写实际代码。 @Around:环绕增强,相当于MethodInterceptor @AfterReturning:后置增强,相当于AfterReturningAdvice,方法正常退出时执行 @Before:标识一个前置增强方法,相当于BeforeAdvice的功能,相似功能的还有 @AfterThrowing:异常抛出增强,相当于ThrowsAdvice @After: final增强,不管是抛出异常或者正常退出都会执行
二.使用方法
添加 PointCut类
该pointcut用来拦截test包下的所有类中的所有方法。
package test; import org.aspectj.lang.annotation.Pointcut; public class PointCuts { @Pointcut(value = "within(test.*)") public void aopDemo() { } }
添加Aspect类
该类中的advice将会用到上面的pointcut,使用方法请看各个advice的value属性。
package test; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; @Component @Aspect public class Aspect1 { @Before(value = "test.PointCuts.aopDemo()") public void before(JoinPoint joinPoint) { System.out.println("[Aspect1] before advise"); } @Around(value = "test.PointCuts.aopDemo()") public void around(ProceedingJoinPoint pjp) throws Throwable{ System.out.println("[Aspect1] around advise 1"); pjp.proceed(); System.out.println("[Aspect1] around advise2"); } @AfterReturning(value = "test.PointCuts.aopDemo()") public void afterReturning(JoinPoint joinPoint) { System.out.println("[Aspect1] afterReturning advise"); } @AfterThrowing(value = "test.PointCuts.aopDemo()") public void afterThrowing(JoinPoint joinPoint) { System.out.println("[Aspect1] afterThrowing advise"); } @After(value = "test.PointCuts.aopDemo()") public void after(JoinPoint joinPoint) { System.out.println("[Aspect1] after advise"); } }
添加测试用Controller
添加一个用于测试的controller,这个controller中只有一个方法,但是它会根据参数值的不同,会作出不同的处理:一种是正常返回一个对象,一种是抛出异常(因为我们要测试@AfterThrowing这个advice)
package test; import test.exception.TestException; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping(value = "/aop") public class AopTestController { @ResponseStatus(HttpStatus.OK) @RequestMapping(value = "/test", method = RequestMethod.GET) public Result test(@RequestParam boolean throwException) { // case 1 if (throwException) { System.out.println("throw an exception"); throw new TestException("mock a server exception"); } // case 2 System.out.println("test OK"); return new Result() {{ this.setId(111); this.setName("mock a Result"); }}; } public static class Result { private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } } }
测试 正常情况
在浏览器直接输入以下的URL,回车:
http://192.168.142.8:7070/aoptest/v1/aop/test?throwException=false
我们会看到输出的结果是:
[Aspect1] around advise 1 [Aspect1] before advise test OK [Aspect1] around advise2 [Aspect1] after advise [Aspect1] afterReturning advise
测试 异常情况
在浏览器中直接输入以下的URL,回车:
http://192.168.142.8:7070/aoptest/v1/aop/test?throwException=true
我们会看到输出的结果是:
[Aspect1] around advise 1 [Aspect1] before advise throw an exception [Aspect1] after advise [Aspect1] afterThrowing advise
三.JoinPoint 简要api文档
AspectJ使用org.aspectj.lang.JoinPoint接口表示目标类连接点对象,如果是环绕增强时,使用org.aspectj.lang.ProceedingJoinPoint表示连接点对象,该类是JoinPoint的子接口。任何一个增强方法都可以通过将第一个入参声明为JoinPoint访问到连接点上下文的信息。我们先来了解一下这两个接口的主要方法:
1)JoinPoint
java.lang.Object[] getArgs():获取连接点方法运行时的入参列表;
Signature getSignature() :获取连接点的方法签名对象;
java.lang.Object getTarget() :获取连接点所在的目标对象;
java.lang.Object getThis() :获取代理对象本身;
2)ProceedingJoinPoint
ProceedingJoinPoint继承JoinPoint子接口,它新增了两个用于执行连接点方法的方法:
- java.lang.Object proceed() throws java.lang.Throwable:通过反射执行目标对象的连接点处的方法;
- java.lang.Object proceed(java.lang.Object[] args) throws java.lang.Throwable:通过反射执行目标对象连接点处的方法,不过使用新的入参替换原来的入参。