接口,要求为每个方法前后添加日志 
  1. @Component("arithmeticCalculator")
  2. public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
  3.  
  4. @Override
  5. public int add(int i, int j) {
  6. int result = i + j;
  7. return result;
  8. }
  9.  
  10. @Override
  11. public int sub(int i, int j) {
  12. int result = i - j;
  13. return result;
  14. }
  15.  
  16. @Override
  17. public int mul(int i, int j) {
  18. int result = i * j;
  19. return result;
  20. }
  21.  
  22. @Override
  23. public int div(int i, int j) {
  24. int result = i / j;
  25. return result;
  26. }
  27.  
  28. }

接口的实现类

  1. public class ArithmeticCalculatorLoggingImpl implements ArithmeticCalculator {
  2.  
  3. @Override
  4. public int add(int i, int j) {
  5. System.out.println("The method add begins with [" + i + "," + j + "]");
  6. int result = i + j;
  7. System.out.println("The method add ends with " + result);
  8. return result;
  9. }
  10.  
  11. @Override
  12. public int sub(int i, int j) {
  13. System.out.println("The method sub begins with [" + i + "," + j + "]");
  14. int result = i - j;
  15. System.out.println("The method sub ends with " + result);
  16. return result;
  17. }
  18.  
  19. @Override
  20. public int mul(int i, int j) {
  21. System.out.println("The method mul begins with [" + i + "," + j + "]");
  22. int result = i * j;
  23. System.out.println("The method mul ends with " + result);
  24. return result;
  25. }
  26.  
  27. @Override
  28. public int div(int i, int j) {
  29. System.out.println("The method div begins with [" + i + "," + j + "]");
  30. int result = i / j;
  31. System.out.println("The method div ends with " + result);
  32. return result;
  33. }
  34.  
  35. }

方法一:手动实现为方法添加日志

  1. public class ArithmeticCalculatorLoggingProxy {
  2.  
  3. private ArithmeticCalculator target;
  4.  
  5. public ArithmeticCalculatorLoggingProxy(ArithmeticCalculator target) {
  6. super();
  7. this.target = target;
  8. }
  9.  
  10. public ArithmeticCalculator getLoggingProxy(){
  11. ArithmeticCalculator proxy = null;
  12.  
  13. ClassLoader loader = target.getClass().getClassLoader();
  14. Class [] interfaces = new Class[]{ArithmeticCalculator.class};
  15. InvocationHandler h = new InvocationHandler() {
  16. /*method 方法
  17. *args 参数
  18. * */
  19. @Override
  20. public Object invoke(Object proxy, Method method, Object[] args)
  21. throws Throwable {
  22. String methodName = method.getName();
  23.  
  24. //前置通知
  25. System.out.println("[before] The method " + methodName + " begins with " + Arrays.asList(args));
  26.  
  27. Object result = null;
  28. try {
  29.  
  30. result = method.invoke(target, args);//返回通知
  31.  
  32. } catch (NullPointerException e) {
  33. e.printStackTrace();
  34. //异常通知
  35. }
  36. //后置通知
  37. System.out.println("[after] The method ends with " + result);
  38.  
  39. return result;
  40. }
  41. };
  42.  
  43. proxy = (ArithmeticCalculator) Proxy.newProxyInstance(loader, interfaces, h);
  44.  
  45. return proxy;
  46. }
  47. }

