代理模式必须满足的条件
1,两个角色,代理对象和被代理对象
2,被代理对象的事情必须要做,但是他自己又不想做
3,代理对象必须知道被代理代理对象的信息(持有被代理对象的引用)
总结:动态代理的本质就是字节码重组
1,定义一个接口
public interface Person2 {
public void findLove();
}
实现类
public class Zhangsan implements Person2{
private String name = "张三";
private String sex = "男";
public void findLove() {
System.out.println("我的名字是:"+this.name+",我的性别是:"+this.sex);
System.out.println("1,我要寻找的对象是白富美");
System.out.println("2,我的对象要有房有车");
}
}
2,实现自己的类加载器
public class ZLClassLoader extends ClassLoader{
/**
* 重写类的加载方式,将字节码加载到JVM中来
*/
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
//在URI中,包名及类名每一层中间都是用”/”来分隔的。
//在加载资源时,也是需要使用完整的类名,但是每层中间的”/”需要替换成”.”才行。
String basePath = "D:/ws_sts/netty-test/target/classes/com/zl/test/custom/"+name+".class";
File classFile = new File(basePath);
if(classFile.exists()) {
FileInputStream fis = null;
ByteArrayOutputStream bos = null;
try {
fis = new FileInputStream(classFile);
bos = new ByteArrayOutputStream();
byte[] buff = new byte[1024];
int len =0;
while((len = fis.read(buff))!=-1) {
bos.write(buff, 0, len);
}
String className = ZLClassLoader.class.getPackage().getName()+"."+name;
System.out.println("className===>"+className);
//JVM读取字节码
Class<?> clz = defineClass(className, bos.toByteArray(), 0, bos.size());
System.out.println("加载文件到JVM完毕。。。。");
//删除字节码文件,无感知
classFile.delete();
return clz;
} catch (Exception e) {
e.printStackTrace();
}finally {
if(fis!=null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(bos!=null) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
return null;
}
}
3,定义自己的ZLInvocationHandler 接口
public interface ZLInvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
4,
public class ZLProxy {
private static String ln = "\r\n";
/**
* 生成代理类的实例
*
* @param zlloader
* @param interfaces
* @param zlhandler
* @return
* @throws IllegalArgumentException
*/
public static Object newProxyInstance(ZLClassLoader zlloader, Class<?>[] interfaces, ZLInvocationHandler zlhandler)
throws IllegalArgumentException {
try {
// 1动态生成java源码
String src = generateSrc(interfaces[0]);
//输出去看下是否语法编译通过
String path = "D:/ws_sts/netty-test/target/classes/com/zl/test/custom/";
File srcfile = new File(path +"$Proxy0.java");
System.out.println(srcfile.getAbsolutePath());
FileWriter fw = new FileWriter(srcfile);
fw.write(src);
fw.flush();
fw.close();
// 2将生成的源文件编译为class字节码
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager standardFileManager = compiler.getStandardFileManager(null, null, null);
Iterable<? extends JavaFileObject> iter = standardFileManager.getJavaFileObjects(srcfile);
CompilationTask task = compiler.getTask(null, standardFileManager, null, null, null, iter);
task.call();//生成class 文件
standardFileManager.close();
//删除源文件,实现无感知的动态生成文件
srcfile.delete();
// 3将字节码加载到JVM
Class<?> clz = zlloader.findClass("$Proxy0");
// 4反射生成代理对象
Constructor<?> c = clz.getConstructor(ZLInvocationHandler.class);
return c.newInstance(zlhandler);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 动态生成源码
*
* @return
*/
public static String generateSrc(Class<?> interfaces) {
StringBuffer src = new StringBuffer();
src.append("package com.zl.test.custom;").append(ln);
src.append("import java.lang.reflect.*;").append(ln).append(ln);
src.append("public class $Proxy0 implements "+interfaces.getName()+"{"+ln);
src.append("\t").append("private ZLInvocationHandler h;"+ln).append(ln);
src.append("\t").append("public $Proxy0(ZLInvocationHandler h){"+ln);
src.append("\t").append("\t").append("this.h=h;"+ln);
src.append("\t").append("}"+ln).append(ln);
//获取目标类的方法
for(Method m :interfaces.getMethods()) {
src.append("\t").append("public "+ m.getReturnType().getSimpleName() + " "+m.getName() +"(){").append(ln);
src.append("\t").append("\t").append("try{").append(ln);
src.append("\t").append("\t\t").append("Method mm = "+interfaces.getName()+".class.getMethod(\""+m.getName()+"\", new Class[]{});").append(ln);
src.append("\t").append("\t\t").append("this.h.invoke(this, mm ,null);").append(ln);
src.append("\t").append("\t").append("}catch(Throwable e){e.printStackTrace();}").append(ln);
src.append("\t").append("\t").append("return;").append(ln);
src.append("\t").append("}").append(ln);
}
src.append("}"+ln);
return src.toString();
}
}
5,生成代理对象
public class CusMeiPo implements ZLInvocationHandler{
private Person2 target;
/**
* 生成一个代理对象
* @return
*/
public Object getInstance(Person2 target) {
this.target = target;
Class<?> clz = target.getClass();
System.out.println("被代理的对象是==》"+clz);
//这里第三个参数this,也就是当前类,传递给代理类(动态生成的类),
//就形成了一个类似回调的方式,当前类的Invoke方法才的得以执行
return ZLProxy.newProxyInstance(new ZLClassLoader(), clz.getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("媒婆开始收费。。。。");
method.invoke(this.target, args);
System.out.println("媒婆收费牵线任务完毕。。。。。");
return null;
}
}
测试:
public class Test {
public static void main(String[] args) {
Person2 target = new Zhangsan();
Person2 proxy= (Person2) new CusMeiPo().getInstance(target);
proxy.findLove();
}
}
测试结果: