1.首先看一下自己实现的jdk动态代理:
UserDao:
package com.sixl.dao;
public interface UserDao {
public void query();
public void query(String p);
}
UserDaoImpl:
package com.sixl.dao;
public class UserDaoImpl implements UserDao{
public void query(){
System.out.println("假装查询数据库");
}
public void query(String aa){
System.out.println(aa);
}
}
CoustomInvocationHandler(用于处理代理方法逻辑的接口):
package com.sixl.dao;
import java.lang.reflect.Method;
public interface CoustomInvocationHandler {
public Object invoke(Method method);
public void setParams(Object[] params);
}
TestCustomHandler(继承CoustomInvocationHandler ,具体实现逻辑)
package com.sixl.util;
import com.sixl.dao.CoustomInvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class TestCustomHandler implements CoustomInvocationHandler {
Object target;
Object[] params;
public TestCustomHandler(Object target){
this.target=target;
}
public void setParams(Object[] params){
this.params=params;
}
@Override
public Object invoke(Method method) {
try {
System.out.println("----------------");
return method.invoke(target,params);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}
ProxyUtil(生成Proxy对象的类)
package com.sixl.proxy;
import com.sixl.dao.CoustomInvocationHandler;
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
public class ProxyUtil {
/**
* content --->string
* .java io
* .class
*
* .new 反射----》class
* @return
*/
public static Object newInstance(Class targetInf, CoustomInvocationHandler h){
Object proxy=null;
//String handlerName = CoustomInvocationHandler.class.
Method methods[] =targetInf.getDeclaredMethods();
String line="\n";
String tab ="\t";
String infName = targetInf.getSimpleName();
String content ="";
String packageContent = "package com.google;"+line;
String importContent = "import "+targetInf.getName()+";"+line
+"import com.sixl.dao.CoustomInvocationHandler;"+line
+"import java.lang.Exception;"+line
+"import java.lang.reflect.Method;"+line;
String clazzFirstLineContent = "public class $Proxy implements "+infName+"{"+line;
String filedContent =tab+"private CoustomInvocationHandler h;"+line;
String constructorContent =tab+"public $Proxy (CoustomInvocationHandler h){" +line
+tab+tab+"this.h =h;"
+line+tab+"}"+line;
String methodContent = "";
for (Method method : methods) {
String returnTypeName = method.getReturnType().getSimpleName();
String methodName =method.getName();
// Sting.class String.class
Class args[] = method.getParameterTypes();
String argsContent = "";
String paramsContent="";
String argsClass="";
String params= "Object[] params = new Object[]{";
int flag =0;
for (Class arg : args) {
String temp = arg.getSimpleName();
//String
//String p0,Sting p1,
argsContent+=temp+" p"+flag+",";
paramsContent+="p"+flag+",";
argsClass+=","+temp+".class";
params+="p"+flag;
flag++;
}
params+="};";
if (argsContent.length()>0){
argsContent=argsContent.substring(0,argsContent.lastIndexOf(","));
paramsContent=paramsContent.substring(0,paramsContent.lastIndexOf(",")-1);
}
methodContent+=tab+"public "+returnTypeName+" "+methodName+"("+argsContent+") {"+line
+tab+tab+params+line
+tab+tab+"h.setParams(params);"+line
+tab+tab+"Method method = null;"+line
+tab+tab+"try{"+line
+tab+tab+tab+"method = Class.forName(\""+targetInf.getName()+"\").getDeclaredMethod(\""+methodName+"\""+argsClass+");"+line
+tab+tab+"}"+line +tab+tab+"catch(Exception e){}"+line;
if (returnTypeName.equals("void")){
methodContent+=tab+tab+"h.invoke(method);"+line;
}else {
methodContent+=tab+tab+"return ("+returnTypeName+")h.invoke(method);"+line;
}
methodContent+=tab+"}"+line;
}
content=packageContent+importContent+clazzFirstLineContent+filedContent+constructorContent+methodContent+"}";
File file =new File("d:\\com\\google\\$Proxy.java");
try {
if (!file.exists()) {
file.createNewFile();
}
FileWriter fw = new FileWriter(file);
fw.write(content);
fw.flush();
fw.close();
//编译,只需了解这部分代码
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
Iterable units = fileMgr.getJavaFileObjects(file);
JavaCompiler.CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);
t.call();
fileMgr.close();
URL[] urls = new URL[]{new URL("file:D:\\\\")};
//使用URLClassLoader类加载器将class文件加载到内存中生成$Proxy的Class类
URLClassLoader urlClassLoader = new URLClassLoader(urls);
Class clazz = urlClassLoader.loadClass("com.google.$Proxy");
//通过反射得到构造方法的方式得到对象并返回
Constructor constructor = clazz.getConstructor(CoustomInvocationHandler.class);
proxy = constructor.newInstance(h);
//clazz.newInstance();
//Class.forName()
}catch (Exception e){
e.printStackTrace();
}
return proxy;
}
}
测试类:
package com.sixl.test;
import com.sixl.dao.LubanDao;
import com.sixl.dao.LubanDaoImpl;
import com.sixl.dao.UserDao;
import com.sixl.dao.UserDaoImpl;
import com.sixl.proxy.ProxyUtil;
import com.sixl.util.LubanInvocationHandler;
import com.sixl.util.TestCustomHandler;
import sun.misc.ProxyGenerator;
public class Test {
public static void main(String[] args) {
UserDao proxy1= (UserDao)ProxyUtil.newInstance(UserDao.class, new TestCustomHandler(new UserDaoImpl()));
proxy1.query("123");
}
}
可以得到生成的代理类:
package com.google;
import com.sixl.dao.LubanDao;
import com.sixl.dao.CoustomInvocationHandler;
import java.lang.Exception;
import java.lang.reflect.Method;
public class $Proxy implements LubanDao{
private CoustomInvocationHandler h;
public $Proxy (CoustomInvocationHandler h){
this.h =h;
}
public String proxy() {
Object[] params = new Object[]{};
h.setParams(params);
Method method = null;
try{
method = Class.forName("com.sixl.dao.LubanDao").getDeclaredMethod("proxy");
}
catch(Exception e){}
return (String)h.invoke(method);
}
}
主要流程为:
.java---->.class---->加载到jvm中----->Object
这里自定义的CoustomInvocationHandler的invoke方法没有传params和Object,而是作为属性设置进去,可以更改为直接将params作为invoke方法的参数。
ProxyUtil主要根据接口和InvocationHandler生成代理的java文件,通过编译生成.class文件,再通过URLClassLoader加载到内存中生成代理类的Class,然后生成代理对象。
存在一定的缺陷:
1.首先要生成文件
2.需要动态编译class
3.需要一个URLClassLoader
对于性能来说,最大的影响在于对文件IO的操作。本动态代理需要生成java文件,读取java文件,因此效率会很低。