接口,要求为每个方法前后添加日志 
 @Component("arithmeticCalculator")
public class ArithmeticCalculatorImpl implements ArithmeticCalculator { @Override
public int add(int i, int j) {
int result = i + j;
return result;
} @Override
public int sub(int i, int j) {
int result = i - j;
return result;
} @Override
public int mul(int i, int j) {
int result = i * j;
return result;
} @Override
public int div(int i, int j) {
int result = i / j;
return result;
} }

接口的实现类

 public class ArithmeticCalculatorLoggingImpl implements ArithmeticCalculator {

     @Override
public int add(int i, int j) {
System.out.println("The method add begins with [" + i + "," + j + "]");
int result = i + j;
System.out.println("The method add ends with " + result);
return result;
} @Override
public int sub(int i, int j) {
System.out.println("The method sub begins with [" + i + "," + j + "]");
int result = i - j;
System.out.println("The method sub ends with " + result);
return result;
} @Override
public int mul(int i, int j) {
System.out.println("The method mul begins with [" + i + "," + j + "]");
int result = i * j;
System.out.println("The method mul ends with " + result);
return result;
} @Override
public int div(int i, int j) {
System.out.println("The method div begins with [" + i + "," + j + "]");
int result = i / j;
System.out.println("The method div ends with " + result);
return result;
} }

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

 public class ArithmeticCalculatorLoggingProxy {

     private ArithmeticCalculator target;

     public ArithmeticCalculatorLoggingProxy(ArithmeticCalculator target) {
super();
this.target = target;
} public ArithmeticCalculator getLoggingProxy(){
ArithmeticCalculator proxy = null; ClassLoader loader = target.getClass().getClassLoader();
Class [] interfaces = new Class[]{ArithmeticCalculator.class};
InvocationHandler h = new InvocationHandler() {
/*method 方法
*args 参数
* */
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
String methodName = method.getName(); //前置通知
System.out.println("[before] The method " + methodName + " begins with " + Arrays.asList(args)); Object result = null;
try { result = method.invoke(target, args);//返回通知 } catch (NullPointerException e) {
e.printStackTrace();
//异常通知
}
//后置通知
System.out.println("[after] The method ends with " + result); return result;
}
}; proxy = (ArithmeticCalculator) Proxy.newProxyInstance(loader, interfaces, h); return proxy;
}
}

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

 /**
* AOP
* 1. 导入jar包
* com.springsource.net.sf.cglib-2.2.0.jar
* com.springsource.org.aopalliance-1.0.0.jar
* com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
* spring-aspects-4.0.0.RELEASE.jar
*
* 2. 在配置文件中加入AOP的命名空间
* xmlns:aop="http://www.springframework.org/schema/aop"
*
* 3. 基于注解的方式
* <context:component-scan base-package="com.atguigu.spring.aop"></context:component-scan>
* <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
*
* 4.把横切关注点的代码抽象到切面的类中
* @Aspect
* @Component
* public class LoggingAspect {}
*
* 5.AspectJ支持5种类型的通知注解
* @Before()前置通知,在方法开始前执行
* @After()后置通知,在方法执行后执行,无论抛异常都会执行;不能访问方法执行的结果
* @AfterRunning()返回通知,在方法返回结果后执行(即方法正常结束后才执行);可以得到方法执行的结果
* @AfterThrowing()异常通知,在方法抛出异常时执行
* @Around()环绕通知,围绕着方法执行
* 6.AspectJ表达式
* execution(public int com.aop.beans.ArithmeticCalculator.*(int, int))
* execution(* com.aop.beans.*.*(int, int))
*
* 7.JoinPoint
* 通过他可以得到方法的信息
*/ //把这个类放入到IOC容器中@Component;再声明为一个切面@Aspect
@Aspect
@Component
public class LoggingAspect {
//该方法是一个前置通知,即在目标方法开始前执行@Before()
@Before("execution(public int com.aop.beans.ArithmeticCalculator.*(int, int))")
public void beforeMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();//得到方法名
Object [] args = joinPoint.getArgs();//得到参数 System.out.println("前置通知:The method " + methodName + " begins with " + Arrays.asList(args));
} @After("execution(* com.aop.beans.*.*(..))")//位置为这个包下的所有类、所有方法、不论参数是什么类型
public void afterMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
System.out.println("后置通知:The method " + methodName + " ends");
} @AfterReturning(value="execution(public int com.aop.beans.ArithmeticCalculator.*(int, int))",
returning="result")
public void afterReturning(JoinPoint joinPoint, Object result){
String methodName = joinPoint.getSignature().getName();
System.out.println("返回通知:The method " + methodName + " ends with " + result);
} @AfterThrowing(value="execution(public int com.aop.beans.ArithmeticCalculator.*(int, int))",
throwing="e")
public void afterThrowing(JoinPoint joinPoint, Exception e){
String methodName = joinPoint.getSignature().getName();
System.out.println("异常通知:The method " + methodName + " occurs excetion:" + e);
} /*
* 环绕通知功能相当于动态代理的全过程,需要有ProceedingJoinPoint 类型的参数;
* pjd 参数可以决定是否执行目标方法
* 环绕通知必须有返回值,返回值即为目标方法的返回值
*
*
@Around("execution(public int com.aop.beans.ArithmeticCalculator.*(int, int))")
public Object aroundMethod(ProceedingJoinPoint pjd){ Object result = null;//返回值
String methodName = pjd.getSignature().getName();//得到方法名 try {
//前置通知
System.out.println("The method " + methodName + " begins with " + Arrays.asList(pjd.getArgs()));
result = pjd.proceed();//执行方法 //返回通知
System.out.println("The method " + methodName + " ends with " + result);
} catch (Throwable e) {
//异常通知
System.out.println("The method " + methodName + " occurs exception:" + e);
throw new RuntimeException(e);
}
//后置通知
System.out.println("The method " + methodName + " ends"); return result;
}
*/ }

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

 <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!-- 自动扫描的包; 扫描@注解,添加到IOC容器中,让Spring管理-->
