为了了解代理模式是什么,我在网上查了一些资料。
通俗来说就是被代理的对象无法执行或者说不想执行某个方法而使用一个该对象的代理对象来帮助执行该方法。并且,这个代理对象需要拿到被代理对象的信息。
举个例子来说,过年回家,因为火车票很紧张,所以自己没办法抢到票,只能通过黄牛来帮助自己抢票,而黄牛抢票必须要得到我的信息,才能帮助抢票。
接下来,按照这个例子,我们实现一下JDK的动态代理
首先要有Proxy类
public class ChampionProxy {
private static String ln = "\r\n";
protected ChampionInvocationHandler ch;
public ChampionProxy() {
}
public ChampionProxy(ChampionInvocationHandler ch) {
this.ch = ch;
}
public static Object newProxyInstance(ChampionClassLoader loader,
Class<?>[] interfaces,
ChampionInvocationHandler ch) {
try {
// 生成源代码
String src = generateSrc(interfaces[0]);
// 输出到磁盘,保存为java文件
String classPath = ChampionProxy.class.getResource("").getPath();
File file = new File(classPath + "$ChampionProxy1.java");
FileWriter fw = new FileWriter(file);
fw.write(src);
fw.flush();
fw.close();
// 编译 java 文件,生成 class 文件
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null);
Iterable<? extends JavaFileObject> iterable = manager.getJavaFileObjects(file);
JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, null, null, iterable);
task.call();
manager.close();
// 删除 java 文件,保证不可察觉
file.delete();
// 添加到 jvm 中
// 返回代理对象
Class<?> proxy1 = loader.findClass("$ChampionProxy1");
Constructor<?> constructor = proxy1.getConstructor(ChampionInvocationHandler.class);
Object o = constructor.newInstance(ch);
return o;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
// 生成源码的方法
private static String generateSrc(Class<?> interfaces) {
StringBuffer buffer = new StringBuffer();
buffer.append("package com.ccc.proxy;" + ln);
buffer.append("import java.lang.reflect.Method;" + ln);
buffer.append("public class $ChampionProxy1 implements " + interfaces.getName() + " {" + ln);
buffer.append(" protected ChampionInvocationHandler ch;" + ln);
buffer.append(" public $ChampionProxy1(ChampionInvocationHandler ch) {" + ln);
buffer.append(" this.ch = ch;" + ln);
buffer.append(" }" + ln);
for (Method m : interfaces.getMethods()) {
buffer.append(" public " + m.getReturnType().getName() + " " + m.getName() + "() {" + ln);
buffer.append(" try {" + ln);
buffer.append(" Method m = " + interfaces.getName() + ".class.getMethod(\"" + m.getName() + "\", new Class[]{});" + ln);
buffer.append(" this.ch.invoke(this, m, null);" + ln); // 调用 ch 的 invoke 方法
buffer.append(" } catch(Throwable e) {e.printStackTrace();}" + ln);
buffer.append(" }" + ln);
}
buffer.append("}" + ln);
return buffer.toString();
}
}
该类中需要用到 ChampionInvocationHandler 和 ChampionClassLoader
public interface ChampionInvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
public class ChampionClassLoader extends ClassLoader {
private File baseDir;
public ChampionClassLoader() {
this.baseDir = new File(this.getClass().getResource("").getPath());
// System.out.println(this.getClass().getResource("").getPath());
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String className = this.getClass().getPackage().getName() + "." + name;
if (baseDir != null) {
File classFile = new File(baseDir + "\\" + name + ".class");
if (classFile.exists()) {
FileInputStream fis = null;
ByteArrayOutputStream bos = null;
try {
fis = new FileInputStream(classFile);
bos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = fis.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
return defineClass(className, bos.toByteArray(), 0, bos.size());
} catch (Exception e) {
e.printStackTrace();
}
}
}
return null;
}
}
到此,我们自己的 Proxy,Handler,ClassLoader就都完成,接下来创建一个 YellowBull 实现Handler 接口
public class YellowBull implements ChampionInvocationHandler {
private Person target;
public Object getInstance(Person target) {
this.target = target;
Class<? extends Person> clazz = target.getClass();
System.out.println("被代理的对象:" + clazz.getName());
return ChampionProxy.newProxyInstance(new ChampionClassLoader(), clazz.getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("想要买票,就得先给个人信息...");
method.invoke(target, args);
System.out.println("买到票了,把手续费付一下...");
return null;
}
}
然后创建 接口 以及 实现类
public interface Person {
void buyTicket();
}
public class SSS implements Person{
public void buyTicket() {
System.out.println("买深圳到北京的高铁票");
}
}
最后添加测试类
public class JDKTestDemo {
public static void main(String[] args) throws NoSuchMethodException {
Person sss = (Person) new YellowBull().getInstance(new SSS());
System.out.println(sss.getClass());
sss.buyTicket();
}
}
程序运行结果:
被代理的对象:com.ccc.proxy.SSS
class com.ccc.proxy.$ChampionProxy1
想要买票,就得先给个人信息…
买深圳到北京的高铁票
买到票了,把手续费付一下…
看到了别人对代理模式的研究,自己对照着实现并且理解,也希望这个好理解的例子帮助更多人理解。