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

教育培训网站模板下载友情链接可以随便找链接加吗

教育培训网站模板下载,友情链接可以随便找链接加吗,网站建设公司做销售前景好不好,上海百度研发中心静态代理 vs 动态代理:从原理到实践的深度对比在面向对象编程中,​​代理模式(Proxy Pattern)​​是一种经典的行为型设计模式,其核心思想是通过一个“代理对象”控制对真实对象的访问,在不修改真实对象的前…

静态代理 vs 动态代理:从原理到实践的深度对比

在面向对象编程中,​​代理模式(Proxy Pattern)​​是一种经典的行为型设计模式,其核心思想是通过一个“代理对象”控制对真实对象的访问,在不修改真实对象的前提下,为其添加额外功能(如日志记录、事务管理、权限校验等)。根据代理类的生成时机,代理模式可分为​​静态代理​​和​​动态代理​​两大类。本文将从实现原理、代码示例、优缺点及适用场景等维度,系统对比两者的差异。


一、代理模式的核心价值

在展开对比前,我们先明确代理模式解决的问题:
假设我们需要为一个业务类(如UserService)添加日志记录功能,最直接的方式是修改UserService的代码,在每个方法前后插入日志。但这样会违反​​开闭原则​​(对扩展开放,对修改关闭),尤其是当需要为多个类添加相同功能时,重复代码会急剧增加,维护成本极高。

代理模式通过引入“代理对象”,将额外功能逻辑封装在代理中,真实对象仅负责核心业务,实现了​​功能解耦​​和​​代码复用​​。


二、静态代理:编译期确定的“固定助手”

静态代理是最基础的代理实现方式,其代理类在​​编译期​​手动编写(或通过工具生成),并在运行时直接使用。

1. 实现步骤

静态代理的核心是:​​代理类与被代理类实现相同接口​​,代理类持有被代理对象的引用,并在重写的接口方法中调用被代理对象的方法,同时添加扩展逻辑。

以用户服务(UserService)的日志代理为例:

步骤1:定义业务接口
public interface UserService {void addUser(String username);void deleteUser(Long userId);
}
步骤2:实现真实业务类(被代理对象)
public class UserServiceImpl implements UserService {@Overridepublic void addUser(String username) {System.out.println("添加用户:" + username);}@Overridepublic void deleteUser(Long userId) {System.out.println("删除用户,ID:" + userId);}
}
步骤3:编写静态代理类

代理类需实现UserService接口,持有UserServiceImpl实例,并在方法中嵌入日志逻辑:

public class UserServiceStaticProxy implements UserService {// 持有被代理对象的引用private final UserService target;public UserServiceStaticProxy(UserService target) {this.target = target;}@Overridepublic void addUser(String username) {// 前置增强:记录方法调用前的信息System.out.println("[日志] 开始执行addUser,参数:" + username);// 调用真实对象的方法target.addUser(username);// 后置增强:记录方法执行结果System.out.println("[日志] addUser执行完成");}@Overridepublic void deleteUser(Long userId) {System.out.println("[日志] 开始执行deleteUser,参数:" + userId);target.deleteUser(userId);System.out.println("[日志] deleteUser执行完成");}
}
步骤4:使用代理对象
public class Client {public static void main(String[] args) {// 创建真实对象UserService realService = new UserServiceImpl();// 创建代理对象,传入真实对象UserService proxyService = new UserServiceStaticProxy(realService);// 通过代理对象调用方法(自动触发日志)proxyService.addUser("张三");proxyService.deleteUser(1L);}
}
2. 静态代理的特点
  • ​优点​​:

    • 实现简单,逻辑清晰,适合新手理解代理模式;
    • 编译期生成代理类,运行时无额外性能损耗(反射调用比直接调用慢,但静态代理无反射)。
  • ​缺点​​:

