代理模式及 Java 实现动态代理

2016/4/23 posted in  Java comments

前提条件

public interface Animal {
    void say();

    void run(String addr);
}

public class Dog implements Animal {
    @Override
    public void say() {
        System.out.println("汪汪汪");
    }

    @Override
    public void run(String addr) {
        say();
        System.out.println("狗在" + addr + "跑");
    }
}

代理模式示例

public class DogProxy implements Animal {
    private Dog dog;

    public DogProxy(Dog dog) {
        this.dog = dog;
    }

    @Override
    public void say() {

    }

    @Override
    public void run(String addr) {
        System.out.println("跑之前");
        try {
            dog.run(addr);
        } finally {
            System.out.println("跑之后");
        }
    }
}

// 调用
new DogProxy(new Dog()).run("路上");

Java 动态代理示例

public class InvokeHandler implements InvocationHandler {
    private Object object;

    public InvokeHandler(Object object) {
        this.object = object;
    }

    /**
     * @param proxy 相当于代理类的 this
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("调用之前");
        try {
            return method.invoke(object, args);
        } finally {
            System.out.println("调用之后");
        }
    }
}

// 调用
InvokeHandler handle = new InvokeHandler(new Dog());
Animal animal = (Animal) Proxy.newProxyInstance(
                this.getClass().getClassLoader(), Dog.class.getInterfaces(), handle);
animal.run("路上");

Java 动态代理类特性

  1. 类名以 $Proxy 开头
  2. 代理类继承自 java.lang.reflect.Proxy
  3. 调用 Proxy.isProxyClass 方法返回 true
  4. 代理类严格按顺序实现所有的接口(当实现的几个接口中有重复的方法时,代理类总是从最前面的接口获取方法对象,并分派给调用处理器)
  5. 在代理类实例上调用其代理的接口中所声明的方法时,最终都会由调用处理器的 invoke 方法执行;此外 java.lang.Object 中的 public,非 final 方法也会分派给调用处理器 invoke 方法执行,如:hashCode,equals,toString

Java 动态代理的限制

  1. 只能代理接口,因此只能代理 public 方法
  2. 代理类的内部方法间的调用时,代理不生效