Spring基础系列--AOP实践

原创作品,可以转载,但是请标注出处地址:   本文目的是简单讲解下Spring AOP的使用。   推荐使用IDEA + Spring Boot。   新建Spring Boot 项目,选择Aspect功能。   创建完成后,POM文件如下: 复制代码 1 2 4 4.0.0 5 6 com.example 7 spring-aspect-demo 8 0.0.1-SNAPSHOT 9 jar 10 11 spring-aspect-demo 12 Demo project for Spring Boot 13 14 15 org.springframework.boot 16 spring-boot-starter-parent 17 2.0.4.RELEASE 18 19 20 21 22 UTF-8 23 UTF-8 24 1.8 25 26 27 28 29 org.springframework.boot 30 spring-boot-starter-aop 31 32 33 34 org.springframework.boot 35 spring-boot-starter-test 36 test 37 38 39 40 41 42 43 org.springframework.boot 44 spring-boot-maven-plugin 45 46 47 48 49 50 复制代码   然后我们创建目标类和方法: 复制代码 1 package com.example.springaspectdemo; 2 3 import org.springframework.stereotype.Component; 4 5 @Component 6 public class AspectDemo { 7 public Integer test(String s){ 8 System.out.println("目标方法执行-"+s); 9 return 123321; 10 } 11 } 复制代码   上面的代码中主要的就是@Component注解,在于将目标类扫描到Spring容器中。   下面我们创建切面类: 复制代码 1 package com.example.springaspectdemo; 2 3 import org.aspectj.lang.JoinPoint; 4 import org.aspectj.lang.ProceedingJoinPoint; 5 import org.aspectj.lang.annotation.*; 6 import org.springframework.stereotype.Component; 7 8 @Aspect 9 @Component 10 public class AspectTest { 11 12 @Pointcut(value = "execution(* *.test(..)) && args(s)") 13 public void pc(String s){ 14 System.out.println("切点执行"); 15 } 16 22 @Before("pc(s)") 23 public void beforeTest(JoinPoint jp,String s){ 24 System.out.println("前置通知-arg="+s); 25 } 26 27 @After("pc(s)") 28 public void afterTest(String s){ 29 System.out.println("后置终点通知-arg="+s); 30 } 31 32 @AfterReturning(pointcut = "pc(s)", returning = "i") 33 public void afterReturningTest(Object i,String s){ 34 System.out.println("后置返回通知-return="+i+"-arg="+s); 35 } 36 37 @AfterThrowing(pointcut = "pc(s)",throwing = "e") 38 public void afterThrowingTest(Exception e,String s){ 39 System.out.println("后置异常通知-"+e.getMessage()+"-arg="+s); 40 } 41 42 @Around("pc(s)") 43 public void aroundTest(ProceedingJoinPoint jp,String s){ 44 System.out.println("环绕前置通知-arg="+s); 45 Object[] os = jp.getArgs(); 46 s = "caocao"; 47 os[0] = s; 48 try { 49 jp.proceed(os); 50 } catch (Throwable throwable) { 51 throwable.printStackTrace(); 52 } 53 System.out.println("环绕后置通知-arg="+s); 54 } 55 } 复制代码   创建测试用例: 复制代码 1 package com.example.springaspectdemo; 2 3 import org.junit.Test; 4 import org.junit.runner.RunWith; 5 import org.springframework.beans.factory.annotation.Autowired; 6 import org.springframework.boot.test.context.SpringBootTest; 7 import org.springframework.context.annotation.EnableAspectJAutoProxy; 8 import org.springframework.test.context.junit4.SpringRunner; 9 10 @RunWith(SpringRunner.class) 11 @SpringBootTest 12 @EnableAspectJAutoProxy 13 public class SpringAspectDemoApplicationTests { 14 @Autowired 15 private AspectDemo aspectDemo; 16 17 @Test 18 public void aspecctTest(){ 19 aspectDemo.test("huahua"); 20 } 21 } 复制代码   执行结果: 复制代码 环绕前置通知-arg=huahua 前置通知-arg=caocao 目标方法执行-caocao 环绕后置通知-arg=caocao 后置终点通知-arg=caocao 后置返回通知-return=null-arg=caocao 复制代码   重点解析:   1、后置返回通知是在目标代码执行完毕,返回结果之后执行,可以对返回的结果进行处理,但是要注意,其不能和环绕通知一起作用于同一个目标方法,否则会导致无法获取到返回值,正如上面例子中执行结果最后一行的null,表示的就是返回值,如果将环绕通知的部分注释掉,则可以返回正确的结果。   2、后置返回通知的返回值类型必须是引用类型或者包装类型,不能是原始类型,否则会报错,类型不匹配。   3、我们可以对目标方法的参数进行修改,但只能在环绕通知中进行,在环绕通知中的第一个参数必然是ProceedJoinPoint,它是JoinPoint的子类,通过其getArgs方法可以获取到调用目标方法的参数列表,可以对其进行修改,然后再执行带参数的proceed方法,将新的参数列表传递到目标方法。而且我们可以从上面的执行结果看到,环绕通知的前置部分是先于其他所有通知而执行的,那么它修改参数之后将会作用于后面所有的通知。正如例子中,我们在环绕通知前置部分将参数"huahua"改成了"caocao",在之后的所有通知和目标方法中获取到的参数全部变成了"caocao"。   4、异常通知不只是捕捉目标方法中的异常,还有作用于同一方法上的其他通知中发生的异常。所以并不是一旦出现异常就不会执行afterReturning通知方法。如果是目标方法执行正常,却在afterReturning中发生异常的话,那么就会同时执行afterReturning通知方法和afterThrowing通知方法。   5、我们还可以从上面的执行结果看到各个通知的执行顺序:     环绕通知前置部分--->前置通知--->目标方法--->环绕通知后置部分--->后置终点通知--->后置返回通知--->后置异常通知   6、对于上面执行的一点补充:     那就是发生异常的情况,如果在环绕通知前置部分发生异常,那么之后除了后置终点通知是必然执行的外,只有最后的异常通知会被触发,其余一概不会执行。     如果第5点中执行顺序哪一步发生了异常,那么其前面的通知会正常执行,后面的除了后置终点通知一定会执行外,异常通知也回被触发。     但有一个例外,那就是前置通知,在前置通知和环绕通知同时作用于一个目标方法时,前置通知的异常将不会被后置异常通知捕捉到。   7、终上所述,推荐不要将环绕通知和其他通知一起使用。因为环绕通知会导致一些异常的情况,使其他通知的部分功能失效。   可以使用上面的代码进行修改测试!https://www.cnblogs.com/V1haoge/p/9615720.html
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信