手写JDK动态代理

静态代理又分为继承和聚合,继承目标类,然后增强方法,或者和目标类实现同一个接口,在代理类的构造方法中传入一个目标类,增强目标类的方法。这样的做法如果有不同的增强需求,会产生大量的代理类,非常不便。如果自己实现一个代理的工具类来做代理:
目标类:

public class UserDaoImpl implements UserDao{

    @Override
    public void query(String ss){
        System.out.println("查询了数据库"+ss);
    }

}

接口:

public interface UserDao {
    public void query(String ss);
}

如果我们自己写一个代理类来代理日志:(和目标类实现了相同的接口)

public class UserDaoLog implements UserDao {

    private UserDao userDao;

    public UserDaoLog(UserDao userDao){
        this.userDao = userDao;
    }

    @Override
    public void query(String aa) {
        System.out.println("---log---");
        userDao.query(aa);
    }
}

然后思考怎么将这个类的对象动态的创建出来,并且执行query()方法,我们知道创建一个类,需要java文件,然后需要.class文件,最后将对象创建出来执行方法,所以写一个工具类生成一个java文件
包:

String packageContent = "package com.google;"+line;

导入包

String importContent = "import "+targetInf.getName()+";"+line;

类的第一行:

String classFirstLineContent = "public class $Proxy implements "+infName+"{"+line;

目标对象属性:

String fieldContent = tab+"private "+infName+" target;"+line;

构造方法:

 String contructContent = tab+"public $Proxy ("+infName+" target){"+line
                                    +tab+tab+"this.target = target;"+line
                                    +tab+"}"+line;

方法:

String methodContent = "";
        for (Method method : methods) {
            //方法返回值类型
            String returnType = method.getReturnType().getSimpleName();
            String methodName = method.getName();
            //方法的参数
            Class[] args = method.getParameterTypes();
            String argsContent = "";
            String paramsContent = "";
            int flag = 0;
            for (Class arg : args) {
                String temp = arg.getSimpleName();
                argsContent+=temp+" i"+flag+",";
                paramsContent+="i"+flag+",";
                flag++;
            }
            if(argsContent.length()>0){
                argsContent=argsContent.substring(0,argsContent.lastIndexOf(",")-1);
                paramsContent=paramsContent.substring(0,paramsContent.lastIndexOf(",")-1);
            }
            methodContent+=tab+"public "+returnType+" "+methodName+"("+argsContent+") {"+line
                            +tab+tab+"System.out.println(\"log\");"+line
                            +tab+tab+"target."+methodName+"("+paramsContent+");"+line
                            +tab+"}"+line;

        }

最后这个类就构造完成了,使用字符串来创建出来的,然后通过文件流的方式,输出为一个java文件

File file = new File("d:\\com\\google\\$Proxy.java");
        try {
            if(!file.exists()){
                    file.createNewFile();
            }
            FileWriter fileOutputStream = new FileWriter(file);
            fileOutputStream.write(content);
            fileOutputStream.flush();

        } catch (IOException e) {
            e.printStackTrace();
        }finally {
        }

这样java文件就产生了,然后将java文件编译成一个.class,由于产生的java文件在我们的磁盘中,所以需要用java代码来编译

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); //编译类
        //文件管理器
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null,null,null);
        //放在文件管理器
        Iterable units = fileManager.getJavaFileObjects(file);

        JavaCompiler.CompilationTask task = compiler.getTask(null,fileManager,null,null,null,units);
        task.call();
        try {
            fileManager.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

将class文件加载:

try {
            URL[] urls = new URL[]{new URL("file:D:\\\\")};
            URLClassLoader urlClassLoader = new URLClassLoader(urls);
            Class aClass = urlClassLoader.loadClass("com.google.$Proxy");
            try {
                Constructor constructor = aClass.getConstructor(targetInf);
                try {
                     **proxy** = constructor.newInstance(target);
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
//            Object o = aClass.newInstance();    //调用的是默认的构造方法
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

这样有了class文件,通过反射就创建出了代理对象
用自己创建的动态代理工具来创建:

    public static void main(String[] args) {
//        UserDaoLogImpl userDaoLog = new UserDaoLogImpl();
//        UserDaoImpl userDao = new UserDaoImpl();
//        UserDaoPowerImpl userDaoPower = new UserDaoPowerImpl();
//        userDaoLog.query();
//        userDaoPower.query();

        //----------------------------------------------------
/*        UserDao target = new UserDaoImpl();
        UserDaoLog userDaoLog = new UserDaoLog(target);
        userDaoLog.query();*/
/*        UserDaoLogAndTimerImpl userDaoLogAndTimer = new UserDaoLogAndTimerImpl();
        userDaoLogAndTimer.query();*/
        UserDao target = new UserDaoImpl();
        UserDao proxy = (UserDao)ProxyUtil.newInstence(target);
        proxy.query("ss");
/*        MyDao myDao = (MyDao)ProxyUtil.newInstence(new MyDaoImpl());
        myDao.query();*/
    }

执行结果:
在这里插入图片描述
在磁盘中生成的java和class文件:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值