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

作者:蓝山. 时间:2021-11-09 00:52:31 

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);
}
}

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

来源:https://blog.csdn.net/Lance_welcome/article/details/105933381

标签:Java, , ,统一管理,日志
0
投稿

猜你喜欢

  • 浅谈mybatis中的#和$的区别 以及防止sql注入的方法

    2023-03-24 10:22:28
  • 如何在Android中实现左右滑动的指引效果

    2023-06-23 09:08:47
  • java 文件上传到读取文件内容的实例

    2023-11-09 22:00:27
  • Java实现XML文件学生通讯录

    2023-07-23 19:21:49
  • 深入剖析Android消息机制原理

    2023-09-30 01:57:11
  • Java中包装类介绍与其注意事项

    2023-03-20 18:26:36
  • Struts2学习笔记(8)-Result常用类型

    2023-06-05 11:10:19
  • Java经典用法总结(二)

    2023-11-24 20:39:10
  • Java异常处理机制try catch流程详解

    2022-09-23 08:51:09
  • Flutter自定义圆盘取色器

    2023-07-05 23:55:43
  • Spring Security配置多个数据源并添加登录验证码的实例代码

    2022-11-19 13:49:26
  • Unity Shader实现黑幕过场效果

    2022-01-13 00:18:10
  • Java程序测试上传Maven工程代码示例解析

    2022-01-21 18:43:25
  • spring如何实现两个xml配置文件间的互调

    2021-06-07 20:50:15
  • 深入理解Java 类加载全过程

    2023-10-20 12:34:23
  • SpringMVC @GetMapping注解路径冲突问题解决

    2022-12-18 01:43:17
  • AsyncTask官方文档教程整理

    2023-07-31 20:25:08
  • 浅谈java+内存分配及变量存储位置的区别

    2022-07-09 00:46:47
  • Maven的porfile与SpringBoot的profile结合使用案例详解

    2023-11-14 00:07:59
  • Java之SSM中bean相关知识汇总案例讲解

    2021-11-10 06:16:26
  • asp之家 软件编程 m.aspxhome.com