方法二:利用动态代理模式实现为方法添加日志

  1. /**
  2. * AOP
  3. * 1. 导入jar包
  4. * com.springsource.net.sf.cglib-2.2.0.jar
  5. * com.springsource.org.aopalliance-1.0.0.jar
  6. * com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
  7. * spring-aspects-4.0.0.RELEASE.jar
  8. *
  9. * 2. 在配置文件中加入AOP的命名空间
  10. * xmlns:aop="http://www.springframework.org/schema/aop"
  11. *
  12. * 3. 基于注解的方式
  13. * <context:component-scan base-package="com.atguigu.spring.aop"></context:component-scan>
  14. * <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
  15. *
  16. * 4.把横切关注点的代码抽象到切面的类中
  17. * @Aspect
  18. * @Component
  19. * public class LoggingAspect {}
  20. *
  21. * 5.AspectJ支持5种类型的通知注解
  22. * @Before()前置通知,在方法开始前执行
  23. * @After()后置通知,在方法执行后执行,无论抛异常都会执行;不能访问方法执行的结果
  24. * @AfterRunning()返回通知,在方法返回结果后执行(即方法正常结束后才执行);可以得到方法执行的结果
  25. * @AfterThrowing()异常通知,在方法抛出异常时执行
  26. * @Around()环绕通知,围绕着方法执行
  27. * 6.AspectJ表达式
  28. * execution(public int com.aop.beans.ArithmeticCalculator.*(int, int))
  29. * execution(* com.aop.beans.*.*(int, int))
  30. *
  31. * 7.JoinPoint
  32. * 通过他可以得到方法的信息
  33. */
  34.  
  35. //把这个类放入到IOC容器中@Component;再声明为一个切面@Aspect
  36. @Aspect
  37. @Component
  38. public class LoggingAspect {
  39. //该方法是一个前置通知,即在目标方法开始前执行@Before()
  40. @Before("execution(public int com.aop.beans.ArithmeticCalculator.*(int, int))")
  41. public void beforeMethod(JoinPoint joinPoint){
  42. String methodName = joinPoint.getSignature().getName();//得到方法名
  43. Object [] args = joinPoint.getArgs();//得到参数
  44.  
  45. System.out.println("前置通知:The method " + methodName + " begins with " + Arrays.asList(args));
  46. }
  47.  
  48. @After("execution(* com.aop.beans.*.*(..))")//位置为这个包下的所有类、所有方法、不论参数是什么类型
  49. public void afterMethod(JoinPoint joinPoint){
  50. String methodName = joinPoint.getSignature().getName();
  51. System.out.println("后置通知:The method " + methodName + " ends");
  52. }
  53.  
  54. @AfterReturning(value="execution(public int com.aop.beans.ArithmeticCalculator.*(int, int))",
  55. returning="result")
  56. public void afterReturning(JoinPoint joinPoint, Object result){
  57. String methodName = joinPoint.getSignature().getName();
  58. System.out.println("返回通知:The method " + methodName + " ends with " + result);
  59. }
  60.  
  61. @AfterThrowing(value="execution(public int com.aop.beans.ArithmeticCalculator.*(int, int))",
  62. throwing="e")
  63. public void afterThrowing(JoinPoint joinPoint, Exception e){
  64. String methodName = joinPoint.getSignature().getName();
  65. System.out.println("异常通知:The method " + methodName + " occurs excetion:" + e);
  66. }
  67.  
  68. /*
  69. * 环绕通知功能相当于动态代理的全过程,需要有ProceedingJoinPoint 类型的参数;
  70. * pjd 参数可以决定是否执行目标方法
  71. * 环绕通知必须有返回值,返回值即为目标方法的返回值
  72. *
  73. *
  74. @Around("execution(public int com.aop.beans.ArithmeticCalculator.*(int, int))")
  75. public Object aroundMethod(ProceedingJoinPoint pjd){
  76.  
  77. Object result = null;//返回值
  78. String methodName = pjd.getSignature().getName();//得到方法名
  79.  
  80. try {
  81. //前置通知
  82. System.out.println("The method " + methodName + " begins with " + Arrays.asList(pjd.getArgs()));
  83. result = pjd.proceed();//执行方法 //返回通知
  84. System.out.println("The method " + methodName + " ends with " + result);
  85. } catch (Throwable e) {
  86. //异常通知
  87. System.out.println("The method " + methodName + " occurs exception:" + e);
  88. throw new RuntimeException(e);
  89. }
  90. //后置通知
  91. System.out.println("The method " + methodName + " ends");
  92.  
  93. return result;
  94. }
  95. */
  96.  
  97. }

方法三:利用Spring AOP AspectJ实现为方法添加日志

  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
  7. http://www.springframework.org/schema/beans/spring-beans.xsd
  8. http://www.springframework.org/schema/aop
  9. http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
  10. http://www.springframework.org/schema/context
  11. http://www.springframework.org/schema/context/spring-context-4.0.xsd">
  12.  
  13. <!-- 自动扫描的包; 扫描@注解,添加到IOC容器中,让Spring管理-->
  14. <context:component-scan base-package="com.aop.beans"></context:component-scan>
  15.  
  16. <!-- 使 AspectJ 的注解起作用 ; autoproxy自动代理-->
  17. <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
  18.  
  19. </beans>

beans-aop.xml

  1. public class Main {
  2.  
  3. public static void main(String[] args) {
  4. /*代理模式实现添加日志功能
  5. ArithmeticCalculator arithmeticCalculator = new ArithmeticCalculatorImpl();
  6. arithmeticCalculator = new ArithmeticCalculatorLoggingProxy(arithmeticCalculator).getLoggingProxy();
  7. int result = arithmeticCalculator.add(11, 12);
  8. System.out.println("result:" + result);
  9. result = arithmeticCalculator.div(21, 3);
  10. System.out.println("result:" + result);
  11. */
  12.  
  13. //AOP实现添加日志功能
  14. ApplicationContext ctx = new ClassPathXmlApplicationContext("com/aop/beans/beans-aop.xml");
  15. ArithmeticCalculator arithmeticCalculator = (ArithmeticCalculator) ctx.getBean("arithmeticCalculator");
  16.  
  17. System.out.println(arithmeticCalculator.getClass().getName());
  18.  
  19. int result = arithmeticCalculator.add(11, 12);
  20. System.out.println("result:" + result);
  21. result = arithmeticCalculator.div(21, 2);
  22. System.out.println("result:" + result);
  23.  
  24. }
  25.  
  26. }

测试类

