当前位置: 首页 > news >正文

JAVAEE 代理

Java 代理是一种设计模式和机制,允许你通过代理对象间接访问目标对象。这种模式在许多场景下非常有用,比如实现方法调用拦截、添加额外功能(如日志、事务管理)、控制访问权限等。

Java 提供了两种主要的代理方式:静态代理和动态代理。

特点:代理类在编译时就已经确定。
实现步骤

  • 定义一个接口。
public interface Singer {void singing();int dance();
}
  • 创建目标类实现该接口。
public class S implements Singer {@Overridepublic void singing() {System.out.println("s 唱歌");}@Overridepublic int dance() {System.out.println("tiaowu");return 0;}
}
  • 创建代理类实现相同接口,并在内部持有目标对象的引用。
  • 在代理类的方法中调用目标对象的方法,并可添加额外逻辑。
public class daili implements  Singer{private Singer S = new S();@Overridepublic void singing() {System.out.println("收钱");S.singing();}@Overridepublic int dance() {System.out.println("收钱");S.dance();return 0;}
}

2. 动态代理(JDK 动态代理)

特点:代理类在运行时动态生成,无需手动编写。
核心组件
  • InvocationHandler:处理代理对象方法调用的接口,需实现 invoke 方法。
  • Proxy:生成代理对象的工具类,通过 Proxy.newProxyInstance() 创建代理。
实现步骤
  1. 定义接口和目标类(同静态代理)。
public interface Singer {void dance();int singing();}public class S implements Singer {@Overridepublic void dance() {System.out.println("S 在跳舞");}@Overridepublic int singing() {System.out.println("S 在唱歌");return 0;}
}

2.创建 InvocationHandler 实现类,在 invoke 方法中添加额外逻辑。

3.使用 Proxy.newProxyInstance() 生成代理对象。

