Java使用JDK与Cglib动态代理技术统一管理日志记录

Java中动态代理主要有JDK和CGLIB两种方式。

区别主要是jdk是代理接口,而cglib是代理类。

  • 优点:这种方式已经解决我们前面所有日记需要的问题。非常的灵活。而且可以方便的在后期进行维护和升级。
  • 缺点:当然使用jdk动态代理,必需要有接口。如果没有接口。就无法使用jdk动态代理技术。

计算接口 Calculate.java

public interface Calculate {
 /**
  * 加法运算
  * @param num1 参数 1
  * @param num2 参数 2
  * @return
  */
 public int add(int num1, int num2);

 /**
  * 加法运算
  * @param num1 参数 1
  * @param num2 参数 2
  * @param num3 参数 3
  * @return
  */
 public int add(int num1, int num2, int num3);

 /**
  * 除法运算
  * @param num1 参数 1
  * @param num2 参数 2
  * @return
  */
 public int div(int num1, int num2);
}

实现计算接口中的方法 CalculateImpl.java

/**
 * 实现计算接口中的方法
 * Created by YongXin Xue on 2020/05/05 11:29
 */
public class CalculateImpl implements Calculate {
 @Override
 public int add(int num1, int num2) {
  // 记录当前操作,及运算参数
  LogUtils.logBefore("add", num1, num2);
  int result = num1 + num2;
  return result;
 }

 @Override
 public int add(int num1, int num2, int num3) {
  // 记录当前操作,及运算参数
  LogUtils.logBefore("add", num1, num2, num3);
  int result = num1 + num2 + num3;
  return result;
 }

 @Override
 public int div(int num1, int num2) {
  // 记录当前操作,及运算参数
  LogUtils.logBefore("div", num1, num2);
  int result = 0;
  try {
   result = num1 / num2;
   // 记录运算结果
   LogUtils.logAfterReturning("div", result);
  }catch (Exception e){
   // 记录异常信息
   LogUtils.logAfterThrowing("div", e);
  }
  return result;
 }
}

记录日志工具类 LogUtils.java

/**
 * 记录日志工具类
 * Created by YongXin Xue on 2020/05/05 11:38
 */
public class LogUtils {
 /**
  * 记录前置的日志操作
  * @param method 当前运算操作
  * @param args 当前运算参数
  */
 public static void logBefore(String method, Object ... args){
  System.out.println("操作运算是 : " + method + " 参数是 : " + Arrays.asList(args));
 }

 /**
  * 返回日志操作
  * @param method 当前方法
  * @param result 当前操作返回值
  */
 public static void logAfterReturning(String method, Object result){
  System.out.println("当前操作运算时 : " + method + " 返回值是 : " + result);
 }

 /**
  * 当前操作产生的异常
  * @param method 当前操作
  * @param e 发生的异常
  */
 public static void logAfterThrowing(String method, Exception e){
  System.out.println("当前运算时 : " + method + " 发生的异常是 : " + e);
 }
}

JDK 动态代理的工厂类 JDKProxyFactory.java

/**
 * JDK 动态代理的工厂
 * Created by YongXin Xue on 2020/05/05 13:02
 */
public class JDKProxyFactory {

 /**
  * 通过 JDK 底层自带的 JDK 动态代理技术解决日志需求问题
  * @param target
  * @return
  */
 public static Object createJDKProxy(Object target){
  /**
   * Proxy 是Jdk中自带的一个工具类(反射包下,属于反射的功能).
   * Proxy类的作用: 它可以帮我们创建代理类或实例
   * 方法newProxyInstance()说明: 创建代理对象实例
   * 第一个参数是: 目标对象的类加载器
   * 第二个参数是: 目标对象实现的所有接口
   * 第三个参数是: InvocationHandler 接口的实例
   * InvocationHandler 接口的实现类可以对代理的目标对象方法进行增强操作.
   * 代理的目标对象 ===>>> 需要额外增加功能的类(对象实例)
   * 增强操作 ===>>> 给原来功能添加的额外功能叫增强操作 ( 日记就是增强操作 )
   */
  return Proxy.newProxyInstance(
    target.getClass().getClassLoader(),
    target.getClass().getInterfaces(),
    new InvocationHandler() { // 匿名内部类
     /**
      * invoke 方法是 InvocationHandler 接口中唯一的方法
      * 代理对象每次调用方法时,都会执行 invoke() 方法 , 所有的增强操作都需要在invoke()方法中完成
      * @param proxy  代理对象实例
      * @param method 代理调用的方法的反射 Method 对象实例
      * @param args  调用代理方法时传递进来的参数
      * @return
      * @throws Throwable
      */
     @Override
     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      System.out.println("代理调用了 invoke 方法 ");
      System.out.println(method);  //打印方法信息
      System.out.println(Arrays.asList(args)); //打印参数信息
      // invoke() 方法执行代理对象的(加法 / 除法 / 增强日志)操作
      Object result = null;
      LogUtils.logBefore(method.getName(), args);
      try {
       // 1. 返回值是 method 方法调用时的返回值
       result = method.invoke(target, args);
       // 2. 增强操作
       LogUtils.logAfterReturning(method.getName(), result);
      }catch (Exception e){
       LogUtils.logAfterThrowing(method.getName(), e);
      }
      // invoke() 返回代理方法的返回值
      return result;
     }
    });
 }

 // 测试代码
 public static void main(String[] args) {
  // 目标对象
  Calculate target = new CalculateImpl();
  // 创建 Calculate 的代理对象实例
  Calculate calculateProxy = (Calculate) createJDKProxy(target );
  // jdk动态代理对象实例和目标对象实例 同宗同族 ( 他们都实现了相同的接口 )
  System.out.println(calculateProxy instanceof Calculate);
  System.out.println(target instanceof Calculate);

  System.out.println( "代理方法的结果是 : " + calculateProxy.div(100,20) );

  // jdk动态代理创建出来的代理对象实例 是 目标对象 接口的一个实现类
  // 这个代理对象 和 目标对象类没有父子关系 ( 只能用接口接收代理对象 )
 }
}

使用 Cglib 代理

  1. Jdk动态代理是通过实现目标对象所有接口产生一个代理对象实例从而解决问题.
  2. 如果目标对象没有接口.则可以使用Cglib动态代理技术.
  3. Cglib动态代理技术对目标对象有没有实现接口,没有要求.
  4. Cglib动态代理技术,是通过拷贝然后修改目标对象的类的字节码来产生一个代理对象
  5. 而且这个Cglib产生的代理对象实例 是 目标对象的一个子类.

IA 接口 IA.java

public interface IA {
 public String show(String start);
}

IA 实现类 IAImpl.java

public class IAImpl implements IA {
 @Override
 public String show(String start) {
  System.out.println(start + "开始表演!");
  return start + "表演的不错!!";
 }
}

使用 Cglib 代理 CglibProxyFactory.java

/**
 * 使用 Cglib 代理
 * Created by YongXin Xue on 2020/05/05 15:03
 */
public class CglibProxyFactory {

 public static Object createCglibProxy(Object target){
  // 是 Cglib 用于创建代理对象的增强工具类
  Enhancer enhancer = new Enhancer();
  // Cglib需要对目标对象的Class字节码进行修改.
  // Cglib产生的代理对象实例.是目标对象的子类
  enhancer.setSuperclass(target.getClass());
  // 只要是代理都会对原来的内容进行增强操作 ( 增强就是在原有功能上 额外添加的功能 )
  // setCallback() 设置用于增强 操作的实现类( MethodInterceptor对代理方法进行拦截 )
  // 每次只要调用Cglib代理的方法,都会执行 MethodInterceptor 接口中 intercept() 方法
  enhancer.setCallback(new MethodInterceptor() {
   /**
    * intercept() 方法 跟 JDK 代理中的 InvocationHandler接口中 invoke() 功能完全一样
    * @param proxy  Cglib代理对象实例
    * @param method 调用方法的反射对象实例
    * @param args 调用方法时传递的参数
    * @param methodProxy 代理方法的method代理对象
    * @return  是代理对象方法的返回值.
    * @throws Throwable
    */
   @Override
   public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    Object result = null;
    try {
     LogUtils.logBefore(method.getName(), args);
     // 调用目标方法 [加 / 减 / 乘 / 除 / 或具体方法]
     result = method.invoke(target, args);
     // 执行增强代码
     LogUtils.logAfterReturning(method.getName(), args);
    }catch (Exception e){
     e.printStackTrace();
     LogUtils.logAfterThrowing(method.getName(), e);
    }

    return result;
   }
  });
  // 创建 Cglib 代理对象实例
  return enhancer.create();
 }
 //测试
 public static void main(String[] args) {
  // 目标对象
  Calculate calculate = new CalculateImpl();
  // 创建代理对象实例
  Calculate cglibProxy = (Calculate) createCglibProxy(calculate);
  // 调用代理方法式会执行 MethodInterceptor 接口中 intercept() 方法
  int result = cglibProxy.div(120, 0);
  // Cglib 代理 是目标子类执行 MethodInterceptor 接口中 intercept() 方法
  System.out.println(cglibProxy instanceof Calculate);
 }
}

