高效便捷Java代理技术:轻松实现Web集成

server/2025/2/13 18:55:19/

一、什么是代理

        在 Java 开发中,Java代理(Proxy)是Java编程语言中一个非常重要的概念,通过引入一个代理类来间接访问目标对象,在不修改原有目标类代码的前提下,增加或修改目标类的行为,将复杂的 Java 代码分解成更易处理的部分,同时也能在不同环境中独立运行。

二、理解Java代理的基本概念

        Java代理(Proxy)是指能够从 Java 代码中分离出来并执行特定功能的其他程序。这些代理通常使用代理类来实现,代理类负责管理 Java 代码的运行,并将结果返回给主程序,举个生活中的例子,某皮革厂老板带着小姨子跑路了,连累很多企业主生活揭不开锅,被迫去申请仲裁,法院会委派一位代理律师去全权负责处理该事宜,这其实就用到了代理模式,再比如租房,找中介,中介会代理房东带你看房,签订合同等,也是用到了代理模式

三、代理模式

        代理模式(Proxy Pattern)是软件开发中常用的设计模式之一,它通过创建代理对象来控制对原始对象的访问。这种模式在面向切面编程(AOP)、远程方法调用(RMI)、事务管理等场景中发挥着重要作用。

代理模式UML结构图
  • Subject(抽象角色)

    定义代理类和真实主体的公共对外方法,也是代理类代理真实主体的方法

  • Proxy(代理角色/代理对象)

    代理角色内部包含了对真实角色的引用,从而可以在任何时候操作真实角色对象,包括在真实角色处理前后做一些预处理或善后工作

  • RealSubject(真实角色/目标对象)

    真实角色是业务逻辑的具体执行者,真正实现业务逻辑的类

 四、代理模式的两种实现

1.静态代理

        静态代理是指在程序运行前就已经存在代理类的字节码文件,代理类和目标类的关系在运行前就已确定,且代理类通常是手工编写的,但是其实际应用场景非常非常少,日常开发几乎看不到使用静态代理的场景。

静态代理的两种实现方式

基于接口编程

java">//抽象主题类
public interface UserService {public void select();   public void update();
}//委托类
public class UserServiceImpl implements UserService {//  public void select() {  System.out.println("查询 selectById");}public void update() {System.out.println("更新 update");}
}//代理类 通过静态代理对功能进行增强,在调用select和update之前记录一些日志
public class UserServiceProxy implements UserService {private UserService target; // 被代理的对象//在构造函数中,通过传入的参数`target`来初始化`target`成员变量。//这样,代理类就可以将实际的业务逻辑委托给被代理的对象来完成。public UserServiceProxy(UserService target) {this.target = target;}public void select() {before();target.select();    // 这里才实际调用真实主题角色的方法after();}public void update() {before();target.update();    // 这里才实际调用真实主题角色的方法after();}private void before() {     // 在执行方法之前执行System.out.println(String.format("log start time [%s] ", new Date()));}private void after() {      // 在执行方法之后执行System.out.println(String.format("log end time [%s] ", new Date()));}
}

基于继承

java">public class UserServiceProxy extends UserServiceImpl {public void select() {before();super.select();    // 这里才实际调用真实主题角色的方法after();}public void update() {before();super.update();    // 这里才实际调用真实主题角色的方法after();}private void before() {     // 在执行方法之前执行System.out.println(String.format("log start time [%s] ", new Date()));}private void after() {      // 在执行方法之后执行System.out.println(String.format("log end time [%s] ", new Date()));}
}

静态代理优点

  • 封装性强:代理类对真实角色进行封装,使真实角色处理的业务更加纯粹,不再去关注一些公共的事情,只需要和代理类交互
  • 扩展性强:通过代理类,可以在不修改真实对象的情况下,对其进行功能扩展或增强
  • 访问控制:通过代理类可以控制客户端对真实对象的访问,实现访问权限的管理,例如在访问某些敏感方法前后进行权限验证或日志记录静态代理缺点 
  • 编码复杂:每一个需要代理的对象都需要单独编写代理类,如果真实对象很多,代理类的数量也会很多,增加了系统的复杂度
  • 灵活性差:由于静态代理在编译期间就已经确定了代理对象和真实对象的关系,因此无法在运行时动态改变代理对象,灵活性较差
  • 局限性:静态代理只能代理固定类型的对象,无法代理不同类型的对象,因此对于不同类型的真实对象需要编写不同的代理类
  • 难维护:当真实对象的接口发生变化时,代理类的接口也需要相应地进行修改,维护起来相对比较麻烦

