博客
关于我
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/

    你可能感兴趣的文章
    ReentrantReadWriteLock读写锁解析
    查看>>
    php laravel请求处理管道(装饰者模式)
    查看>>
    PHP mongoDB 操作
    查看>>
    ReentrantLock读写锁
    查看>>
    php mysql procedure获取多个结果集
    查看>>
    php mysql query 行数,PHP和MySQL:返回的行数
    查看>>
    PHP mysql_real_escape_string() 函数防SQL注入
    查看>>
    php mysql优化方法_MySQL优化常用方法
    查看>>
    PHP OAuth 2.0 Server
    查看>>
    php odbc驱动,php常用ODBC函数集(详细)
    查看>>
    php openssl aes ecb,php openssl_encrypt AES-128-ECB iOS
    查看>>
    php paypal rest api,PayPal REST API指定网络配置文件PHP
    查看>>
    php pcntl 多进程学习
    查看>>
    PHP pcntl_fork不能在web服务器中使用的变通方法
    查看>>
    php private ,public protected三者的区别
    查看>>
    php PSR规范
    查看>>
    php rand() 重复,array_rand()函数从另外一个数组中随机取得的一定数量的数组的元素是否会重复?...
    查看>>
    php redis pub/sub(Publish/Subscribe,发布/订阅的信息系统)之基本使用
    查看>>
    php redis 集群扩展类文件
    查看>>
    php redis(2)
    查看>>