JAVA设计模式之动态代理
动态代理模式主要由四个元素共同构成:
1. 接口,接口中的方法是要真正去实现的
2. 被代理类,实现上述接口,这是真正去执行接口中方法的类
3. 代理类,实现InvocationHandler,帮助被代理类去实现方法
4. 测试用例:
举例详解:
1. 接口:
public interface Person {
void searchHouse();
}
2. 被代理类Master,实现上述接口:
public interface Person {
void searchHouse();
}
3. 代理类HomeLine,实现InvocationHandler接口
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class HomeLink implements InvocationHandler{
private Person target;
public Object getInstance(Person target){
this.target = target;
Class clazz = target.getClass();
Object obj = Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
return obj;
}
@Override
public Object invoke(Object obj, Method method, Object[] args) throws Throwable {
System.out.println("我是链家,我帮别人找房子..");
//第一个参数是target,也就是被代理类的对象;第二个参数是方法中的参数
method.invoke(target, args);
System.out.println("我是链家,已经找完了..");
return null;
}
}
4.测试用例:
public class TestSearchHouse {
public static void main(String[] args) {
Person person = (Person) new HomeLink().getInstance(new Master());
person.searchHouse();
}
}
5. 结果:
我是链家,我帮别人找房子.. 我是主人,我要找房子,一室一厅! 我是链家,已经找完了..
动态代理类详细分析:
动态代理的步骤:
1. 首先获得一个被代理对象的引用,
2. 获得该引用的接口
3. 生成一个类,这个类实现了我们给的代理对象所实现的接口
4. 上述类编译生成了.class字节码供JVM使用
5. 调用上述生成的class
对于生成的字节码,我们可以输出都磁盘中:
try {
byte[] data = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{Person.class});
FileOutputStream os = new FileOutputStream("D:/$Proxy0.class");
os.write(data);
os.flush();
os.close();
} catch (Exception e) {
e.printStackTrace();
}
对于生成的$Proxy0.class文件,可以用java反编译工具jd-gui-0.3.3.windows查看,
import com.yding.pattern.proxy.Person;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy
implements Person
{
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public $Proxy0(InvocationHandler paramInvocationHandler)
throws
{
super(paramInvocationHandler);
}
public final boolean equals(Object paramObject)
throws
{
try
{
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
public final String toString()
throws
{
try
{
return (String)this.h.invoke(this, m2, null);
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
public final void searchHouse()
throws
{
try
{
this.h.invoke(this, m3, null);
return;
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
public final int hashCode()
throws
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
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.yding.pattern.proxy.Person").getMethod("searchHouse", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
}
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
我们还不仅仅满足于上述的理解,需要更进一步的理解,手写java动态代理的细节过程:
有三个类我们需要自己手写,分别是Proxy, ClassLoader, InvocationHandler
1. MyProxy类,有一个方法,newInstance(ClassLoader loader, Class<?> interfaces,MyInvocationHandler h)
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
public class MyProxy {
private static String ln = "\r\n";
/**
* Proxy最重要的方法是newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h){ ..}
* @param loader
* @param interfaces
* @param h
* @return
*/
public static Object newProxyInstance(MyClassLoader loader,Class<?>[] interfaces,MyInvocationHandler h){
try {
//1. 生成源代码
String proxySrc = generateSrc(interfaces[0]);
//2. 将源代码输出到磁盘中
String filePath= MyProxy.class.getResource("").getPath();
File f = new File(filePath+"$Proxy0.java");
FileWriter fw = new FileWriter(f);
System.out.println(f.getAbsolutePath());
fw.write(proxySrc);
fw.flush();
fw.close();
//3. 编译源代码,并且生成.class文件
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null);
//4. 将class文件中的内容,动态加载到jvm中
Iterable iterable = manager.getJavaFileObjects(f);
CompilationTask task = compiler.getTask(null, manager, null, null, null, iterable);
task.call();
manager.close();
//5. 返回被代理后的对象
Class proxyClass = loader.findClass("$Proxy0");
Constructor c = proxyClass.getConstructor(MyInvocationHandler.class);
f.delete();
return c.newInstance(h);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
private static String generateSrc(Class<?> interfaces) {
StringBuffer src = new StringBuffer();
src.append("package com.yding.pattern.proxy.customer;" + ln);
src.append("import java.lang.reflect.Method;" + ln);
src.append("public class $Proxy0 implements " + interfaces.getName() + "{ "+ ln);
src.append("MyInvocationHandler h;" + ln);
src.append("public $Proxy0(MyInvocationHandler h){" + ln);
src.append("this.h = h;" + ln);
src.append("}" +ln);
for(Method m : interfaces.getMethods()){
src.append("public " + m.getReturnType().getName() + " " + m.getName() + "()" + "{" + ln);
src.append("try{" + ln);
//输出双引号 "\""
src.append("Method m = " + interfaces.getName()+".class.getMethod(\"" + m.getName() + "\",new Class[]{});"+ln);
src.append("this.h.invoke(this,m,null);" + ln);
src.append("}catch(Throwable e){e.printStackTrace();}" + ln);
src.append("}" + ln);
}
src.append("}");
return src.toString();
}
}
2. MyClassLoader(),有一个方法,findClass(String className)
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class MyClassLoader extends ClassLoader {
private File baseDir;
public MyClassLoader() {
// TODO Auto-generated constructor stub
String baseDir = MyClassLoader.class.getResource("").getPath();
this.baseDir = new java.io.File(baseDir);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String className = MyClassLoader.class.getPackage().getName() + "." + name;
if (baseDir != null) {
File classFile = new File(baseDir, name.replaceAll("\\.", "/") + ".class");
System.out.println("class File : " + classFile);
System.out.println(classFile.exists());
if (classFile.exists()) {
FileInputStream in = null;
ByteArrayOutputStream out = null;
try {
in = new FileInputStream(classFile);
out = new ByteArrayOutputStream();
byte[] buff = new byte[1024];
int len;
while ((len = in.read(buff)) != -1) {
out.write(buff, 0, len);
}
return defineClass(className, out.toByteArray(), 0, out.size());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
classFile.delete();
}
}
}
return null;
}
}
3. MyInvocationHandler
/**
* InvocationHandler
* @author Rick
*
*/
public interface MyInvocationHandler {
//接口的方法invoke
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
4. 用新定义的类再来执行代码:
public class TestSearchHouse {
public static void main(String[] args) {
Person person = (Person) new HomeLink().getInstance(new Master());
System.out.println(person.getClass());
person.searchHouse();
}
}


浙公网安备 33010602011771号