代理模式有两种对象:目标对象,代理对象。客户端不直接操作目标对象,由代理对象间接调用。下面举个例子:
静态代理:
public interface TargetInterface {
int count();
void say(String s);
}
public class RealTarget implements TargetInterface{
@Override
public int count() {
return 1;
}
@Override
public void say(String s) {
System.out.println(s);
}
}
public class StaticProxy implements TargetInterface{
private TargetInterface target;
public StaticProxy(RealTarget realTarget) {
this.target=realTarget;
}
@Override
public int count() {
System.out.println("我是代理count()");
return target.count();
}
@Override
public void say(String s) {
target.say("我是代理:"+s);
}
}
private static void testStaticProxy(){
RealTarget realTarget=new RealTarget();
StaticProxy staticProxy=new StaticProxy(realTarget);
staticProxy.count();
staticProxy.say("hero");
}
结果:
我是代理count()
我是代理:hero
缺点是代理类运行之前已经确定,无法动态改变。
JDK动态代理:
public class DynamicProxyFactory implements InvocationHandler{
private TargetInterface target;
public TargetInterface getProxy(TargetInterface target){
this.target=target;
return (TargetInterface)Proxy.newProxyInstance(getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
System.out.println("我是动态代理对象:"+proxy.getClass());
return method.invoke(target,args);
}
}
测试:
private static void testDynamicProxy(){
DynamicProxyFactory dynamicProxyFactory=new DynamicProxyFactory();
TargetInterface proxy = dynamicProxyFactory.getProxy(new RealTarget());
System.out.println(proxy.count());
proxy.say("dynamic");
}
结果:
我是动态代理对象:class com.sun.proxy.$Proxy0
1
我是动态代理对象:class com.sun.proxy.$Proxy0
dynamic
特点:代理类动态生成,易于扩展。
我们从打印看到JDK的动态代理生成的代理类com.sun.proxy.$Proxy0,那么这个类是什么样子的呢。我们跟下源码发现Proxy这个类生成的代理类是ProxyGenerator的public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) 方法生成的,我们就通过这个方法生成字节码写到本地文件中,然后通过反编译工具来看一下com.sun.proxy.$Proxy0的庐山真面目。
private static void testDynamicProxyClassFile() throws Exception {
byte[] bytes = ProxyGenerator.generateProxyClass("com.sun.proxy.$Proxy0", new Class[]{TargetInterface.class}, Modifier.FINAL | Modifier.PUBLIC);
FileOutputStream fileOutputStream=new FileOutputStream("$Proxy0.class");
fileOutputStream.write(bytes);
fileOutputStream.close();
}
通过反编译工具打开$Proxy0.class文件
package com.sun.proxy;
import com.pattern.proxy.TargetInterface;
import java.lang.reflect.*;
public final class $Proxy0 extends Proxy
implements TargetInterface
{
public $Proxy0(InvocationHandler invocationhandler)
{
super(invocationhandler);
}
public final boolean equals(Object obj)
{
try
{
return ((Boolean)super.h.invoke(this, m1, new Object[] {
obj
})).booleanValue();
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final String toString()
{
try
{
return (String)super.h.invoke(this, m2, null);
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final int count()
{
try
{
return ((Integer)super.h.invoke(this, m3, null)).intValue();
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final void say(String s)
{
try
{
super.h.invoke(this, m4, new Object[] {
s
});
return;
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final int hashCode()
{
try
{
return ((Integer)super.h.invoke(this, m0, null)).intValue();
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m4;
private static Method m0;
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {
Class.forName("java.lang.Object")
});
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m3 = Class.forName("com.pattern.proxy.TargetInterface").getMethod("count", new Class[0]);
m4 = Class.forName("com.pattern.proxy.TargetInterface").getMethod("say", new Class[] {
Class.forName("java.lang.String")
});
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
}
catch(NoSuchMethodException nosuchmethodexception)
{
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
}
catch(ClassNotFoundException classnotfoundexception)
{
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
}
}
我们可以看到生成的代理类的构造参数中就是需要我们实现的InvocationHandler的接口,代理类的方法调用都会委派给InvocationHandler对象。所以JDK的Proxy实际就是动态生成了一个实现了代理类接口的类,然后通过classloader加载到内存中,为以后使用。我们也可以模仿这种思路自定义一个Proxy。
public class CustomProxy {
public static final String CLASSNAME="Custom$Proxy0";
public static final String CLASSFULLNAME="com.pattern.proxy.custom.Custom$Proxy0";
public static Object newProxyInstance(CustomClassLoader loader,Class<?>[] interfaces,CustomInvocationHandler h) throws Exception {
InputStream resourceAsStream = CustomProxy.class.getResourceAsStream(CLASSNAME+".txt");
InputStreamReader inputStreamReader=new InputStreamReader(resourceAsStream);
BufferedReader bufferedReader=new BufferedReader(inputStreamReader);
String source=bufferedReader.lines().reduce(new StringBuilder(),(l,r)->l.append(r).append("\n"),(l,r)->l.append(r)).toString();
File f=new File("Custom$Proxy0.java");
new FileOutputStream(f).write(source.getBytes());
JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager javaFileManager = javaCompiler.getStandardFileManager(null, null, null);
Iterable<? extends JavaFileObject> javaFileObjects = javaFileManager.getJavaFileObjects(f);
JavaCompiler.CompilationTask task = javaCompiler.getTask(null, javaFileManager, null, null, null, javaFileObjects);
task.call();
javaFileManager.close();
Class proxyClass = loader.loadClass(CLASSNAME);
Constructor c = proxyClass.getConstructor(CustomInvocationHandler.class);
return c.newInstance(h);
}
}
自定义classloader
public class CustomClassLoader extends ClassLoader{
@Override
protected Class<?> findClass(String name) {
FileInputStream in = null;
ByteArrayOutputStream out = null;
try{
in = new FileInputStream(CustomProxy.CLASSNAME+".class");
out = new ByteArrayOutputStream();
byte [] buff = new byte[1024];
int len;
while ((len = in.read(buff)) != -1){
out.write(buff,0,len);
}
return defineClass(CustomProxy.CLASSFULLNAME,out.toByteArray(),0,out.size());
}catch (Exception e){
e.printStackTrace();
}finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
}
自定义CustomInvocationHandler
public interface CustomInvocationHandler {
Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
public class CustomProxyFactory implements CustomInvocationHandler {
private TargetInterface target;
public TargetInterface getProxy(TargetInterface target) throws Exception {
this.target=target;
return (TargetInterface) CustomProxy.newProxyInstance(new CustomClassLoader(),target.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
System.out.println("我是自定义动态代理对象:"+proxy.getClass());
return method.invoke(target,args);
}
}
代表动态生成代理类的java代码(生成过程可以通过反射获取获取接口信息,然后通过组拼字符串的方式生成java代码,这个过程略了,直接写个txt文件Custom$Proxy0.txt代表动态生成的源代码
package com.pattern.proxy.custom;
import com.pattern.proxy.TargetInterface;
import java.lang.reflect.Method;
import java.lang.reflect.UndeclaredThrowableException;
public final class Custom$Proxy0 implements TargetInterface
{
private CustomInvocationHandler h;
public Custom$Proxy0(CustomInvocationHandler invocationhandler)
{
this.h=invocationhandler;
}
public final boolean equals(Object obj)
{
try
{
return ((Boolean)h.invoke(this, m1, new Object[] {
obj
})).booleanValue();
}
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final String toString()
{
try
{
return (String)h.invoke(this, m2, null);
}
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final int count()
{
try
{
return ((Integer)h.invoke(this, m3, null)).intValue();
}
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final void say(String s)
{
try
{
h.invoke(this, m4, new Object[] {
s
});
return;
}
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final int hashCode()
{
try
{
return ((Integer)h.invoke(this, m0, null)).intValue();
}
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m4;
private static Method m0;
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {
Class.forName("java.lang.Object")
});
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m3 = Class.forName("com.pattern.proxy.TargetInterface").getMethod("count", new Class[0]);
m4 = Class.forName("com.pattern.proxy.TargetInterface").getMethod("say", new Class[] {
Class.forName("java.lang.String")
});
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
}
catch(NoSuchMethodException nosuchmethodexception)
{
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
}
catch(ClassNotFoundException classnotfoundexception)
{
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
}
}
测试:
private static void testCustomProxy() throws Exception {
CustomProxyFactory customProxyFactory=new CustomProxyFactory();
TargetInterface proxy = customProxyFactory.getProxy(new RealTarget());
System.out.println(proxy.count());
proxy.say("custom");
}
结果:
我是自定义动态代理对象:class com.pattern.proxy.custom.Custom$Proxy0
1
我是自定义动态代理对象:class com.pattern.proxy.custom.Custom$Proxy0
custom
将JDK动态代理生成的类保存为class文件
通过查看sun.misc.ProxyGenerator#generateProxyClass(java.lang.String, java.lang.Class<?>[], int)源码发现,还可以通过设置java系统属性sun.misc.ProxyGenerator.saveGeneratedFiles=true。
jdk8之后的设置系统属性jdk.proxy.ProxyGenerator.saveGeneratedFiles=true