2.动态代理

        动态代理是指在程序运行时动态地创建代理类,无需手动编写代理类的源代码。动态代理主要依靠JDK的反射(Reflection)API来实现。

动态代理的两种实现方式

基于接口实现的动态代理——JDK动态代理

JDK动态代理主要涉及两个类:java.lang.reflect.Proxy 和 java.lang.reflect.InvocationHandler

实现原理:

java">public class JdkDynamicProxy implements InvocationHandler {private Object target;public JdkDynamicProxy(Object target) {this.target = target;}public Object getProxy() {return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("JDK代理前置处理");Object result = method.invoke(target, args);System.out.println("JDK代理后置处理");return result;}
}

使用示例:

java">UserService service = new UserServiceImpl();
UserService proxy = (UserService) new JdkDynamicProxy(service).getProxy();
proxy.saveUser();

基于继承实现的动态代理——CGLIB

实现原理:

java">public class CglibProxy implements MethodInterceptor {public Object getProxy(Class<?> clazz) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(clazz);enhancer.setCallback(this);return enhancer.create();}@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("CGLIB代理前置处理");Object result = proxy.invokeSuper(obj, args);System.out.println("CGLIB代理后置处理");return result;}
}

代理机制对比分析

特性静态代理JDK动态代理CGLIB代理
实现方式手动编码反射机制字节码增强
代理目标接口接口
性能中等较高(优化后)
依赖JDK原生第三方库
方法过滤不支持支持支持
初始化消耗编译时运行时运行时

动态代理优点

  • 灵活性高:与静态代理相比,动态代理可以在运行时动态地生成代理类,无需提前编写大量的代理类,更加灵活
  • 代码简洁:由于动态代理是在运行时生成的,因此可以大大减少代码量,使代码更加简洁、清晰
  • 维护成本低:由于动态代理不需要为每个被代理的类编写单独的代理类,因此当原始类的接口发生变化时,对代码的影响较小,维护成本低
  • 适用范围广:动态代理可以代理任意实现了接口的类,不限于特定的类或接口类型,因此适用范围更广泛

动态代理缺点 

  • 性能低:相比静态代理,动态代理在运行时需要动态生成代理类,因此可能会稍微降低程序的运行效率
  • 复杂度高:动态代理涉及到反射机制和动态生成字节码等技术,因此相对于静态代理而言,实现和理解的难度较高
  • 不支持对类的直接代理:动态代理只能代理实现了接口的类,无法直接代理类,这在某些情况下可能会限制其使用
  • 难以调试:动态代理生成的代理类通常是在运行时动态生成的字节码,因此在调试时可能会增加一定的难度,不如静态代理那样直观

五、代理在Spring框架中的应用

AOP切面编程

  • 切面(Aspect):在AOP中,切面是一个横切关注点的模块化,如日志记录、事务管理等。切面可以横切多个类或方法,将横切关注点从业务逻辑中分离出来
  • 通知(Advice):通知是切面在特定连接点(如方法调用前后)执行的动作。Spring支持多种类型的通知,如前置通知、后置通知、环绕通知等
  • 代理实现:在Spring AOP中,代理是实现切面的关键机制。当方法被调用时,代理会拦截方法调用,并根据配置执行相应的通知逻辑。如果目标对象实现了接口,Spring默认使用JDK动态代理;如果目标对象没有实现接口,则使用CGLIB动态代理

事务管理

  • 事务:事务是一组要么全都执行成功,要么全都回滚的操作。事务管理对于确保数据一致性和完整性至关重要
  • 声明式事务管理:Spring提供了声明式事务管理,允许开发者通过注解或XML配置来管理事务,而无需手动编写事务管理代码
  • 代理实现:在声明式事务管理中,Spring使用代理来拦截方法调用,并在方法执行前后添加事务管理的逻辑。例如,在方法执行前开启事务,在方法执行后提交或回滚事务