Spring AOP 5种通知与java动态代理的更多相关文章

  1. Spring AOP中的JDK和CGLib动态代理哪个效率更高?

    一.背景 今天有小伙伴面试的时候被问到:Spring AOP中JDK 和 CGLib动态代理哪个效率更高? 二.基本概念 首先,我们知道Spring AOP的底层实现有两种方式:一种是JDK动态代理, ...

  2. Spring AOP中的JDK和CGLIB动态代理

    Spring在将Advice织入目标对象的Joinpoint是在运行时动态进行的.它采用的方式可能有两种,即JDK动态代理与CGLIB代理.Spring会根据具体的情况在两者之间切换. 实际情况如下: ...

  3. Spring AOP简介与底层实现机制——动态代理

    AOP简介 AOP (Aspect Oriented Programing) 称为:面向切面编程,它是一种编程思想.AOP 是 OOP(面向对象编程 Object Oriented Programmi ...

  4. java面试题之spring aop中jdk和cglib哪个动态代理的性能更好?

    在jdk6和jdk7的时候,jdk比cglib要慢: 在jdk8的时候,jdk性能得到提升比cglib要快很多: 结论出自:https://www.cnblogs.com/xuliugen/p/104 ...

  5. JAVA动态代理的全面深层理解

    Java 动态代理机制的出现,使得 Java 开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类.代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执行的过 ...

  6. 一文读懂Java动态代理

    作者 :潘潘 日期 :2020-11-22 事实上,对于很多Java编程人员来说,可能只需要达到从入门到上手的编程水准,就能很好的完成大部分研发工作.除非自己强主动获取,或者工作倒逼你学习,否则我们好 ...

  7. 深入浅出Java动态代理

    文章首发于[博客园-陈树义],点击跳转到原文深入浅出Java动态代理 代理模式是设计模式中非常重要的一种类型,而设计模式又是编程中非常重要的知识点,特别是在业务系统的重构中,更是有举足轻重的地位.代理 ...

  8. Java动态代理 深度详解

    代理模式是设计模式中非常重要的一种类型,而设计模式又是编程中非常重要的知识点,特别是在业务系统的重构中,更是有举足轻重的地位.代理模式从类型上来说,可以分为静态代理和动态代理两种类型. 今天我将用非常 ...

  9. Java动态代理:一个面包店的动态代理帝国

    文章首发于[博客园-陈树义],点击跳转到原文大白话说Java动态代理:一个面包店的动态代理帝国 代理模式是设计模式中非常重要的一种类型,而设计模式又是编程中非常重要的知识点,特别是在业务系统的重构中, ...

随机推荐

  1. github添加ssh key报错Key is invalid. Ensure you've copied the file correctly

    github添加ssh key的时候报错:Key is invalid. Ensure you've copied the file correctly 将秘钥复制粘贴到文本编辑器中,再粘贴复制到

  2. VS2012 asp.net mvc 4 运行项目提示:"错误消息 401.2。: 未经授权: 服务器配置导致登录失败"

    创建mvc4 应用程序发布,运行出错.出现未经授权: 服务器配置导致登录失败.请验证您是否有权基于您提供的凭,后来找得解决方法: 打开点站的web.confg文件,将: <authorizati ...

  3. jQuery原型属性和方法总结

    从大四下学期开始了解jquery源码相关的东西,在回校参加毕业典礼(准确的说是参加补考挂科太多)期间便开始借着<jQuery>内幕学习jquery源码,然后在博客园写笔记也已经两个月了,也 ...

  4. 优秀的CSS框架---bootstrap

    Bootstrap是Twitter推出的一个用于前端开发的开源工具包.它 由Twitter的设计师Mark Otto和Jacob Thornton合作开发,是一个CSS/HTML框架.现在在网上已经有 ...

  5. ST05 跟踪SQL

          SAP R/3 提供标准ABAP SQL 跟踪工具.使用T-Code:ST05 可以进入追踪设定画面:          在Trace Modes 区域中选择需要在SAP R/3 Serv ...

  6. 如何:对 SharePoint 列表项隐藏 ECB 中的菜单项

    可以通过使用功能框架向编辑控制块 (ECB) 菜单添加新的自定义操作.但是,您不能使用此方法进行相反的操作,即隐藏现有的 ECB 菜单项,因为它们是通过使用 ECMAScript(JavaScript ...

  7. [Dynamics CRM 2016]如何配置多语言显示

    1.安装相对应的语言包并安装 2015语言包下载地址:https://www.microsoft.com/en-us/download/details.aspx?id=45014 2016语言包下载地 ...

  8. Android Tips: 打电话和发短信

    利用Android打电话非常简单,直接调用Android内在的电话功能就可以了. btnDail.setOnClickListener(new OnClickListener(){ @Override ...

  9. 属性(@property)、@synthesize

    先前我们学的实例变量是这样的 { int _age; int _height; int age; } 后来学属性 @property int age; 看到@property 会自动编译生成某个成员变 ...

  10. Kotlin语法(函数和lambda表达式)

    三.函数和lambda表达式 1. 函数声明 fun double(x: Int): Int { } 函数参数是用 Pascal 符号定义的 name:type.参数之间用逗号隔开,每个参数必须指明类 ...