优点:在没有接口的情况下,同样可以实现代理的效果。
缺点:同样需要自己编码实现代理全部过程。

到此这篇关于Java使用JDK与Cglib动态代理技术统一管理日志记录的文章就介绍到这了,更多相关Java动态代理统一管理日志 内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java动态代理的应用详解

    动态代理其实就是java.lang.reflect.Proxy类动态的根据您指定的所有接口生成一个class byte,该class会继承Proxy类,并实现所有你指定的接口(您在参数中传入的接口数组):然后再利用您指定的classloader将 class byte加载进系统,最后生成这样一个类的对象,并初始化该对象的一些值,如invocationHandler,以即所有的接口对应的Method成员. 初始化之后将对象返回给调用的客户端.这样客户端拿到的就是一个实现你所有的接口的Proxy对象

  • java动态代理和cglib动态代理示例分享

    java动态代理类可以分为两种. 静态代理:由程序员创建或特定工具自动生成源代码,再对其编译.在程序运行前,代理类的.class文件就已经存在了. 动态代理:在程序运行时,运用反射机制动态创建而成. 一.首先我们进行java动态代理的演示. 现在我们有一个简单的业务接口Saying,如下: 复制代码 代码如下: package testAOP;public interface Saying {public void sayHello(String name);    public void ta

  • java 静态代理 动态代理深入学习

    一.代理模式 代理模式是常用的java设计模式,特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等. 代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务. 按照代理的创建时期,代理类可以分为两种: 静态代理:由程序员创建或特定工具自动生成源代码再对其编译.在程序运行前代理类的.class文件就已经存在了. 动态代理:在

  • 详解java动态代理的2种实现方式

    java的动态代理在接java的api上有说明,这里就不写了.我理解的代理: 对特定接口中特定方法的功能进行扩展,这就是代理.代理是通过代理实例关联的调用处理程序对象调用方法. 下面通过一个例子看一下: 接口: public interface Num { void show(); int getNum(); int getProduct(int x); } 实现类: public class MyNum implements Num { @Override public int getNum(

  • java实现动态代理方法浅析

    一些Java项目中在mybatis与spring整合中有MapperScannerConfigurer的使用,该类通过反向代理自动生成基于接口的动态代理类. 有鉴于此,本文浅析了java的动态代理. 本文使用动态代理模拟处理事务的拦截器. 接口: public interface UserService { public void addUser(); public void removeUser(); public void searchUser(); } 实现类: public class

  • 基于接口实现java动态代理示例

    Subject.java 复制代码 代码如下: package _20140416_; import java.util.List; public interface Subject {   public String say(String name,int age);   public List<Person> getAllList(String name);} RealSubject.java 复制代码 代码如下: package _20140416_; import java.util.

  • Java动态代理分析及简单实例

      Java动态代理 要想了解Java动态代理,首先要了解什么叫做代理,熟悉设计模式的朋友一定知道在Gof总结的23种设计模式中,有一种叫做代理(Proxy)的对象结构型模式,动态代理中的代理,指的就是这种设计模式. 在我看来所谓的代理模式,和23种设计模式中的"装饰模式"是一个东西.23种设计模式中将它们作为两种模式,网上也有些文章讲这两种模式的异同,从细节来看,确实可以人为地区分这两种模式,但是抽象到一定高度后,我认为这两种模式是完全一样的.因此学会了代理模式,也就同时掌握了装饰模

  • java代理模式与动态代理模式详解

    1.代理模式 所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动.在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之前起到中介的作用.代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用. 生活中的例子:过年加班比较忙,没空去买火车票,这时可以打个电话到附近的票务中心,叫他们帮你买张回家的火车票,当然这会附加额外的劳务费.但要清楚票务中心自己并不卖票,只有火车站才真正卖票,票务中心卖给你的票其实是通过火车站实现的.这点很重要!

  • 详解java中动态代理实现机制

    代理模式是常用的java设计模式,它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务. JAVA各种动态代理实现的比较 接口 interface AddInterface{ int add(int a, int b); } interface SubInterfa

  • java使用动态代理来实现AOP(日志记录)的实例代码

    下面是一个AOP实现的简单例子: 首先定义一些业务方法: 复制代码 代码如下: /** * Created with IntelliJ IDEA. * Author: wangjie  email:tiantian.china.2@gmail.com * Date: 13-9-23 * Time: 下午3:49 */public interface BussinessService {    public String login(String username, String password

随机推荐