使用Spring AOP和JDK动态代理的代码示例

java">import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.stereotype.Component;// 目标接口
public interface UserService {void saveUser(String username, String password);
}// 目标类实现
@Component
public class UserServiceImpl implements UserService {@Overridepublic void saveUser(String username, String password) {System.out.println("保存用户信息: " + username);}
}// 切面类
@Aspect
public class LoggingAspect {@Before("execution(* com.example.service.UserServiceImpl.saveUser(..))")public void logBefore() {System.out.println("执行saveUser方法前记录日志");}
}// 代理工厂类(模拟Spring AOP的代理创建过程)
public class AopProxyFactory {public static Object createProxy(Object target) {ProxyFactory proxyFactory = new ProxyFactory(target);// 添加切面逻辑// proxyFactory.addAdvice(new LoggingAdvice()); // 模拟代理过程return proxyFactory.getProxy();}
}// 客户端代码
public class Client {public static void main(String[] args) {UserService userService = new UserServiceImpl();UserService proxyUserService = (UserService) AopProxyFactory.createProxy(userService);proxyUserService.saveUser("testUser", "password123");}
}


http://www.ppmy.cn/server/167398.html

相关文章

信息科技伦理与道德3-3:智能决策

2.3 智能控制 智能控制算法介绍 智能控制算法的优化&#xff1a;性能提升的秘诀 https://blog.csdn.net/universsky2015/article/details/137309308 案例一&#xff1a;特斯拉自动驾驶汽车未能识别白色卡车导致车祸

React 中的 useMemo 和 useCallback 有什么区别?

useMemo 和 useCallback 是 React 中的两个 Hook,主要用于性能优化,但它们的用途和工作方式有所不同。以下是它们之间的主要区别: 1. useMemo 用途:用于记忆计算值。它可以避免在每次组件渲染时重新计算一个值,只有当依赖项发生变化时,才会重新计算。 返回值:返回缓存的…

网络安全—DDoS攻防

背景简述&#xff1a;DDoS攻击分为很多类型&#xff0c;有消耗网络带宽的流量攻击&#xff0c;有消耗服务器资源的应用层攻击等。影响巨大&#xff0c;且让无论大公司还是小公司都肃然“起敬”的当属&#xff1a;流量攻击。在流量越来越廉价的今天&#xff0c;攻击流量小则几百…

将Markdown格式文件与word文件相互转化方法

不多说直接上方法 下载Writage软件 Writage是一款word插件&#xff0c;下载网址为&#xff1a;http://www.writage.com/。 下载之后直接安装即可。 安装之后在使用word打开和使用word软件另存为的时候就出现Markdown格式了

42页精品PPT | 数字政府智慧政务大数据平台建设方案

这份《数字政府智慧政务大数据平台建设方案》PPT详细阐述了数字政府智慧政务大数据平台的建设背景、目标、架构以及实施策略。方案围绕解决当前政务服务中的痛点&#xff0c;如“互联网政务服务”推进中的数据共享难题、数据安全风险以及部门间业务流程整合等问题展开。 通过构…

Python+Selenium+Pytest+POM自动化测试框架封装

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 1、测试框架简介 1&#xff09;测试框架的优点 代码复用率高&#xff0c;如果不使用框架的话&#xff0c;代码会显得很冗余。可以组装日志、报告、邮件等一些高…

CSS 性能优化全攻略:提升网站加载速度与流畅度

系列文章目录 01-从零开始学CSS选择器&#xff1a;属性选择器与伪类选择器完全指南 02-避免样式冲突&#xff1a;掌握CSS选择器优先级与层叠规则的终极指南 03-如何精确掌控网页布局&#xff1f;深入解析 CSS 样式与盒模型 04-CSS 布局全面解析&#xff1a;从传统浮动到现代 F…

【DeepSeek】Deepseek辅组编程-通过卫星轨道计算终端距离、相对速度和多普勒频移

引言 笔者在前面的文章中&#xff0c;介绍了基于卫星轨道参数如何计算终端和卫星的距离&#xff0c;相对速度和多普勒频移。 【一文读懂】卫星轨道的轨道参数&#xff08;六根数&#xff09;和位置速度矢量转换及其在终端距离、相对速度和多普勒频移计算中的应用 Matlab程序 …