前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >教你如何手写一个动态代理【模拟JDK】

教你如何手写一个动态代理【模拟JDK】

作者头像
田维常
发布2020-04-26 12:07:45
3170
发布2020-04-26 12:07:45
举报

模拟JDK定义一个InvokeHandler

代码语言:javascript
复制
public interface MyInvocationHandler {

	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable;

}

定义一个实现类

代码语言:javascript
复制
package com.jv.own;

import java.lang.reflect.Method;

public class MyOwnInvocationHandler implements MyInvocationHandler{
	private UserDao target;
	public MyOwnInvocationHandler(UserDao target){
		this.target = target;
	}
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("invoke before");
		method.invoke(target,args);
		System.out.println("invoke after");
		return null;
	}
}

模拟JDK的Proxy类

代码语言:javascript
复制
package com.jv.own;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

public class MyProxyUtil {
	private static final String l = "\n\r";
	private static final String t = "\t";

	public static Object newInstance(ClassLoader classLoader,Class[] interfaces,MyInvocationHandler handler) throws Exception{
		StringBuilder sb = new StringBuilder();
		StringBuilder sbImport = new StringBuilder();
		StringBuilder sbImplements = new StringBuilder();
		StringBuilder sbMethods = new StringBuilder();

		//############################################生成源代码############################################
		//包定义
		sb.append("package com.jv.own;").append(l+l);
		if(interfaces == null || interfaces.length==0){
			throw new Exception("接口不能为空");
		}
		//生成导入和implements
		for (Class anInterface : interfaces) {
			sbImport.append("import "+anInterface.getName()+";"+l);
			sbImplements.append(anInterface.getSimpleName()+",");
		}
		sbImport.append("import java.lang.reflect.Method;").append(l+l);
		sbImport.append("import com.jv.own.MyInvocationHandler;").append(l+l);
		sb.append(sbImport.toString());
		String temp = sbImplements.toString().substring(0,sbImplements.toString().lastIndexOf(","));
		//类定义
		sb.append("public class MyProxy implements ").append(temp).append("{").append(l).append(l);
		sb.append(t+"private MyInvocationHandler handler;").append(l);
		//构造函数
		sb.append(t+"public MyProxy(").append("MyInvocationHandler handler){").append(l);
		sb.append(t+t+"this.handler = handler;").append(l).append(t).append("}").append(l).append(l);
		//生成接口里面所有的
		for (Class anInterface : interfaces) {
			Method[] methods = anInterface.getMethods();
			for (Method method : methods) {
				String parameter = "";
				String parameterType = "";
				int i = 1;
				for(Class cl:method.getParameterTypes()){
					parameter += cl.getName() + " p" + i++ +",";
					parameterType += "Class.forName(\""+cl.getTypeName()+"\")"+",";
				}
				if(parameter!=null&&!parameter.equals("")) {
					parameter = parameter.substring(0, parameter.lastIndexOf(","));
					parameterType = parameterType.substring(0, parameterType.lastIndexOf(","));
				}
				sbMethods.append(t).append("public ").append(method.getReturnType().getName()).append(" ").append(method.getName())
						 .append("(").append(parameter).append("){").append(l+t+t);
				sbMethods.append("try{").append(l+t+t+t);
				String args = "Object[] args = new Object[]{";
				for(int j=1;j<i;j++){
					args += "p"+j+",";
				}
				args = args.substring(0,args.lastIndexOf(","))+"};";
				sbMethods.append(args).append(l+t+t+t);

				StringBuilder methodContent = new StringBuilder();
				//methodContent.append("Method method = Class.forName(\""+anInterface.getTypeName()+"\").getMethod(\""+method.getName()+"\","+parameterType+");");
				methodContent.append("Method method = "+anInterface.getName()+".class.getMethod(\""+method.getName()+"\","+parameterType+");");
				sbMethods.append(methodContent.toString()).append(l+t+t+t);

				if(method.getReturnType().getName().equals("void")){
					sbMethods.append("handler.invoke(this,method,args);").append(l+t+t);
				}else{
					sbMethods.append("return "+"("+method.getReturnType().getName()+")"+"handler.invoke(this,method,args);").append(l+t+t);
				}
				sbMethods.append("}catch(Throwable e){"+l+t+t+t+"return null;"+l+t+t+"}"+l+t);
				sbMethods.append("}").append(l);
			}
		}
		sb.append(sbMethods.toString());

		sb.append("}");
		System.out.println(sb.toString());

		//############################################将源代码写入磁盘文件############################################
		String filePath = MyProxyUtil.class.getResource("").getPath()  + "MyProxy.java";
		System.out.println(filePath);
		FileWriter fileWriter = new FileWriter(filePath);
		fileWriter.write(sb.toString());
		fileWriter.flush();
		fileWriter.close();
		//############################################编译源代码############################################
		JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
		StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
		Iterable iterable = fileManager.getJavaFileObjects(filePath);
		JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, null, null, iterable);
		task.call();
		fileManager.close();
		//############################################将文件通过URLClassLocader或者自定义ClassLoader进行加载############################################
		URL[] urls = new URL[]{new URL("file:f\\\\projects\\own\\spring-framework-master\\proxy\\out\\production\\classes")};

		URLClassLoader urlClassLoader = new URLClassLoader(urls);
		Class clazz = urlClassLoader.loadClass("com.jv.own.MyProxy");
		//############################################实例化############################################

		//返回
		Constructor[] constructors = clazz.getConstructors();
		constructors[0].newInstance(handler);
		return constructors[0].newInstance(handler);
	}
}

其他类

代码语言:javascript
复制
package com.jv.own;

public class User {
	private String userName;

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}
}
代码语言:javascript
复制
package com.jv.own;

public interface UserDao {
	User query(String name);
}
代码语言:javascript
复制
package com.jv.own;

public class UserDaoImpl implements UserDao {
	@Override
	public User query(String name) {
		System.out.println("UserDaoImpl execute query");
		return null;
	}
}

测试类

代码语言:javascript
复制
package com.jv.own;


public class TestMyProxy {
	public static void main(String[] args) {
		MyInvocationHandler handler = new MyOwnInvocationHandler(new UserDaoImpl());
		try {
			UserDao dao = (UserDao)MyProxyUtil.newInstance(com.jv.jdk.UserDao.class.getClassLoader(),new Class[]{UserDao.class},handler);
			dao.query("a");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

生成的代码:

代码语言:javascript
复制
package com.jv.own;

import com.jv.own.UserDao;
import java.lang.reflect.Method;

import com.jv.own.MyInvocationHandler;

public class MyProxy implements UserDao{

	private MyInvocationHandler handler;
	public MyProxy(MyInvocationHandler handler){
		this.handler = handler;
	}

	public com.jv.own.User query(java.lang.String p1){
		try{
			Object[] args = new Object[]{p1};
			Method method = com.jv.own.UserDao.class.getMethod("query",Class.forName("java.lang.String"));
			return (com.jv.own.User)handler.invoke(this,method,args);
		}catch(Throwable e){
			return null;
		}
	}
}

执行结果:

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-04-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java后端技术栈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档