举例:小明因为工作忙,没时间恋爱,父母比较着急,给小明介绍相亲对象,安排相亲…
代码示例:
public interface People {
public void marry();
}
public class XiaoMing implements People
{
@Override
public void marry() {
System.out.println("我是小明,我要结婚啦");
}
}
public class Parent implements InvocationHandler {
private People people;
public Parent(People people){
this.people = people;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
method.invoke(people , null);
after();
return null;
}
private void before(){
System.out.println("小明父母介绍相亲对象");
}
private void after(){
System.out.println("小明父母帮小明带孩子");
}
}
public class Test {
public static void main(String[] args) {
People proxyObj = (People)Proxy.newProxyInstance
(Test.class.getClassLoader(), new Class<?>[]{People.class}, new Parent(new XiaoMing()));
proxyObj.marry();
}
}
这样一个简单的动态代理示例代码就创建好了,看一下main函数结果如图所示:
那问题来了,Parent类中的invoke方法是在哪里调用的呢?
通过上图可以看到,代理对象是一个名称为 $ Proxy0的对象,在$Proxy0中有一个名称为h的属性,这个h属性就是Parent对象。由于这个代理对象是在内存中的,通过以下的代码,可以通过流的方式将其导出来。
public static void createProxyClassFile(){
byte[] $Proxy0s = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{People.class});
try {
FileOutputStream fileOutputStream = new FileOutputStream("$Proxy0.class");
fileOutputStream.write($Proxy0s);
fileOutputStream.close();
}catch (FileNotFoundException e){
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
这样在工程的根路径就生成了一个class文件,在ide中打开,就是长这个熊样:
import com.study.dongsq.proxy.People;
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 People {
private static Method m1;
private static Method m2;
private static Method m0;
private static Method m3;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void marry() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
m3 = Class.forName("com.study.dongsq.proxy.People").getMethod("marry");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
可以看到,代理对象调marry方法,会调到super.h的invoke方法,这个h属性就是Parent
我们也可以利用类似javassist的技术,自己写一个MyProxy,代替jdk的Proxy,给Xiaoming创建一个代理对象。
public class MyProxy {
private static String rt = "\r\n";
private static String path = "D:\\study\\spring\\spring-source\\src\\main\\java\\com\\study\\dongsq\\myProxy\\";
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, MyInvocationHandler h){
//通过拼凑字符串的方式生成一个$proxy0
String javaStr = getJavaStr(interfaces);
//创建一个文件$Proxy0.java,并把字符串用流的方式写到这个文件里面
createFile(javaStr);
//用编译器编译成class文件
compiler();
//把class文件加载到jvm内存,并在内存中执行,返回代理实例
MyClassLoader myClassLoader = new MyClassLoader(path);
try {
Class<?> $Proxy0 = myClassLoader.findClass("$Proxy0");
Constructor<?> constructor = $Proxy0.getConstructor(MyInvocationHandler.class);
Object o = constructor.newInstance(h);
return o;
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
private static String getJavaStr(Class<?>[] interfaces){
Method[] methods = interfaces[0].getMethods();
String proxyClassStr = "package com.study.dongsq.myProxy;" + rt
+"import java.lang.reflect.Method;"+rt
+"public class $Proxy0 implements " + interfaces[0].getName()
+"{"+rt+"MyInvocationHandler h;" +rt
+"public $Proxy0(MyInvocationHandler h){" + rt
+"this.h=h;" +rt+ "}"
+getMethodString(methods, interfaces[0]) +rt+"}";
return proxyClassStr;
}
private static String getMethodString(Method[] methods, Class intf){
String proxyMe = "";
for(Method method : methods){
proxyMe+="public void " + method.getName()
+"() throws Throwable {" +rt+ "Method md= "
+intf.getName() +".class.getMethod(\""+method.getName()
+"\",new Class[]{});" +rt
+"this.h.invoke(this, md, null);" +rt+ "}" +rt;
}
return proxyMe;
}
private static void createFile(String javaStr){
File file = new File(path +"\\$Proxy0.java");
try {
FileWriter fw = new FileWriter(file);
fw.write(javaStr);
fw.flush();
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private static void compiler(){
try {
JavaCompiler systemJavaCompile = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager standardJavaFileManager = systemJavaCompile.getStandardFileManager(null, null, null);
Iterable<? extends JavaFileObject> javaFileObjects = standardJavaFileManager.getJavaFileObjects(new File(path +"\\$Proxy0.java"));
JavaCompiler.CompilationTask task = systemJavaCompile.getTask(null, standardJavaFileManager, null, null, null, javaFileObjects);
task.call();
standardJavaFileManager.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class MyClassLoader extends ClassLoader {
private File classPathFile;
public MyClassLoader(String path){
this.classPathFile = new File(path);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String className = MyClassLoader.class.getPackage().getName() + "." + name;
if(classPathFile != null){
File classFile = new File(classPathFile,name.replaceAll("\\.","/") + ".class");
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();
}
}
}
return null;
}
}
public interface MyInvocationHandler {
public Object invoke(Object proxy, Method method, Object args) throws Throwable;
}
用自己生成的Proxy去生成一个代理,执行效果是一样的
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/13822.html