    • ​强耦合​​:代理类与被代理类必须实现相同接口,若接口新增方法,代理类需同步修改;
    • ​可维护性差​​:每个被代理类都需要单独编写代理类(如OrderServiceOrderServiceStaticProxy),代码冗余;
    • ​扩展性低​​:无法动态切换被代理对象或动态添加新的增强逻辑。

三、动态代理:运行时生成的“万能助手”

动态代理的核心是​​代理类在运行时动态生成​​,无需手动编写。它通过反射机制拦截方法调用,并在运行时将增强逻辑织入目标方法。Java中主流的动态代理实现有两种:​​JDK动态代理​​和​​CGLIB动态代理​​。

1. JDK动态代理:基于接口的“轻量级代理”

JDK动态代理是Java标准库提供的内置代理机制(java.lang.reflect.Proxy),其原理是通过反射生成一个实现目标接口的代理类,并将方法调用转发到InvocationHandler处理器中。

核心组件
  • InvocationHandler:代理对象的方法调用处理器,所有通过代理对象发起的方法调用都会被转发到此处;
  • Proxy:用于生成代理类实例的工具类。
实现步骤(以UserService日志代理为例)
步骤1:定义业务接口(同静态代理)
public interface UserService {void addUser(String username);void deleteUser(Long userId);
}
步骤2:实现真实业务类(同静态代理)
public class UserServiceImpl implements UserService { ... }
步骤3:编写InvocationHandler

InvocationHandlerinvoke方法是核心,负责拦截所有代理对象的方法调用,并添加增强逻辑:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;public class LogInvocationHandler implements InvocationHandler {// 持有被代理对象的引用private final Object target;public LogInvocationHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 前置增强:记录方法调用信息String methodName = method.getName();System.out.println("[日志] 开始执行" + methodName + ",参数:" + String.join(",", toString(args)));// 调用真实对象的方法(核心逻辑)Object result = method.invoke(target, args);// 后置增强:记录方法执行完成System.out.println("[日志] " + methodName + "执行完成");return result;}// 辅助方法:将参数数组转为字符串private String toString(Object[] args) {if (args == null) return "无";StringBuilder sb = new StringBuilder();for (int i = 0; i < args.length; i++) {sb.append(args[i]);if (i != args.length - 1) sb.append(",");}return sb.toString();}
}
步骤4:生成代理对象并使用

通过Proxy.newProxyInstance方法动态生成代理类实例:

import java.lang.reflect.Proxy;public class Client {public static void main(String[] args) {// 真实对象UserService realService = new UserServiceImpl();// 创建InvocationHandler,绑定真实对象InvocationHandler handler = new LogInvocationHandler(realService);// 动态生成代理对象(类型为UserService)UserService proxyService = (UserService) Proxy.newProxyInstance(UserService.class.getClassLoader(), // 类加载器new Class<?>[]{UserService.class},  // 代理需要实现的接口handler                             // 方法调用处理器);// 通过代理对象调用方法(自动触发日志)proxyService.addUser("李四");proxyService.deleteUser(2L);}
}
输出结果
[日志] 开始执行addUser,参数:李四
添加用户:李四
[日志] addUser执行完成
[日志] 开始执行deleteUser,参数:2
删除用户,ID:2
[日志] deleteUser执行完成
2. CGLIB动态代理:基于继承的“全能代理”

JDK动态代理的局限性在于​​只能代理接口​​,若目标类未实现接口(如直接定义的class),则无法使用。此时可使用CGLIB(Code Generation Library),它通过​​继承目标类​​生成子类作为代理,从而实现对无接口类的代理。

核心依赖

需引入CGLIB库(Maven坐标:cglib:cglib:3.3.0)。

实现步骤(以无接口的OrderService为例)
步骤1:定义无接口的真实类
public class OrderService {public void createOrder(Long userId, String product) {System.out.println("创建订单:用户" + userId + "购买" + product);}
}
步骤2:编写MethodInterceptor(方法拦截器)

CGLIB通过MethodInterceptor拦截所有方法调用:

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;public class LogMethodInterceptor implements MethodInterceptor {@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {// 前置增强System.out.println("[CGLIB日志] 开始执行" + method.getName() + ",参数:" + String.join(",", toString(args)));// 调用真实对象的方法(通过MethodProxy,避免递归调用)Object result = proxy.invokeSuper(obj, args);// 后置增强System.out.println("[CGLIB日志] " + method.getName() + "执行完成");return result;}private String toString(Object[] args) {if (args == null) return "无";StringBuilder sb = new StringBuilder();for (int i = 0; i < args.length; i++) {sb.append(args[i]);if (i != args.length - 1) sb.append(",");}return sb.toString();}
}
步骤3:生成代理对象并使用

通过Enhancer类生成代理类:

import net.sf.cglib.proxy.Enhancer;public class Client {public static void main(String[] args) {// 真实对象OrderService realService = new OrderService();// 创建Enhancer,设置父类(目标类)Enhancer enhancer = new Enhancer();enhancer.setSuperclass(OrderService.class);// 设置方法拦截器enhancer.setCallback(new LogMethodInterceptor());// 生成代理对象(类型为OrderService的子类)OrderService proxyService = (OrderService) enhancer.create();// 调用代理方法(触发日志)proxyService.createOrder(100L, "手机");}
}
输出结果
[CGLIB日志] 开始执行createOrder,参数:100,手机
创建订单:用户100购买手机
[CGLIB日志] createOrder执行完成
3. 动态代理的对比与选择
特性JDK动态代理CGLIB动态代理
​代理方式​基于接口,生成接口的实现类基于继承,生成目标类的子类
​目标类要求​必须实现至少一个接口可以是任意类(包括无接口的类)
​性能​反射调用,略慢于CGLIB(JDK8+后差距缩小)基于继承,方法调用更快(但生成子类耗时)
​适用场景​接口稳定的业务类(如Spring的Service)无接口的类(如工具类、第三方库类)
​扩展限制​无法代理接口中未声明的方法可以代理目标类的所有方法(包括私有方法?需注意访问权限)

四、静态代理 vs 动态代理:核心差异总结

维度静态代理动态代理
​代理类生成时机​编译期(手动/工具生成)运行期(动态生成字节码)
​代码侵入性​需为每个被代理类编写代理类无需手动编写代理类,通用性强
​维护成本​高(接口变更需同步修改代理类)低(仅需调整InvocationHandler)
​扩展性​差(无法动态代理新类)强(一个代理可代理多个类/接口)
​适用场景​接口稳定、代理逻辑简单的场景接口多变、需要批量代理或AOP的场景

五、实际应用场景建议

  • ​静态代理​​:适合小型项目或代理逻辑非常固定的场景(如单个类的日志/校验),优点是代码直观,易于调试。
  • ​JDK动态代理​​:适合基于接口的Spring Service层(90%的Java业务系统采用接口设计),配合Spring AOP实现事务管理、权限控制等功能。
  • ​CGLIB动态代理​​:适合代理无接口的类(如MyBatis的Mapper接口本质是接口,仍用JDK代理;但某些工具类可能未实现接口),或需要对类的所有方法(包括私有方法)进行代理的场景(需注意CGLIB通过继承实现,私有方法无法被重写,实际仍调用父类方法)。

总结

静态代理是代理模式的“入门版”,通过手动编写代理类实现功能扩展,适合简单场景;动态代理则是“进阶版”,通过反射或字节码生成技术,在运行时动态创建代理类,解决了静态代理的代码冗余和维护问题,是框架(如Spring AOP)的核心实现技术。理解两者的差异,有助于在实际开发中根据需求选择合适的代理方式,提升代码的可维护性和扩展性。

http://www.dtcms.com/a/552545.html

相关文章:

  • 免费html网站模板南昌有限公司 网站
  • 台州网站建设网站推广公众号入口
  • 福州哪里会网站制作的wordpress print_r
  • ps个人网站建设培训网址
  • 互联网网站 有哪些网站建设与网页设计论文
  • 重庆市住房和城乡建设厅网站门户网站开发设计方案
  • 网站关键词怎么填写哪家网络推广好
  • 青岛网页设计学校厦门seo网络推广
  • html5移动网站模板如何设置网站默认首页
  • 如何做企业网站界面app怎么做需要多少钱
  • 集运网站建设服务器安装wordpress
  • 成都网站建设 小兵cms网站建设的要点
  • 网站建设的利益昆明免费网站建设
  • 代做电大网站ui作业国内wordpress教程
  • 怎样用wordpress做网站下载网站模板怎么使用
  • 有建网站的软件兰州做网站优化的公司
  • 网站备案是备什么网站建设-信科网络
  • 网站专题页是什么微信crm系统哪家好
  • 企业 备案 网站服务内容百度百科分类方法
  • 济南企业建站哪家做的好网站主色调
  • 电子商务网站案例分析股东分红如何合理节税
  • 网站设计大全用python网站开发
  • 站点建错了网页能打开吗系统下载网站源码
  • 品牌做网站比较好的wordpress
  • 常见网站模式二季域名做网站
  • 哪些购物网站用php做的能用的网站
  • 老河口网站定制可以做翻译任务的网站
  • 在一家传媒公司做网站编辑 如何中国未来楼市走势分析
  • 哈尔滨模板建站推荐桂林网红民宿
  • 网站h1标签用在哪里建设网站纳什么税