一 参考
https://www.jianshu.com/p/af271ad4e056
二 代码位置
https://gitee.com/cakin24/javatest/tree/master/src/main/java/GPProxy
三 代码
1 Customer
package GPProxy;
public class Customer implements Person{
public void findLove(){
System.out.println("高富帅");
System.out.println("身高180cm");
System.out.println("有6块腹肌");
}
}
2 CustomMeipo
package GPProxy;
import java.lang.reflect.Method;
public class CustomMeipo implements GPInvocationHandler {
//被代理的对象,把引用给保存下来
private Person target;
public Object getInstance(Person target) throws Exception{
this.target = target;
Class<?> clazz = target.getClass();
//下半截,老师深入底层来给大家讲解字节码是如何重组的
//用来生成一个新的对象(字节码重组来实现)
return GPProxy.newProxyInstance(new GPClassLoader(),clazz.getInterfaces(),this);
}
@Override
public Object invoke( Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我是媒婆:我要给你找对象,现在已经拿到你的需求");
System.out.println("开始物色");
method.invoke(this.target,args);
System.out.println("如果合适的话,就准备办事");
return null;
}
}
3 CustomPorxyTest
package GPProxy;
public class CustomPorxyTest {
public static void main(String[] args) {
try {
Person obj = (Person)new CustomMeipo().getInstance(new Customer());
System.out.println(obj.getClass());
obj.findLove();
} catch (Exception e) {
e.printStackTrace();
}
}
}
4 GPClassLoader
package GPProxy;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class GPClassLoader extends ClassLoader{
private File classPathFile;
public GPClassLoader(){
String classPath = GPClassLoader.class.getResource("").getPath();
this.classPathFile = new File(classPath);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String className = GPClassLoader.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();
}finally {
if(null != in){
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(out != null){
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
return null;
}
}
5 GPInvocationHandler
package GPProxy;
import java.lang.reflect.Method;
public interface GPInvocationHandler {
public Object invoke( Object proxy, Method method, Object[] args) throws Throwable;
}
6 GPProxy
package GPProxy;
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class GPProxy {
public static final String ln = "\r\n";
public static Object newProxyInstance(GPClassLoader classLoader,Class<?> [] interfaces,GPInvocationHandler h){
try {
//1、动态生成源代码.java文件
String src = generateSrc(interfaces);
//2、Java文件输出磁盘
String filePath = GPProxy.class.getResource("").getPath();
System.out.println(filePath);
File f = new File(filePath + "$Proxy0.java");
FileWriter fw = new FileWriter(f);
fw.write(src);
fw.flush();
fw.close();
//3、把生成的.java文件编译成.class文件
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager manage = compiler.getStandardFileManager(null,null,null);
Iterable iterable = manage.getJavaFileObjects(f);
JavaCompiler.CompilationTask task = compiler.getTask(null,manage,null,null,null,iterable);
task.call();
manage.close();
//4、编译生成的.class文件加载到JVM中来
Class proxyClass = classLoader.findClass("$Proxy0");
Constructor c = proxyClass.getConstructor(GPInvocationHandler.class);
// f.delete();
//5、返回字节码重组以后的新的代理对象
return c.newInstance(h);
}catch (Exception e){
e.printStackTrace();
}
return null;
}
private static String generateSrc(Class<?>[] interfaces){
StringBuffer sb = new StringBuffer();
sb.append("package GPProxy;" + ln);
// sb.append("import GPProxy.*;" + ln);
sb.append("import GPProxy.Person;" + ln);
sb.append("import java.lang.reflect.Method;" + ln);
sb.append("public class $Proxy0 implements " + interfaces[0].getName() + "{" + ln);
sb.append("GPInvocationHandler h;" + ln);
sb.append("public $Proxy0(GPInvocationHandler h) { " + ln);
sb.append("this.h = h;");
sb.append("}" + ln);
for (Method m : interfaces[0].getMethods()){
sb.append("public " + m.getReturnType().getName() + " " + m.getName() + "() {" + ln);
sb.append("try{" + ln);
sb.append("Method m = " + interfaces[0].getName() + ".class.getMethod(\"" + m.getName() + "\",new Class[]{});" + ln);
sb.append("this.h.invoke(this,m,null);" + ln);
sb.append("}catch(Throwable e){" + ln);
sb.append("e.printStackTrace();" + ln);
sb.append("}");
sb.append("}");
}
sb.append("}" + ln);
return sb.toString();
}
}
7 Person
package GPProxy;
public interface Person {
public void findLove();
}
四 测试结果
/F:/Javatest/target/classes/GPProxy/
F:\Javatest\target\classes\GPProxy\$Proxy0.java:4: 错误: 找不到符号
public class $Proxy0 implements GPProxy.Person{
^
符号: 类 Person
位置: 类 GPProxy
F:\Javatest\target\classes\GPProxy\$Proxy0.java:10: 错误: 找不到符号
Method m = GPProxy.Person.class.getMethod("findLove",new Class[]{});
^
符号: 类 Person
位置: 类 GPProxy
2 个错误
class GPProxy.$Proxy0
我是媒婆:我要给你找对象,现在已经拿到你的需求
开始物色
高富帅
身高180cm
有6块腹肌
如果合适的话,就准备办事
五 分析
测试结果有两个错误,但不影响结果,这两个错误主要出现在生成的代码上,生成代码如下:
package GPProxy;
import GPProxy.Person;
import java.lang.reflect.Method;
public class $Proxy0 implements GPProxy.Person { // GPProxy.Person改为Person可规避这个错误
GPInvocationHandler h;
public $Proxy0( GPInvocationHandler h ) {
this.h = h;
}
public void findLove() {
try {
// // GPProxy.Person改为Person可规避这个错误
Method m = GPProxy.Person.class.getMethod("findLove", new Class[]{});
this.h.invoke(this, m, null);
} catch (Throwable e) {
e.printStackTrace();
}
}
}
将GPProxy.Person手动修改为Person可规避错误。
来源:CSDN
作者:cakincqm
链接:https://blog.csdn.net/chengqiuming/article/details/103650836