1、代理模式
被代理人没有时间去做某件事情,交由代理人去做。
例子
- 媒婆
- 房屋中介
- 经纪人
2、静态代理
- 代理的动作接口 -- 就是要代理做的事情:相亲
public interface Person {
public abstract void findLove();
}
- 被代理人要实现动作接口-- 相亲要找什么样的女生
public class XiaoYuan implements Person {
@Override
public void findLove() {
System.out.println("小元要找短头发、可爱的女生");
}
}
- 代理人实现动作接口帮助代理人 -- 在大把资源找到被代理人心仪的女生
public class MeiPo implements Person{
private Person xiaoYuan;
MeiPo(XiaoYuan xiaoYuan){
this.xiaoYuan = xiaoYuan;
}
@Override
public void findLove() {
System.out.println("媒婆有大把资源,说出你想要的");
xiaoYuan.findLove();
System.out.println("媒婆把联系方式给你,你可以谈恋爱了");
}
}
public class TestProxy {
public static void main(String[] args) {
Person meipo = new MeiPo(new XiaoYuan());
meipo.findLove(); // 媒婆资源比较多,让媒婆帮忙找下合适的小姐姐
// new XiaoYuan().findLove(); // 本来是要自己去找小姐姐谈恋爱的
}
}
Output
媒婆有大把资源,说出你想要的
小元要找短头发、可爱的女生
媒婆把联系方式给你,你可以谈恋爱了
3、动态代理 (下面例子讲的是jdk的动态代理)
public class DynamicMeiPo implements InvocationHandler {
private Person person;
// 返回动态生成一个实现代理动作接口的$Proxy0.class类
public Object newInstance(Person xiaoYuan){
this.person = xiaoYuan;
Class clazz = xiaoYuan.getClass();
// 获取被代理人信息和被代理人实现的接口
return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("媒婆有大把资源,说出你想要的");
method.invoke(person,args);
System.out.println("媒婆把联系方式给你,你可以谈恋爱了");
return null;
}
- 通过Proxy.newProxyInstance()会动态生成一个$Proxy0.class,通过下面代码会类的字节码将输出到文件。
public class TestDynamicProxy {
public static void main(String[] args) {
// $Proxy0.class类对象
Person dynamicMeiPo = (Person) (new DynamicMeiPo().newInstance(new XiaoYuan()));
dynamicMeiPo.findLove();
// 获取$Proxy0.class类
byte[] gengarateProxyClass = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{dynamicMeiPo.getClass()});
try {
FileOutputStream fos = new FileOutputStream("D:/$Proxy0.class" );
fos.write(gengarateProxyClass);
fos.close();
} catch (java.io.IOException e) {
e.printStackTrace();
}
}
}
- 其中实现了代理要做的动作接口(Person : findLove()),$Proxy0的父类会有一个InvocationHandler h,用来接收实现InvocationHandler的DynamicMeiPo
public final class $Proxy0 extends Proxy implements Proxy0
protected InvocationHandler h;
- $Proxy0 这是实现Person接口的findLove()方法,当对象调用findLove(),会通过invoke(DynamicMeiPo实现的方法)
public final void findLove() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
(1)、jdk动态代理原理
- 1、生成代理对象类文件$Proxy0.java代码内容
/**
* 动态生成代理对象的代码内容
*
* @param interfaces
* @return
*/
private static String generateSrc(Class interfaces) {
StringBuffer src = new StringBuffer();
src.append("package com.xiaoyuan.aop.myproxy;" + LN);
src.append("import java.lang.reflect.Method;" + LN);
src.append("import java.lang.reflect.Proxy;" + LN);
// 实现代理动作接口
src.append("public final class $Proxy0 implements " + interfaces.getName() + " {" + LN);
src.append("YInvocationHandler h;" + LN);
src.append("public $Proxy0(YInvocationHandler h){" + LN);
src.append("this.h = h;" + LN);
src.append("}" + LN);
// 代理动作接口的方法
for (Method method : interfaces.getMethods()) {
src.append("public final " + method.getReturnType() + " findLove() {" + LN);
src.append("try {" + LN);
src.append("Method m3 = Class.forName(\"" + interfaces.getName() + "\").getMethod(\"" + method.getName() + "\");" + LN);
src.append("h.invoke(this, m3, (Object[])null);" + LN);
src.append("} catch (Throwable var3) {" + LN);
src.append("System.out.println(\"出现错误\");" + LN);
src.append("}" + LN);
src.append("}" + LN);
}
src.append("}");
return src.toString();
}
- 2、生成java文件
// 2、生成java文件
String filePath = YProxy.class.getResource("").getPath();
File f = new File(filePath + "$Proxy0.java");
FileWriter fos = new FileWriter(f);
fos.write(src);
fos.close();
- 3、编译成生成$Proxy0.class
// 3、编译成生成$Proxy0.class
JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager manager = javaCompiler.getStandardFileManager(null, null, null);
Iterable iterable = manager.getJavaFileObjects(f);
JavaCompiler.CompilationTask task = javaCompiler.getTask(null,manager,null,null,null,iterable);
task.call();
manager.close();
- 3、$Proxy0.class加载到JVM中并返回类实例
protected Class<?> findClass(String name) {
String className = YClassLoader.class.getPackage().getName() + "." + name;
if (baseDir != null){
// 拿到$Proxy0.class的文件位置
File classFile = new File(baseDir, name.replaceAll("\\." , "/") + ".class");
if (classFile.exists()){
FileInputStream fis = null;
try {
// 读取该文件到输出流out上
fis = new FileInputStream(classFile);
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buff = new byte[1024];
int len;
while ((len = fis.read(buff) )!= -1){
out.write(buff, 0 ,len);
}
// 最后加载到jvm上
return defineClass(className, out.toByteArray(), 0, out.size());
} catch (java.io.IOException e) {
e.printStackTrace();
}
}
}
return null;
}
- 4、类实例通过反射生成实例对象返回
// 4、生成实例对象返回
Constructor c = proxyClass.getConstructor(YInvocationHandler.class);
return c.newInstance(h);