• 12 - Spring AOP介绍与使用3 - AOP的xml配置文件方式


    之前,aop是通过注解的方式,在resources文件夹下定义了applicationContext.xml配置文件:
    
    1. "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:context="http://www.springframework.org/schema/context"
    5. xmlns:aop="http://www.springframework.org/schema/aop"
    6. xsi:schemaLocation="http://www.springframework.org/schema/beans
    7. http://www.springframework.org/schema/beans/spring-beans.xsd
    8. http://www.springframework.org/schema/context
    9. http://www.springframework.org/schema/context/spring-context.xsd
    10. http://www.springframework.org/schema/aop
    11. http://www.springframework.org/schema/aop/spring-aop.xsd
    12. ">
    13. <context:component-scan base-package="com.zhoulz">context:component-scan>
    14. <aop:aspectj-autoproxy>aop:aspectj-autoproxy>
    15. beans>

    下面介绍aop的xml配置文件的方式:

    同样在resources文件夹下定义了aop.xml配置文件

    1. "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. xsi:schemaLocation="http://www.springframework.org/schema/beans
    6. http://www.springframework.org/schema/beans/spring-beans.xsd
    7. http://www.springframework.org/schema/aop
    8. http://www.springframework.org/schema/aop/spring-aop.xsd
    9. ">
    10. <bean id="logUtil" class="com.zhoulz.util.LogUtil" >bean>
    11. <bean id="securityUtil" class="com.zhoulz.util.SecurityUtil">bean>
    12. <bean id="myCalculator" class="com.zhoulz.service.MyCalculator">bean>
    13. <aop:config>
    14. <aop:pointcut id="globalPoint" expression="execution(public Integer com.zhoulz.service.MyCalculator.*(..))"/>
    15. <aop:aspect ref="logUtil">
    16. <aop:pointcut id="myPoint" expression="execution(public Integer com.zhoulz.service.MyCalculator.*(..))"/>
    17. <aop:before method="start" pointcut-ref="myPoint">aop:before>
    18. <aop:after method="logFinally" pointcut-ref="myPoint">aop:after>
    19. <aop:after-returning method="stop" pointcut-ref="myPoint" returning="result">aop:after-returning>
    20. <aop:after-throwing method="logException" pointcut-ref="myPoint" throwing="e">aop:after-throwing>
    21. <aop:around method="around" pointcut-ref="myPoint">aop:around>
    22. aop:aspect>
    23. <aop:aspect ref="securityUtil">
    24. <aop:before method="start" pointcut-ref="myPoint">aop:before>
    25. <aop:after method="logFinally" pointcut-ref="myPoint">aop:after>
    26. <aop:after-returning method="stop" pointcut-ref="myPoint" returning="result">aop:after-returning>
    27. <aop:after-throwing method="logException" pointcut-ref="globalPoint" throwing="e">aop:after-throwing>
    28. <aop:around method="around" pointcut-ref="globalPoint">aop:around>
    29. aop:aspect>
    30. aop:config>
    31. beans>

    代码示例: —— 注意,相关注解已取消

    参考:11 - Spring AOP介绍与使用2 - 简单配置_哆啦A梦的_梦的博客-CSDN博客

    基本相同。

    Calculator接口:

    1. package com.zhoulz.service;
    2. import org.springframework.stereotype.Service;
    3. //@Service
    4. public interface Calculator {
    5. public Integer add(Integer i,Integer j) throws NoSuchMethodException;
    6. public Integer sub(Integer i,Integer j) throws NoSuchMethodException;
    7. public Integer mul(Integer i,Integer j) throws NoSuchMethodException;
    8. public Integer div(Integer i,Integer j) throws NoSuchMethodException;
    9. }

    MyCalculator 类:

    1. package com.zhoulz.service;
    2. import com.zhoulz.util.LogUtil;
    3. import org.springframework.stereotype.Service;
    4. import java.lang.reflect.Method;
    5. //@Service
    6. public class MyCalculator /*implements Calculator */{
    7. public Integer add(Integer i, Integer j) throws NoSuchMethodException {
    8. //现在,想添加日志的输出功能,怎么做?
    9. //最简单的做法:在每行代码里面都做一个最基本的输出 —— 但是这样做效率太低了
    10. //System.out.prIntegerln("add方法开始执行,参数是:" + i + "----" + j );
    11. //改进: —— 定义一个LogUtil类(包含start()方法和stop()方法)
    12. //通过反射
    13. /*Method add = MyCalculator.class.getMethod("add", Integer.class, Integer.class);
    14. //然后add传入到下面的方法中 —— 下面的都同理
    15. LogUtil.start(add,i,j);*/
    16. Integer result = i + j;
    17. //System.out.prIntegerln("add方法执行结束,结果是:" + result);
    18. //LogUtil.stop(add,result);
    19. return result;
    20. }
    21. public Integer sub(Integer i, Integer j) throws NoSuchMethodException {
    22. //System.out.prIntegerln("sub方法开始执行,参数是:" + i + "----" + j );
    23. /*Method sub = MyCalculator.class.getMethod("sub", Integer.class, Integer.class);
    24. LogUtil.start(sub,i,j);*/
    25. Integer result = i - j;
    26. //System.out.prIntegerln("sub方法执行结束,结果是:" + result);
    27. //LogUtil.stop(sub,result);
    28. return result;
    29. }
    30. public Integer mul(Integer i, Integer j) throws NoSuchMethodException {
    31. //System.out.prIntegerln("mul方法开始执行,参数是:" + i + "----" + j );
    32. //Method mul = MyCalculator.class.getMethod("mul", Integer.class, Integer.class);
    33. //LogUtil.start(mul,i,j);
    34. Integer result = i * j;
    35. //System.out.prIntegerln("mul方法执行结束,结果是:" + result);
    36. //LogUtil.stop(mul,result);
    37. return result;
    38. }
    39. public Integer div(Integer i, Integer j) throws NoSuchMethodException {
    40. //System.out.prIntegerln("div方法开始执行,参数是:" + i + "----" + j );
    41. //Method div = MyCalculator.class.getMethod("div", Integer.class, Integer.class);
    42. //LogUtil.start(div,i,j);
    43. Integer result = i / j;
    44. //System.out.prIntegerln("div方法执行结束,结果是:" + result);
    45. //LogUtil.stop(div,result);
    46. return result;
    47. }
    48. //再加一个方法
    49. public Integer show(Integer i, Double j){
    50. System.out.println("show ........");
    51. return i;
    52. }
    53. }

    util文件夹下,两个切面类:LogUtil、SecurityUtil

    1. package com.zhoulz.util;
    2. import com.zhoulz.service.Calculator;
    3. import org.aspectj.lang.JoinPoint;
    4. import org.aspectj.lang.ProceedingJoinPoint;
    5. import org.aspectj.lang.Signature;
    6. import org.aspectj.lang.annotation.*;
    7. import org.springframework.core.annotation.Order;
    8. import org.springframework.stereotype.Component;
    9. import java.lang.reflect.Method;
    10. import java.util.Arrays;
    11. //@Aspect
    12. //@Component
    13. //@Order(200)
    14. public class LogUtil {
    15. //如果有多个匹配的表达式相同,能否做抽象?可以
    16. // : 定义一个没有返回值的空方法,给该方法添加@Pointcut注解,后续在使用(匹配表达式)的时候直接调用该方法名称
    17. // 此处的方法只是起一个声明的作用,能够供内部的其他通知方法进行调用
    18. @Pointcut("execution(public Integer com.zhoulz.service.MyCalculator.*(Integer,*))")
    19. public void myPointCut(){} // —— 然后后面用的时候直接写:myPointCut() 即可
    20. //还可以定义多个
    21. @Pointcut("execution(* *(..))")
    22. public void myPointCut2(){}
    23. @Before("execution(public Integer com.zhoulz.service.M*Calculator.*(Integer,*))")
    24. //public static void start(Method method,Object ... args){ //原来的写法 //方法里面暂时不用传入参数
    25. public static void start(JoinPoint joinPoint){
    26. //获取方法签名
    27. Signature signature = joinPoint.getSignature();
    28. //获取方法参数信息
    29. Object[] args = joinPoint.getArgs();
    30. //获取方法名称
    31. //System.out.println(signature.getName());
    32. System.out.println("Log----"+signature.getName()+"方法开始执行,参数是:" +Arrays.asList(args));
    33. }
    34. //@AfterReturning(value = "execution(public Integer com.zhoulz.service.MyCalculator.*(Integer,*))",returning = "result")
    35. //匹配表达式进行了抽象,见上面的 myPointCut()方法
    36. @AfterReturning(value = "myPointCut()",returning = "result")
    37. public static void stop(JoinPoint joinPoint,Object result){ // —— 怎么加结果result?:上面的通知注解要改动
    38. Signature signature = joinPoint.getSignature();
    39. System.out.println("Log----"+signature.getName()+"方法执行结束,结果是:" +result);
    40. }
    41. @AfterThrowing(value = "myPointCut()",throwing = "e")
    42. public static void logException(JoinPoint joinPoint,Exception e){
    43. Signature signature = joinPoint.getSignature();
    44. System.out.println("Log----"+signature.getName()+"方法抛出异常:" + e.getMessage());
    45. }
    46. @After("myPointCut2()")
    47. public static void logFinally(JoinPoint joinPoint){
    48. Signature signature = joinPoint.getSignature();
    49. System.out.println("Log----"+signature.getName()+"方法执行结束。。。。over");
    50. }
    51. //环绕通知 —— 把上面4个通知任意拿过来执行
    52. @Around("myPointCut2()")
    53. public Object around(ProceedingJoinPoint pjp) throws Throwable { //需要传参
    54. Signature signature = pjp.getSignature();
    55. Object[] args = pjp.getArgs();
    56. Object result = null;
    57. try {
    58. System.out.println("Log----"+"环绕通知start:"+signature.getName()+"方法开始执行,参数为:"+ Arrays.asList(args));
    59. //通过反射的方式调用目标的方法,相当于执行method.invoke(),可以自己修改结果值
    60. result = pjp.proceed(args);
    61. //result = 100;
    62. System.out.println("Log----"+"环绕通知stop:"+signature.getName()+"方法执行结束了");
    63. } catch (Throwable throwable) {
    64. //throwable.printStackTrace();
    65. System.out.println("Log----"+"环绕异常通知:"+signature.getName()+"出现异常了");
    66. throw throwable;
    67. }finally {
    68. System.out.println("Log----"+"环绕返回通知:"+signature.getName()+"方法返回结果是:"+result);
    69. }
    70. return result;
    71. }
    72. }
    1. package com.zhoulz.util;
    2. import org.aspectj.lang.JoinPoint;
    3. import org.aspectj.lang.ProceedingJoinPoint;
    4. import org.aspectj.lang.Signature;
    5. import org.aspectj.lang.annotation.*;
    6. import org.springframework.core.annotation.Order;
    7. import org.springframework.stereotype.Component;
    8. import java.util.Arrays;
    9. /*@Aspect
    10. @Component
    11. @Order(100)*/
    12. public class SecurityUtil {
    13. //如果有多个匹配的表达式相同,能否做抽象?可以
    14. // : 定义一个没有返回值的空方法,给该方法添加@Pointcut注解,后续在使用(匹配表达式)的时候直接调用该方法名称
    15. // 此处的方法只是起一个声明的作用,能够供内部的其他通知方法进行调用
    16. @Pointcut("execution(public Integer com.zhoulz.service.MyCalculator.*(Integer,*))")
    17. public void myPointCut(){} // —— 然后后面用的时候直接写:myPointCut() 即可
    18. //还可以定义多个
    19. @Pointcut("execution(* *(..))")
    20. public void myPointCut2(){}
    21. @Before("execution(public Integer com.zhoulz.service.M*Calculator.*(Integer,*))")
    22. //public static void start(Method method,Object ... args){ //原来的写法 //方法里面暂时不用传入参数
    23. public static void start(JoinPoint joinPoint){
    24. //获取方法签名
    25. Signature signature = joinPoint.getSignature();
    26. //获取方法参数信息
    27. Object[] args = joinPoint.getArgs();
    28. //获取方法名称
    29. //System.out.println(signature.getName());
    30. System.out.println("Security----"+signature.getName()+"方法开始执行,参数是:" +Arrays.asList(args));
    31. }
    32. //@AfterReturning(value = "execution(public Integer com.zhoulz.service.MyCalculator.*(Integer,*))",returning = "result")
    33. //匹配表达式进行了抽象,见上面的 myPointCut()方法
    34. @AfterReturning(value = "myPointCut()",returning = "result")
    35. public static void stop(JoinPoint joinPoint, Object result){ // —— 怎么加结果result?:上面的通知注解要改动
    36. Signature signature = joinPoint.getSignature();
    37. System.out.println("Security----"+signature.getName()+"方法执行结束,结果是:" +result);
    38. }
    39. @AfterThrowing(value = "myPointCut()",throwing = "e")
    40. public static void logException(JoinPoint joinPoint,Exception e){
    41. Signature signature = joinPoint.getSignature();
    42. System.out.println("Security----"+signature.getName()+"方法抛出异常:" + e.getMessage());
    43. }
    44. @After("myPointCut2()")
    45. public static void logFinally(JoinPoint joinPoint){
    46. Signature signature = joinPoint.getSignature();
    47. System.out.println("Security----"+signature.getName()+"方法执行结束。。。。over");
    48. }
    49. //环绕通知 —— 把上面4个通知任意拿过来执行
    50. @Around("myPointCut2()")
    51. public Object around(ProceedingJoinPoint pjp) throws Throwable { //需要传参
    52. Signature signature = pjp.getSignature();
    53. Object[] args = pjp.getArgs();
    54. Object result = null;
    55. try {
    56. System.out.println("Security----"+"环绕通知start:"+signature.getName()+"方法开始执行,参数为:"+ Arrays.asList(args));
    57. //通过反射的方式调用目标的方法,相当于执行method.invoke(),可以自己修改结果值
    58. result = pjp.proceed(args);
    59. //result = 100;
    60. System.out.println("Security----"+"环绕通知stop:"+signature.getName()+"方法执行结束了");
    61. } catch (Throwable throwable) {
    62. //throwable.printStackTrace();
    63. System.out.println("Security----"+"环绕异常通知:"+signature.getName()+"出现异常了");
    64. throw throwable;
    65. }finally {
    66. System.out.println("Security----"+"环绕返回通知:"+signature.getName()+"方法返回结果是:"+result);
    67. }
    68. return result;
    69. }
    70. }

    测试类:—— 注意:切换到 aop.xml (原来是 applicationContext.xml )

    1. import com.zhoulz.service.Calculator;
    2. import com.zhoulz.service.MyCalculator;
    3. import org.junit.Test;
    4. import org.springframework.context.support.ClassPathXmlApplicationContext;
    5. public class MyTest {
    6. //ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    7. //采用xml配置文件的方式,一定要注意切换到aop.xml
    8. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("aop.xml");
    9. @Test
    10. public void test01() throws NoSuchMethodException {
    11. //ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    12. //Calculator calculator = context.getBean("myCalculator", Calculator.class);
    13. //或者直接写
    14. //Calculator calculator = context.getBean(Calculator.class);
    15. //取消MyCalculator对Calculator的继承,再测试 —— 结果正常(即没有接口实现的话,则用的是cglib进行动态代理)
    16. MyCalculator calculator = context.getBean(MyCalculator.class);
    17. calculator.add(10,2);
    18. // calculator.sub(10,2);
    19. calculator.div(10,0);
    20. calculator.show(10,2.5);
    21. //System.out.println(calculator.getClass()); //class com.sun.proxy.$Proxy24
    22. //取消继承后,结果为:class com.zhoulz.service.MyCalculator$$EnhancerBySpringCGLIB$$77df863d
    23. }
    24. @Test
    25. public void test02() throws NoSuchMethodException {
    26. MyCalculator calculator = context.getBean(MyCalculator.class);
    27. //calculator.add(10,2);
    28. calculator.div(10,2);
    29. }
    30. }

    结果:

    Log----div方法开始执行,参数是:[10, 2]
    Log----环绕通知start:div方法开始执行,参数为:[10, 2]
    Security----div方法开始执行,参数是:[10, 2]
    Security----环绕通知start:div方法开始执行,参数为:[10, 2]
    Security----环绕通知stop:div方法执行结束了
    Security----环绕返回通知:div方法返回结果是:5
    Security----div方法执行结束,结果是:5
    Security----div方法执行结束。。。。over
    Log----环绕通知stop:div方法执行结束了
    Log----环绕返回通知:div方法返回结果是:5
    Log----div方法执行结束,结果是:5
    Log----div方法执行结束。。。。over

  • 相关阅读:
    linux_进程周边知识——理解冯诺依曼体系结构
    Spring多线程事务处理
    Django 与图表的数据交互
    windows环境CLion调试SRS流媒体服务器源码
    基于生物激励神经网络的室内实时激光SLAM控制方法
    单链表笔试题(是否相交,求交点;是否有环,求入环点)C++
    Java网络编程(二)Socket 套接字(TCP和UDP),以及TCP的回显
    字节迎来新 CFO,或重启上市;马斯克以 440 亿美元收购 Twitter;FFmpeg 支持 JPEG-XL|极客头条
    dd命令用法学习,是一个功能强大的工具
    Zookeeper
  • 原文地址:https://blog.csdn.net/zhoulizhengZ/article/details/127683479