Java使用JDK与Cglib * 技术统一管理日志记录
作者:蓝山. 发布时间:2021-11-09 00:52:31
标签:Java, , ,统一管理,日志
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 代理
Jdk * 是通过实现目标对象所有接口产生一个代理对象实例从而解决问题.
如果目标对象没有接口.则可以使用Cglib * 技术.
Cglib * 技术对目标对象有没有实现接口,没有要求.
Cglib * 技术,是通过拷贝然后修改目标对象的类的字节码来产生一个代理对象
而且这个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


猜你喜欢
- 前言我们都知道WebApi是依赖于Asp.Net MVC的 ,所以,想创建WebApi,就需要先创建一个Asp.Net MVC项目。但用Vi
- 本文实例讲述了android获取当前运行Activity名字的方法,可以避免即时聊天再出现通知的情况。分享给大家供大家参考。具体方法如下:最
- 在模板文件的表达式中,可以使用“${T(全限定类名).方法名(参数)}”这种格式来调用Java类的静态方法。开发环境:IntelliJ ID
- 主要完成任务:1.read read 并行化2.read write 不允许3.write write 不允许public class Re
- 最近在做一个项,有一个收藏的功能。后来看到了一点资讯的收藏动画,感觉不错,所有自己就实现了一下。这是效果:附上完整的代码,其中Animati
- 我们先来看下运行效果图Form1.cs代码:using System;using System.Collections.Generic;us
- 今天一个读者问我关于Android通过调用Webservice实现天气预报这篇文章的源码下载后出现的错误Could not find cla
- 模拟新闻 APP 的界面1)写 ListView 之前先写布局: 这里有两种 Item 的布局:<?xml version=
- 这篇文章主要介绍了JAVA基于SnakeYAML实现解析与序列化YAML,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考
- 以下代码可以获得已安装应用(包)的信息:// 包管理器PackageManager pm = getPackageManager();//获
- 引言思考:HashTable是线程安全的,为什么不推荐使用?HashTable是一个线程安全的类,它使用synchronized来锁住整张H
- 本文实例讲述了Java实现储存对象并按对象某属性排序的几种方法。分享给大家供大家参考,具体如下:在编程的时候,经常会出现对某一种类的对象们按
- 本文实例为大家分享了Android实现背景图滑动变大松开回弹的具体代码,供大家参考,具体内容如下原图放大后1、自定义view继承Scroll
- 本文实例讲述了Java Socket实现多线程通信功能的方法。分享给大家供大家参考,具体如下:前面的文章《Java Socket实现单线程通
- 摘要分析验证码素材图片混淆原理,并采用selenium模拟人拖动滑块过程,进而破解验证码。人工验证的过程1、打开威锋网注册页面2、移动鼠标至
- 自定义加载yml,附源码解读昨天在对公司的微服务配置文件标准化的过程中,发现将原来的properties文件转为yml文件之后,微服务mod
- 反射提供了封装程序集、模块和类型的对象(Type 类型)。可以使用反射动态创建类型的实例,将类型绑定到现有对象,或从现有对象获取类型并调用其
- 前言借用《Effactive Java》这本书中的话,float和double类型的主要设计目标是为了科学计算和工程计算。他们执行二进制浮点
- 指针的概念:指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址。要搞清一个指针需要搞清指针的四方面的内容:指针的类型,指针所指
- private void button1_Click(object sender, EventArgs e) &nbs