最近空闲时间在研究dubbo,里面用到了代理,正好这块以前不怎么了解,现在学习并记录下来。
参考:Java核心技术 卷I 基础知识(原书第9版) 6.5 代理
JDK代理是Java 1.3新增的特性,主要用于以下一些场景:
- 路由对远程服务器的方法调用。
- 在程序运行期间,将用户接口事件与动作关联起来。
- 为调试,跟踪方法调用。
JDK代理的实现原理是通过反射机制实例化被代理类及调用被代理的方法,在这个过程中可以做一些自定义的操作。
要被代理的类必须实现一个接口,没有实现接口的话,就无法使用JDK代理,不过CGLib代理不受此限制,并且由于底层是通过ASM字节码生成新的类,效率更高一些。
下面通过一个例子演示一下JDK代理。
首先写一个接口:
public interface Animal {
void sayHello();
}
接着是实现类:
public class Dog implements Animal {
private String name;
public Dog(String name) {
this.name = name;
}
public void sayHello() {
System.out.println("Hello, my name is " + name);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
接下来实现一种很简单代理类,该代理类在方法执行前打印了下被代理类的名字,在方法执行后打印了一段话:
public class MethodHandler implements InvocationHandler {
private Object target;
public MethodHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(target.getClass().getName());
Object result = method.invoke(target, args);
System.out.println("proxy end");
return result;
}
}
最后我们将Dog类进行代理,并测试:
public class Main {
private static Animal findADog(String name) {
Animal animal = new Dog(name);
return (Animal) Proxy.newProxyInstance(animal.getClass().getClassLoader(), animal.getClass().getInterfaces(), new MethodHandler(animal));
}
public static void main(String[] args) {
findADog("Teddy").sayHello();
}
}
运行结果如下:
com.company.Dog
Hello, my name is Teddy
proxy end