这篇文章主要讲解了Java如何使用JDK与Cglib动态代理技术统一管理日志记录,内容清晰明了,对此有兴趣的小伙伴可以学习一下,相信大家阅读完之后会有帮助。
站在用户的角度思考问题,与客户深入沟通,找到汉寿网站设计与汉寿网站推广的解决方案,凭借多年的经验,让设计与互联网技术结合,创造个性化、用户体验好的作品,建站类型包括:成都网站设计、成都网站建设、外贸网站建设、企业官网、英文网站、手机端网站、网站推广、空间域名、虚拟空间、企业邮箱。业务覆盖汉寿地区。
Java中动态代理主要有JDK和CGLIB两种方式。
区别主要是jdk是代理接口,而cglib是代理类。
计算接口 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 代理
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动态代理技术统一管理日志记录有进一步的了解,如果还想学习更多内容,欢迎关注创新互联行业资讯频道。