jdk动态代理实现(源码),包括自己实现的动态代理(1)

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文件,因此效率会很低。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值