Java动态代理

Java中的动态代理

一、使用

简介

在Java中要创建一个动态代理对象,需要使用

Proxy.newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h)

  • loader,类加载器,用来加载Class文件

  • interfaces,代理对象实现的接口

  • h,调用处理器。对动态代理调用方法,都会被这个对象进行处理。InvocationHandler源码如下:

    public interface InvocationHandler {
        public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable;
    }
    

    也就是,对代理对象调用方法都会,调用InvocationHandler里面的invoke方法。

写一个例子

有一个接口

public interface Interface {

    void doSomething(String s);

    void doSomethingElse(String s);

}

有一个接口的实现类

public class RealObject implements Interface{
    @Override
    public void doSomething(String s) {
        System.out.println(s);
    }

    @Override
    public void doSomethingElse(String s) {
        System.out.println(s);
    }
}

有一个调用处理器,我们将被代理对象的引用传入调用处理器,在invoke方法中调用被代理对象的方法。此时的调用处理器就相当于一个包装类。

public class SimpleHandler implements InvocationHandler {

    private Object proxied;

    public SimpleHandler(Object proxied) {
        this.proxied = proxied;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("{");
        System.out.println("proxy class = " + proxy.getClass());
        System.out.println("method name = " + method.getName());
        System.out.println("args = ");
        for (Object arg : args) {
            System.out.print(arg + " ");
        }
        System.out.println("}");
        return method.invoke(proxied, args);
    }
}

测试程序:

public class Main {
    public static void main(String[] args) {
        //使用Proxy.newProxyInstance()生成代理对象
        Interface proxy = (Interface) Proxy.newProxyInstance(
                Interface.class.getClassLoader(),
                new Class[]{Interface.class},
            //向调用处理器传入被代理对象 RealObject
                new SimpleHandler(new RealObject()));
        proxy.doSomething("Hello");
        proxy.doSomethingElse("World");
    }
}

输出:

Java动态代理_第1张图片
输出

从输出的结果,我们可以看到:

  1. 程序在运行的时候,生成了Class对象 com.sun.proxy.$Proxy0,因为这个Class对象是在程序运行的时候生成的,所以这种代理模式,叫做动态代理。
  2. 在调用代理对象的方法的时候,会执行调用处理器里面的invoke方法
  3. 因为我们在调用处理器的invoke方法里面返回的是被代理对象 RealObject的方法调用,所以会执行被代理对象的方法调用。

二、为什么要使用动态代理

因为invoke方法在调用代理对象的方法时会执行的,所以我们可以在调用代理对象的方法之前,之后做一些处理。可以在不修改源码的情况下,为现有的方法添加功能。

知乎里有关于这个的问题的讨论

比如我们想在调用代理方法的前后,打印日志

定义Log类:

public class Log {
    public void before() {
        System.out.println("log before");
    }

    public void after() {
        System.out.println("log after");
    }
}

修改InvocationHandler类:

public class SimpleHandler implements InvocationHandler {

    private Object proxied;

    public SimpleHandler(Object proxied) {
        this.proxied = proxied;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Log log = new Log();
        log.before();
        Object result = method.invoke(proxied, args);
        log.after();
        //返回方法调用的返回值
        return result;
    }
}

这样我们在没有修改 RealObject 的情况下添加了日志功能。

输出:

Java动态代理_第2张图片
1567393460628.png

你可能感兴趣的:(Java动态代理)