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");
}
}
输出:
输出从输出的结果,我们可以看到:
- 程序在运行的时候,生成了Class对象
com.sun.proxy.$Proxy0
,因为这个Class对象是在程序运行的时候生成的,所以这种代理模式,叫做动态代理。 - 在调用代理对象的方法的时候,会执行调用处理器里面的invoke方法
- 因为我们在调用处理器的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
的情况下添加了日志功能。
输出:
1567393460628.png
网友评论