博客
关于我
Java--代理
阅读量:285 次
发布时间:2019-03-01

本文共 3613 字,大约阅读时间需要 12 分钟。

Java动态代理详解

代理的概念

代理是一种常见的设计模式,旨在在不修改源代码的情况下对目标类的方法进行增强或扩展。在Java中,代理可以分为静态代理和动态代理两种形式。本文将重点介绍动态代理的实现方式及其应用场景。


动态代理的实现原理

动态代理通过Proxy.newProxyInstance方法来创建接口代理对象。该方法的三个主要参数如下:

  • ClassLoader loader:指定用于加载代理类的类加载器。
  • Class<?>[] interfaces:指定被代理接口的类数组。
  • InvocationHandler h:指定一个动态代理的调用处理器(Invocation Handler),用于动态地处理被代理方法的调用。
  • 通过InvocationHandler,我们可以在不修改目标类源代码的情况下,动态地增强目标类的方法行为。


    动态代理的实现步骤

    1. 创建被代理接口

    假设我们有一个接口OneDao,其中定义了一个方法add(int a, int b)用于计算两个整数的和。以下是接口的定义:

    public interface OneDao {    public int add(int a, int b);}

    2. 创建被代理实现类

    接下来,我们创建一个实现OneDao接口的类OneDaoImpl。该类的实现如下:

    public class OneDaoImpl implements OneDao {    @Override    public int add(int a, int b) {        return a + b;    }}

    3. 定义Invocation Handler

    为了实现动态代理,我们需要定义一个InvocationHandler的实现类MyHandler。该类将负责动态地处理被代理方法的调用。以下是MyHandler的实现:

    class MyHandler implements InvocationHandler {    private Object object; // 被代理对象    public MyHandler(Object object) {        this.object = object;    }    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        System.out.println("方法前:" + method.getName());        Object result = method.invoke(object, args);        System.out.println("方法后:" + method.getName());        return result;    }}

    4. 创建代理对象

    通过Proxy.newProxyInstance方法,我们可以根据指定的接口和调用处理器创建一个动态代理对象。以下是创建代理对象的代码示例:

    @Testpublic void method() {    OneDaoImpl oneDao = new OneDaoImpl();    OneDao dao = (OneDao) Proxy.newProxyInstance(OneDaoImpl.class.getClassLoader(),         new Class[]{OneDaoImpl.class},         new MyHandler(oneDao)    );    int add = dao.add(1, 2);    System.out.println(add);}

    5. 调用代理对象

    通过上述代码,我们可以看到动态代理对象dao实际上是通过MyHandler来调用OneDaoImpl类的方法。每当调用dao.add(1, 2)时,MyHandler都会先输出日志,执行目标方法oneDao.add(1, 2),然后再输出日志。


    动态代理的优势

    动态代理的主要优势在于它能够在不修改目标类源代码的情况下,动态地增强目标类的方法行为。这种特性在以下场景尤为有用:

  • 日志记录:可以在方法执行前后记录日志。
  • 性能监控:可以在方法执行过程中监控性能参数。
  • 安全性:可以在方法执行前后进行权限检查或其他安全验证。
  • 功能扩展:可以在不修改目标类的情况下,扩展方法功能。

  • 实际应用示例

    假设我们有一个Human接口,定义了两个方法getAge()getName()。我们可以通过动态代理来增强这些方法的行为。

    被代理类

    public class GDPeople implements Human {    private int age;    private String name;    public GDPeople(int age, String name) {        this.age = age;        this.name = name;    }    @Override    public int getAge() {        return age;    }    @Override    public String getName() {        return name;    }}

    代理工厂

    我们可以创建一个ProxyFactory工厂类,用于生成动态代理对象。以下是ProxyFactory的实现:

    public class ProxyFactory {    public static Object getProxyInstance(Object obj) {        MyInvocationHandler handler = new MyInvocationHandler();        handler.bind(obj);        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),             obj.getClass().getInterfaces(),             handler        );    }}class MyInvocationHandler implements InvocationHandler {    private Object object;    public void bind(Object object) {        this.object = object;    }    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        System.out.println("代理之前:" + method.getName());        Object result = method.invoke(object, args);        System.out.println("代理之后:" + method.getName());        return result;    }}

    使用示例

    public class ProxyTest {    public static void main(String[] args) {        GDPeople gdPeople = new GDPeople(15, "Tom");        Human proxyInstance = (Human) ProxyFactory.getProxyInstance(gdPeople);        int age = proxyInstance.getAge();        String name = proxyInstance.getName();        System.out.println("name:" + name + "-----age:" + age);    }}

    输出结果

    运行上述代码,输出结果如下:

    name:Tom-----age:15

    总结

    通过本文的详细分析和代码示例,我们可以看到动态代理是一种强大的设计模式,能够在不修改目标类源代码的情况下,动态地增强目标类的方法行为。在实际应用中,动态代理广泛应用于日志记录、性能监控、安全性验证等场景。

    转载地址:http://chca.baihongyu.com/

    你可能感兴趣的文章
    NutzWk 5.1.5 发布,Java 微服务分布式开发框架
    查看>>
    NUUO网络视频录像机 css_parser.php 任意文件读取漏洞复现
    查看>>
    NUUO网络视频录像机 upload.php 任意文件上传漏洞复现
    查看>>
    Nuxt Time 使用指南
    查看>>
    NuxtJS 接口转发详解:Nitro 的用法与注意事项
    查看>>
    NVDIMM原理与应用之四:基于pstore 和 ramoops保存Kernel panic日志
    查看>>
    NVelocity标签使用详解
    查看>>
    NVelocity标签设置缓存的解决方案
    查看>>
    Nvidia Cudatoolkit 与 Conda Cudatoolkit
    查看>>
    NVIDIA GPU 的状态信息输出,由 `nvidia-smi` 命令生成
    查看>>
    nvidia 各种卡
    查看>>
    Nvidia 系列显卡大解析 B100、A40、A100、A800、H100、H800、V100 该如何选择,各自的配置详细与架构详细介绍,分别运用于哪些项目场景
    查看>>
    NVIDIA-cuda-cudnn下载地址
    查看>>
    nvidia-htop 使用教程
    查看>>
    nvidia-smi 参数详解
    查看>>
    Nvidia驱动失效,采用官方的方法重装更快
    查看>>
    nvmw安装node-v4.0.0之后版本的临时解决办法
    查看>>
    nvm切换node版本
    查看>>
    nvm安装 出现 Error retrieving “http://xxxx/SHASUMS256.txt“: HTTP Status 404 解决方法
    查看>>
    nvm安装以后,node -v npm 等命令提示不是内部或外部命令 node多版本控制管理 node多版本随意切换
    查看>>