静态代理、动态代理基础

本贴最后更新于 2306 天前,其中的信息可能已经事过境迁

静态代理

静态代理也可以看做是代理模式,屏蔽了对真实对象的感知,处理或者调用方法时无需真实对象,只要与代理对象交互即可。主要用于由于安全或者其他原因隐藏真实访问对象,或者是为了提升性能对真实对象进行延迟加载等操作。

代码实例如下:

  • 定义一个接口
/** * 账户接口 */ public interface Account { /** * 查询账户 */ void query(); /** * 更新账户 */ void update(); }
  • 实现接口方法
public class AccountImpl implements Account { static { System.out.println("初始化操作"); } @Override public void query() { System.out.println("查询账户余额"); } @Override public void update() { System.out.println("更新账户余额"); } }
  • 定义一个代理对象(请注意代码中 getAccount() 方法)
public class AccountProxy implements Account { private AccountImpl account; public AccountImpl getAccount() { if (account == null) { this.account = new AccountImpl(); } return account; } @Override public void query() { System.out.println("查询操作预处理"); // 调用真正的查询账户方法 getAccount().query(); System.out.println("查询操作后回调"); } @Override public void update() { System.out.println("更新操作预处理"); // 调用真正的更新账户方法 getAccount().update(); System.out.println("更新操作后回调"); } }
  • 调用方法
public class Main { public static void main(String[] args) { AccountProxy accountProxy = new AccountProxy(); accountProxy.query(); accountProxy.update(); } }

动态代理

与静态代理不同,动态代理实在运行时动态生成代理类。不需要像静态代理一样为每一个接口写一个代理方法
或者对象,更方便而且利于维护。

动态代理的实现技术有很多,JDK 自带动态处理,CGLIB 和 ASM 库等也都提供了相关的处理方法。

JDK

  • 定义一个接口
public interface TaskService { void complete(); }
  • 实现接口方法
public class TaskServiceImpl implements TaskService { static { System.out.println("初始化操作"); } @Override public void complete() { System.out.println("完成任务"); } }
  • 代理实现
public class TaskProxy implements InvocationHandler { private Object target; public Object bind(Object target) { this.target = target; //通过反射机制,创建一个代理类对象实例并返回。用户进行方法调用时使用 //创建代理对象时,需要传递该业务类的类加载器(用来获取业务实现类的元数据,在包装方法是调用真正的业务方法)、接口、handler实现类 return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result; System.out.println("预处理操作"); result = method.invoke(target, args); System.out.println("回调操作"); return result; } }
  • 运行
public class Main { public static void main(String[] args) { TaskServiceImpl taskServiceImpl = new TaskServiceImpl(); TaskProxy proxy = new TaskProxy(); TaskService taskService = (TaskService) proxy.bind(taskServiceImpl); taskService.complete(); } }

CGLIB

由于该种实现是基于 extend 的方式,所以对于 final 类型的方法无法进行代理执行

  • 方法定义
public class ProcessService { public void start() { System.out.println("流程启动处理"); } }
  • 代理
public class ProcessServiceAgent implements MethodInterceptor { private Object target; public Object getInstance(Object object) { this.target = object; Enhancer enhancer = new Enhancer(); //为加强器指定要代理的业务类(即:为下面生成的代理类指定父类) enhancer.setSuperclass(this.target.getClass()); //设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦 enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("预处理操作"); methodProxy.invokeSuper(o, objects); System.out.println("回调操作"); return null; } }
  • 运行
public class Main { public static void main(String[] args) { ProcessService processService = new ProcessService(); ProcessServiceAgent processServiceAgent = new ProcessServiceAgent(); ProcessService instance = (ProcessService) processServiceAgent.getInstance(processService); instance.start(); } }

其他

常用的应用场景

  • 远程代理
  • 虚拟代理
  • 安全代理
  • 指针引用
  • 延迟加载

文档参考

  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3195 引用 • 8215 回帖
  • 动态代理
    6 引用 • 10 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • amu123

    无意间进来的 感觉你们都好牛啊