public class Test {public static void main(String[] args) {S s =new S();Ruler ruler = new Ruler(s);//Proxy.newProxyInstance 是 Java 中用于创建动态代理实例的方法。它有三个参数://ClassLoader 获取 类 的类加载器。类加载器用于加载动态代理类的字节码。使用目标类的类加载器可以确保动态代理类与目标类在同一个加载环境中//Class<?>[] 一个接口类数组,表示动态代理类需要实现的接口//InvocationHandler InvocationHandler 是一个接口,用于处理代理对象上方法调用的逻辑。//当通过代理对象调用接口方法时,调用会被转发到 InvocationHandler 的 invoke 方法中,由 ruler 来处理具体的逻辑。//构建了 以原被代理类为基准的代理类的一个对象// o 已经等同于 Singer singer = new daili(); 这个singer了Object o = Proxy.newProxyInstance(S.class.getClassLoader(), new  Class[]{Singer.class}, ruler);System.err.println(o.getClass().toString());//检查代理对象是否实现了 Singer 接口,然后将其强制转换为 Singer 类型。if(o instanceof Singer){Singer singer =  (Singer)o;singer.dance();System.out.println("调用singing");singer.singing();singer.toString();}}
}//额外逻辑
//Ruler 类实现了 InvocationHandler 接口,用于处理代理对象的方法调用。
class Ruler implements InvocationHandler{private Singer s;public Ruler(Singer s) {this.s = s;}@Overridepublic Object invoke(Object p, Method method, Object[] args) throws Throwable {
//        System.out.println(p.getClass().toString());System.out.println("调用前");//调用目标对象 s 的方法,方法名和参数由 method 和 args 指定。Object returnVal = method.invoke(s, args);System.out.println("调用后");return returnVal;}
}

3. CGLIB 动态代理特点:无需接口,通过继承目标类生成子类代理。

适用场景:目标类没有实现接口时。
核心组件
  • Enhancer:CGLIB 的核心类,用于生成代理对象。
public class Target implements TargetInteface {@Overridepublic void method1() {System.out.println("method1 running ...");}@Overridepublic void method2() {System.out.println("method2 running ...");}@Overridepublic int method3(Integer i) {System.out.println("method3 running ...");return i;}
}public interface TargetInteface {void method1();void method2();int method3(Integer i);
}public class TargetProxy {public static  <T> Object getTarget(T t) {//新构建了一个 新的 代理类的对象return Proxy.newProxyInstance(t.getClass().getClassLoader(), t.getClass().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// proxy就是目标对象t,method就是调用目标对象中方法,args就是调用目标对象中方法的参数。//比如说:代理对象.method1(),这时proxy就是目标类,method1就是method,args就是method1方法参数。System.out.println("执行方法前...");Object invoke = method.invoke(t, args);System.out.println("执行方法后...");return invoke;}});}
}public class TargetUser {public static void main(String[] args) {TargetInteface target = (TargetInteface) TargetProxy.getTarget(new Target());target.method1();System.out.println("-----------------------------");target.method2();System.out.println("-----------------------------");System.out.println(target.method3(3));print(target);}public  static void  print( Object target){Class aClass = target.getClass();Class cl = target.getClass();Class supercl = cl.getSuperclass();String modifiers = Modifier.toString(cl.getModifiers());if (modifiers.length() > 0)System.out.print(modifiers + " ");System.out.print("class:" + cl.getName());if (supercl != null && supercl != Object.class)System.out.print("extends:" + supercl.getName());System.out.print("\n{\n");printConstructors(cl);System.out.println();printMethods(cl);System.out.println();printFields(cl);System.out.println("}");System.exit(0);
}public static void printConstructors(Class cl) {Constructor[] consturctors = cl.getDeclaredConstructors();for (Constructor c : consturctors) {String name = c.getName();System.out.println(" ");String modifiers = Modifier.toString(c.getModifiers());if (modifiers.length() > 0)System.out.print(modifiers + " ");System.out.print(name + "(");Class[] paramTypes = c.getParameterTypes();for (int j = 0; j < paramTypes.length; j++) {if (j > 0)System.out.print(", ");System.out.print(paramTypes[j].getName());}System.out.println(");");}}public static void printMethods(Class cl) {Method[] methods = cl.getDeclaredMethods();for (Method m : methods) {Class reType = m.getReturnType();String name = m.getName();System.out.print("  ");String modifiers = Modifier.toString(m.getModifiers());if (modifiers.length() > 0)System.out.print(modifiers + " ");System.out.print(reType.getName() + " " + name + "(");Class[] paramTypes = m.getParameterTypes();for (int j = 0; j < paramTypes.length; j++) {if (j > 0)System.out.print(", ");System.out.print(paramTypes[j].getName());}System.out.println(");");}}public static void printFields(Class cl) {Field[] fields = cl.getDeclaredFields();for (Field f : fields) {Class type = f.getType();String name = f.getName();System.out.print("  ");String modifiers = Modifier.toString(f.getModifiers());if (modifiers.length() > 0)System.out.print(modifiers + " ");System.out.println(type.getName() + " " + name + ";");}}}

4. 三种代理方式对比

特性静态代理JDK 动态代理CGLIB 动态代理
代理类生成时机编译时手动编写运行时动态生成运行时动态生成
是否需要接口否(通过继承实现)
性能高(无反射)中(反射调用)高(ASM 字节码增强)
复杂度高(需手动编写代理类)低(反射 API 简洁)低(CGLIB API 简洁)

总结

  • 静态代理:简单但维护成本高,适用于代理类较少的场景。
  • JDK 动态代理:基于接口,灵活但有局限性。
  • CGLIB 动态代理:基于继承,功能强大,适合无接口的类。
http://www.lryc.cn/news/582850.html

相关文章:

  • 短视频电商APP源码开发技术栈解析:音视频、商品链路与互动设计
  • 怪物机制分析(有限状态机、编辑器可视化、巡逻机制)
  • DCL学习
  • SpringAI学习笔记-MCP客户端简单示例
  • C#Halcon从零开发_Day18_OCR识别
  • SpringAI系列 - 基于Spring AI 1.0.0 的AI助手实现示例
  • 图像梯度处理与边缘检测:OpenCV 实战指南
  • Apache Atlas编译打包,可运行包下载地址
  • VM上创建虚拟机以及安装RHEL9操作系统并ssh远程连接
  • 7月8日星期二今日早报简报微语报早读
  • XSLT注入与安全修复方法
  • 人工智能与人工智障———仙盟创梦IDE
  • 【Note】《Kafka: The Definitive Guide》第11章:Stream Processing
  • 【Bluedroid】BLE 地址解析列表的初始化与清除机制(btm_ble_resolving_list_init)
  • MySQL 8.0 OCP 1Z0-908 题目解析(23)
  • Kafka消息倾斜
  • 编码器(Encoder)和解码器(Decoder)
  • Spring注解驱动开发
  • window wsl 环境下编译openharmony,HarmonyOS 三方库 FFmpeg
  • Flutter基础(前端教程④-组件拼接)
  • Ansible 介绍及安装
  • ffmpeg 中config 文件一些理解
  • OSPFv3和v2区别(续)
  • 客户频繁变更需求,如何保障项目进度稳定
  • Spring AI:ETL Pipeline
  • 深入解读MCP:构建低延迟、高吞吐量通信中间件
  • C语言基础(1)
  • STM32第十八天 ESP8266-01S和电脑实现串口通信
  • Flutter编译安卓应用时遇到的compileDebugJavaWithJavac和compileDebugKotlin版本不匹配的问题
  • 超低功耗CC2340R SimpleLink™ 系列 2.4GHz 无线 MCU支持BLE5.3/Zigbee/Thread/专有协议