03Spring实现AOP前置后置等

张创琦

代码详见 spring03_aop

以下代码共用一个测试类和service类

Test01.java

  1. package com.kkb.test;
  2. import com.kkb.service.NBAService;
  3. import com.kkb.service.TeamService;
  4. import org.junit.Test;
  5. import org.springframework.context.ApplicationContext;
  6. import org.springframework.context.support.ClassPathXmlApplicationContext;
  7. public class Test01 {
  8. @Test
  9. public void test01(){
  10. ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
  11. TeamService teamService = (TeamService)ac.getBean("teamService");
  12. teamService.add(1001, "湖人队");
  13. System.out.println("----------");
  14. boolean update = teamService.update(888);
  15. System.out.println("update结果: " + update);
  16. System.out.println("---------------------");
  17. NBAService nbaService = (NBAService)ac.getBean("nbaService");
  18. nbaService.add(1002, "热火队");
  19. System.out.println("----------");
  20. boolean update2 = teamService.update(888);
  21. System.out.println("update2结果: " + update2);
  22. }
  23. }

IService.java

  1. package com.kkb.service;
  2. public interface IService {
  3. void add(int id, String name);
  4. boolean update(int num);
  5. }

NBAService.java

标头引入相关依赖。

  1. package com.kkb.service;
  2. import org.springframework.stereotype.Service;
  3. @Service("nbaService")
  4. public class NBAService implements IService {
  5. @Override
  6. public void add(int id, String name) {
  7. System.out.println("NBAService------add------");
  8. }
  9. @Override
  10. public boolean update(int num) {
  11. System.out.println("NBAService------update------");
  12. if(num > 666){
  13. return true;
  14. }
  15. return false;
  16. }
  17. }

TeamService.java

  1. package com.kkb.service;
  2. import org.springframework.stereotype.Service;
  3. @Service
  4. public class TeamService implements IService {
  5. @Override
  6. public void add(int id, String name) {
  7. //int num = 10 / 0;
  8. System.out.println("TeamService------add------");
  9. }
  10. @Override
  11. public boolean update(int num) {
  12. System.out.println("TeamService------update------");
  13. if(num > 666){
  14. return true;
  15. }
  16. return false;
  17. }
  18. }

方法1: 通过注解方式实现

MyAspect.java

  1. package com.kkb.aop;
  2. import org.aspectj.lang.JoinPoint;
  3. import org.aspectj.lang.ProceedingJoinPoint;
  4. import org.aspectj.lang.annotation.*;
  5. import org.springframework.stereotype.Component;
  6. //切面类
  7. @Component //切面对象的创建权限依然交给Spring容器
  8. @Aspect //aspectj框架的注解,标识当前类是一个切面类
  9. public class MyAspect {
  10. //统一提取切入点表达式
  11. //其它的通知可以直接在value直接使用方法名称
  12. @Pointcut("execution(* com.kkb.service..*.*(..))") //注解表示切入点表达式,方法一般声明为私有
  13. private void pointCut(){
  14. }
  15. //可以声明多个
  16. @Pointcut("execution(* com.kkb.service..*.update*(..))") //注解表示切入点表达式,方法一般声明为私有
  17. private void pointCut2(){
  18. }
  19. @Before("execution(* com.kkb.service..*.*(..))")
  20. //也可以写成@Before(pointCut())
  21. public void before(JoinPoint jp){
  22. System.out.println("前置通知:在目标方法调用之前被调用的通知。");
  23. String name = jp.getSignature().getName();
  24. System.out.println("拦截的方法名称:"+name);
  25. Object[] args = jp.getArgs();
  26. System.out.println("方法的参数格式:"+args.length);
  27. System.out.println("方法的参数列表:");
  28. for (Object arg: args) {
  29. System.out.println("\t"+arg);
  30. }
  31. }
  32. //Return表示返回的结果,如果需要的话可以在后置方法通知中修改结果,value依然表示切入点表达式
  33. @AfterReturning(value="execution(* com.kkb.service..*.update*(..))", returning = "result")
  34. public Object after(Object result){
  35. if(result != null){
  36. boolean res = (boolean) result;
  37. if(res){
  38. result = false;
  39. }
  40. }
  41. System.out.println("后置通知:在目标方法调用之后被调用的通知。result="+result);
  42. return result;
  43. }
  44. //注解声明环绕通知方法
  45. //ProceedingJoinPoint中的proceed方法表示目标方法被执行
  46. @Around("execution(* com.kkb.service..*.*(..))")
  47. public Object around(ProceedingJoinPoint pjp) throws Throwable {
  48. System.out.println("环绕方法------目标方法执行之前");
  49. Object proceed = pjp.proceed();
  50. System.out.println("环绕方法------目标方法执行之后");
  51. return proceed;
  52. }
  53. //注解声明异常通知方法
  54. @AfterThrowing(value="execution(* com.kkb.service..*.*(..))", throwing = "ex")
  55. public void exception(JoinPoint jp, Throwable ex){
  56. //一般会把异常发生的时间 位置 缘由记录下来
  57. System.out.println("异常通知:在目标方法执行出现异常被调用的通知。否则不执行");
  58. System.out.println(jp.getSignature() + "方法出现异常,异常信息是:" +ex.getMessage());
  59. }
  60. //注解声明最终通知方法
  61. @After("execution(* com.kkb.service..*.*(..))")
  62. public void myFinally(){
  63. System.out.println("最终通知:无论是否出现异常都会调用的通知。");
  64. }
  65. }

