当前位置: 首页 > 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.xdnf.cn/news/1087975.html

相关文章:

  • 3D 演示动画在汽车培训与教育领域中的应用
  • Modbus TCP转Profinet网关实现视觉相机与西门子PLC配置实例研究
  • Anolis OS 23 架构支持家族新成员:Anolis OS 23.3 版本及 RISC-V 预览版发布
  • 面试题--系统如何处理异常
  • SpringAI学习笔记-MCP服务器简单示例
  • 【UE5】虚幻引擎小百科
  • 后台设计指南:系统架构、交互规范与工具实战全流程解析
  • (C++)list列表相关基础用法(C++教程)(STL库基础教程)
  • Android T startingwindow使用总结
  • 深度剖析:向70岁老系统植入通信芯片——MCP注入构建未来级分布式通信
  • 容器技术技术入门与 Docker 环境部署
  • Flutter基础(前端教程④-组件拼接)
  • Python Web应用开发之Flask框架高级应用(三)——蓝图(Blueprints)
  • uniapp b树
  • 【LeetCode 热题 100】142. 环形链表 II——快慢指针
  • FairyGUI 实现 Boss 双层血条动画
  • Crazyflie无人机集群控制笔记(二)通过SDK实时对接Crazyswarm2及NOKOV度量动捕数据
  • jmeter 性能测试步骤是什么?
  • 代码详细注释:C语言实现控制台用户注册登录系统
  • C++进阶—二叉树进阶
  • [2025CVPR]SGC-Net:开放词汇人机交互检测的分层粒度比较网络解析
  • 【网络协议安全】任务14:路由器DHCP_AAA_TELNET配置
  • Redis基础数据结构
  • Serverless 数据库来了?无服务器数据库 vs 传统数据库有何不同?
  • 学习日记-spring-day43-7.8
  • 日语学习-日语知识点小记-构建基础-JLPT-N3阶段(1):新的开始-尊他开始
  • Docker企业级应用:从入门到生产环境最佳实践
  • ReactNative【实战系列教程】我的小红书 4 -- 首页(含顶栏tab切换,横向滚动频道,频道编辑弹窗,瀑布流布局列表等)
  • 论文略读:UniPELT: A Unified Framework for Parameter-Efficient Language Model Tuning
  • C++(STL源码刨析/vector)