静态代理、动态代理基础

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

静态代理

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

代码实例如下:

  • 定义一个接口
/**
 * 账户接口
 */
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 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3187 引用 • 8213 回帖
  • 动态代理
    6 引用 • 10 回帖

相关帖子

欢迎来到这里!

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

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

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