spring.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:aop="http://www.springframework.org/schema/aop"
  5. xmlns:context="http://www.springframework.org/schema/context"
  6. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  7. http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
  8. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
  9. ">
  10. <!-- beans标签中引入AOPcontext约束 -->
  11. <context:component-scan base-package="com.kkb.service, com.kkb.aop"/>
  12. <!-- aspectj的相关配置, true开启代理模式 -->
  13. <aop:aspectj-autoproxy proxy-target-class="true"/>
  14. </beans>

方法2: 通过xml配置实现

MyAOP.java

  1. package com.kkb.aop;
  2. import org.aspectj.lang.JoinPoint;
  3. import org.aspectj.lang.ProceedingJoinPoint;
  4. import org.aspectj.lang.annotation.*;
  5. import org.springframework.stereotype.Component;
  6. /**
  7. * 切面类
  8. */
  9. //通过xml调取
  10. @Component //切面对象的创建权限依然交给Spring容器
  11. @Aspect //aspectj框架的注解,标识当前类是一个切面类
  12. public class MyAOP {
  13. public void before(JoinPoint jp){
  14. System.out.println("AOP前置通知:在目标方法调用之前被调用的通知。");
  15. }
  16. public void after(Object result){
  17. System.out.println("AOP后置通知:在目标方法调用之后被调用的通知。result="+result);
  18. }
  19. public Object around(ProceedingJoinPoint pjp) throws Throwable {
  20. System.out.println("AOP环绕方法------目标方法执行之前");
  21. Object proceed = pjp.proceed();
  22. System.out.println("AOP环绕方法------目标方法执行之后");
  23. return proceed;
  24. }
  25. public void exception(JoinPoint jp, Throwable ex){
  26. //一般会把异常发生的时间 位置 缘由记录下来
  27. System.out.println("AOP异常通知:在目标方法执行出现异常被调用的通知。否则不执行");
  28. System.out.println(jp.getSignature() + "方法出现异常,异常信息是:" +ex.getMessage());
  29. }
  30. public void myFinally() {
  31. System.out.println("AOP最终通知:无论是否出现异常都会调用的通知。");
  32. }
  33. }

spring.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:aop="http://www.springframework.org/schema/aop"
  5. xmlns:context="http://www.springframework.org/schema/context"
  6. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  7. http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
  8. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
  9. ">
  10. <!-- beans标签中引入AOPcontext约束 -->
  11. <context:component-scan base-package="com.kkb.service, com.kkb.aop"/>
  12. <!-- aspectj的相关配置, true开启代理模式 -->
  13. <aop:aspectj-autoproxy proxy-target-class="true"/>
  14. <!-- xml方式实现AOP -->
  15. <aop:config>
  16. <aop:pointcut id="pt1" expression="execution(* com.kkb.service..*.*(..))"/>
  17. <aop:pointcut id="pt2" expression="execution(* com.kkb.service..*.add*(..))"/>
  18. <aop:aspect ref="myAOP" >
  19. <!-- 声明切入点的表达式 -->
  20. <aop:before method="before" pointcut-ref="pt1"></aop:before>
  21. <!-- 也可以写成 <aop:before method="before" pointcut="execution(* com.kkb.service..*.*(..))"></aop:before>-->
  22. <aop:after-returning method="after" pointcut-ref="pt2" returning="result"></aop:after-returning>
  23. <aop:after-throwing method="exception" pointcut-ref="pt1" throwing="ex"></aop:after-throwing>
  24. <aop:after method="myFinally" pointcut-ref="pt1"></aop:after>
  25. <aop:around method="around" pointcut-ref="pt2"></aop:around>
  26. </aop:aspect>
  27. </aop:config>
  28. </beans>