在编程时,代理是非常重要的一个概念。在设计模式中,也有所谓的代理模式,我们来看它的定义:通过创建一个对象来控制对某些特定对象的访问。也就是说,代理的价值在于可以拦截对象的访问,在拦截后,你可以在使用原有功能时添加额外的一些东西,比如添加日志等,而不需要改变原对象的源码。当然直接在源代码中添加是可以的,但最后造成的结果就是庞大的代码量以及复杂的逻辑,相信谁都不愿意看到。在JDK中内置了实现动态代理的类,那就是Proxy类。
一、Proxy类概述
Proxy类位于java.lang.reflect包中,所以其实现跟反射机制有关,它实现了Serializable接口,所以此类的对象可以序列化。Proxy类提供创建动态代理类及其实例,创建的方式一般有两种,其中一种:
InvocationHandler handler = new MyInvocationHandler(...);
Class<?> proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), Foo.class);
Foo f = (Foo) proxyClass.getConstructor(InvocationHandler.class).
newInstance(handler);
或者更简单的方式:
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
new Class<?>[] { Foo.class },
handler);
一般使用第二种方式即可。接下来来阐述这些方法的细节,两种方法相似,所以只介绍第二种方式:
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
这个方法产生代理对象的实例,参数loader是类加载器,interfaces提供被代理的对象,通过接口指定。h提供InvocationHandler的实例,表明代理对象所要做的事情。InvocationHandler是一个接口,实现它需要重写invoke方法:
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 调用被代理对象的方法
method.invoke(object, null);
return null;
}
};
梳理一下代理对象的使用方式:我们使用newProxyInstance(...)方法产生一个代理对象,此对象可以转型成被代理的实例(原实例),此时调用原实例方法,会将调用传递给InvocationHandler的实例的invoke()方法,方法内部传递原实例,再调用原实例方法及添加处理逻辑,这样就实现了代理对象的功能。
另外需要注意的是,上文提过需要提供接口,实际上被代理实例必须实现一个或更多的接口,这是一个必要条件。
二、代理对象的特点
通过Proxy类产生的代理对象,具有以下特点:
- 如果所有被实现接口的访问权限均是public,那么代理对象的访问权限是public, final, 并且非abstract的。
- 如果有一个接口的访问权限是非public的,那么代理对象的访问权限是非public, final, 并且非abstract的。
- 代理对象的类命名一般以"$Proxy"开头
- 代理对象继承自Proxy类
- 代理对象按照指定顺序实现接口
- 给定代理对象和有关接口,调用instanceof表达式会返回true:
proxy instanceof Foo
7.代理对象可转型成有关接口的实例三、例子
通过一个简单的例子呈现Proxy类的使用:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/*
* 生成代理对象
* 这个例子实现了两个接口
*/
public class ProxyTest implements Hello, Hey{
public static void main(String[] args) {
ProxyTest test = new ProxyTest();
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
method.invoke(test, null);
return null;
}
};
Class<?> proxyClass = Proxy.getProxyClass(Hey.class.getClassLoader(), new Class[]{Hello.class, Hey.class});
// 继承自Proxy类
System.out.println(proxyClass.getSuperclass());
// 类名字以"$Proxy"开头
System.out.println(proxyClass.getName());
try {
// 第一种方式
Object proxy = proxyClass.getConstructor(InvocationHandler.class).newInstance(handler);
// 第二种方式
// Proxy.newProxyInstance(Hey.class.getClassLoader(), new Class[]{Hello.class, Hey.class}, handler);
// 调用instanceof表达式会返回true
System.out.println(proxy instanceof Hello);
System.out.println(proxy instanceof Hey);
// 可以转型成任意接口的实例
Hello hello = (Hello )proxy;
Hey hey = (Hey)proxy;
hello.hello();
hey.hey();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void hey() {
System.out.println("Hey!!");
}
@Override
public void hello() {
System.out.println("Hello!!");
}
}
interface Hello {
public void hello();
}
interface Hey {
public void hey();
}
输出结果:
class java.lang.reflect.Proxy
$Proxy0
true
true
Hello!!
Hey!!