<context:component-scan base-package="com.aop.beans"></context:component-scan> <!-- 使 AspectJ 的注解起作用 ; autoproxy自动代理-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>

beans-aop.xml

 public class Main {

     public static void main(String[] args) {
/*代理模式实现添加日志功能
ArithmeticCalculator arithmeticCalculator = new ArithmeticCalculatorImpl();
arithmeticCalculator = new ArithmeticCalculatorLoggingProxy(arithmeticCalculator).getLoggingProxy();
int result = arithmeticCalculator.add(11, 12);
System.out.println("result:" + result);
result = arithmeticCalculator.div(21, 3);
System.out.println("result:" + result);
*/ //AOP实现添加日志功能
ApplicationContext ctx = new ClassPathXmlApplicationContext("com/aop/beans/beans-aop.xml");
ArithmeticCalculator arithmeticCalculator = (ArithmeticCalculator) ctx.getBean("arithmeticCalculator"); System.out.println(arithmeticCalculator.getClass().getName()); int result = arithmeticCalculator.add(11, 12);
System.out.println("result:" + result);
result = arithmeticCalculator.div(21, 2);
System.out.println("result:" + result); } }

测试类

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. vue安装

     条件:已安装 node&npm 1.安装 cnpm :                      $ npm install -g cnpm --registry=https://regis ...

  2. Sql Server Always On主库与附库遇到的问题

    使用Always On的时候永远要记住只有一个主数据库可写,如果写的话要不在监听节点上做写的操作,要不只在主数据库上写的操作不然只读库无法读写

  3. Atitit.木马病毒强制强行关闭360 360tray.exe的方法

    Atitit.木马病毒强制强行关闭360 360tray.exe的方法 1. taskkill /im 进程名称1 2. 用 wmic process where name="进程名称&qu ...

  4. 115个Java面试题和答案——终极列表(下)

    第一篇讨论了面向对象编程和它的特点,关于Java和它的功能的常见问题,Java的集合类,垃圾收集器,本章主要讨论异常处理,Java小应用程序,Swing,JDBC,远程方法调用(RMI),Servle ...

  5. Android 手机卫士--阶段小结1

    本文地址:http://www.cnblogs.com/wuyudong/p/5904528.html,转载请注明源地址. 本文对之前手机卫士开发进行一个小结. 1.SplashActivity 版本 ...

  6. Android 视频播放器进度的处理

    在前面的项目中添加SeekBar <SeekBar android:id="@+id/sb" android:layout_width="match_parent& ...

  7. Android 采用HttpClient提交数据到服务器

    在前几篇文章中<Android 采用get方式提交数据到服务器><Android 采用post方式提交数据到服务器>介绍了android的两种提交数据到服务器的方法 本文继续介 ...

  8. 使用 AngularJS 开发一个大规模的单页应用(SPA)

      本文的目标是基于单页面应用程序开发出拥有数百页的内容,包括认证,授权,会话状态等功能,可以支持上千个用户的企业级应用. 下载源代码 介绍 (SPA)这样一个名字里面蕴含着什么呢? 如果你是经典的S ...

  9. Sublime更换默认字体的方法

    Sublime是一款很不错的编辑器,不过默认安装后的字体却不尽人意,并且Sublime竟然连个完整的设置页面都没有(直接让你编辑配置文件).于是很多人对这字体就忍气吞声了.其实只要添加一行代码就可以完 ...

  10. Lazy<T>在Entity Framework中的性能优化实践(附源码)

    在使用EF的过程中,导航属性的lazy load机制,能够减少对数据库的不必要的访问.只有当你使用到导航属性的时候,才会访问数据库.但是这个只是对于单个实体而言,而不适用于显示列表数据的情况. 这篇文 ...