欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

动态代理类的实现和解析

程序员文章站 2022-04-16 08:17:31
静态代理类: 由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了 动态代理类: 与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统 ......

 静态代理类

  由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了

动态代理类:
   与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的proxy类和invocationhandler 接口提供了生成动态代理类的能力。

话不多说看代码。。

 

package proxybase;

import java.io.ioexception;
import java.lang.reflect.constructor;
import java.lang.reflect.invocationhandler;
import java.lang.reflect.invocationtargetexception;
import java.net.malformedurlexception;
import java.util.arrays;

import javax.tools.javacompiler;
import javax.tools.javacompiler.compilationtask;
import javax.tools.standardjavafilemanager;
import javax.tools.toolprovider;

public class myproxy {
    static class<?>[] parametertypes = { invocationhandler.class };
    protected invocationhandler h;

    protected myproxy(invocationhandler h) {
        this.h = h;
    }

    public static object newinstance(classloader loader, class<?>[] interfaces, invocationhandler h) {
        // :产生一个代理类的字节码对象
        class<?> c1 = null;
        try {
            // :通过getclass0方法可以得到一个代理类的字节码对象
            c1 = getclass0(loader, interfaces);
        } catch (malformedurlexception e1) {
            e1.printstacktrace();
        }
        constructor<?> constructor = null;
        try {
            /**
             * 调用子类$proxy0(invocationhandler h)构造函数,由于继承了myproxy类,
             * 所以又会继续调用父类的myproxy(invocationhandler h)构造函数给 h初始化一个值;
             */
            constructor = c1.getdeclaredconstructor(invocationhandler.class);
            /**
             * 返回一个生成的代理类对象,并将invocationhandler 的实现类对象传入进去。从而达到给h赋值的目的
             * 
             */
            return constructor.newinstance(h);
        } catch (nosuchmethodexception | securityexception | instantiationexception | illegalaccessexception
                | illegalargumentexception | invocationtargetexception e) {
            e.printstacktrace();
        }
        return null;
    }

    // :用来生成一个代理类对象
    private static class<?> getclass0(classloader loader, class<?>[] interfaces) throws malformedurlexception {
        class<?> forname = null;
        try {
            gennerateclass.generate(interfaces[0]);
            // :动态编译
            javacompiler compiler = toolprovider.getsystemjavacompiler();
            standardjavafilemanager filemgr = compiler.getstandardfilemanager(null, null, null);
            iterable units = filemgr.getjavafileobjects(system.getproperty("user.dir") + "/src/"
                    + interfaces[0].getpackage().getname() + "/" + interfaces[0].getsimplename() + "$proxy0.java");
            // :"-d", system.getproperty("user.dir")+"/bin/" 用来指定java文件编译后存放的地方
            iterable<string> options = arrays.aslist("-d", system.getproperty("user.dir") + "/bin/");
            compilationtask t = compiler.gettask(null, filemgr, null, options, null, units);
            t.call();
            try {
                filemgr.close();
            } catch (ioexception e) {
                e.printstacktrace();
            }
            // :得到代码自动生成代理类的实例对象
            forname = class.forname(interfaces[0].getname() + "$proxy0");
        } catch (classnotfoundexception e) {
            e.printstacktrace();
        }
        return forname;
    }
}

 这个gennerateclass类是用来生成代理类的java文件的,是通过字符串拼接而成,仅供参考.

  1 package proxybase;
  2 
  3 import java.io.bufferedwriter;
  4 import java.io.file;
  5 import java.io.filewriter;
  6 import java.io.ioexception;
  7 import java.lang.reflect.method;
  8 
  9 public class gennerateclass {
 10     public static void generate(class<?> clazz) {
 11         string methodstr = "";  //:方法字符串的拼接
 12         string classstr = "";    //:类名的拼接
 13         string packagestr = "";    //:导入包名的拼接
 14         string classparamstr = ""; //:
 15         string staticcodestr = "static {\ntry {";//:静态代码块的拼接
 16         string member_var = "";  //:成员变量的拼接
 17         string package1 = clazz.getpackage().getname();
 18         string simplename = clazz.getsimplename(); //:获得简单类名
 19         string classname = clazz.getname();    //:获得权限定类名
 20         //:构造函数的拼接
 21         string counstructstr = "public " + simplename + "$proxy0(invocationhandler h) {\r\n" + "        super(h);\r"
 22                 + "    }\n";
 23         // :导包
 24         packagestr = "package " + package1 + ";\n"
 25                 + "import proxybase.myproxy;\r import java.lang.reflect.invocationhandler;\n"
 26                 + "import java.lang.reflect.method;\n";
 27         // :构建类名
 28         classstr += "public class " + simplename + "$proxy0 extends myproxy implements " + simplename + "{\n" + "";
 29         // :构建代理类的方法
 30         method[] methods = clazz.getmethods();
 31         int i = 0;
 32         for (method method : methods) {
 33             string paramstr = "";//:参数变量拼接
 34             int paramcount = 0; //:参数个数计数用来生成参数变量
 35             i += 1;
 36             member_var += "private static method m" + i + ";\n";//成员变量的拼接
 37             string tempstr = "";  //:参数列表
 38             string methodname = method.getname();// 方法名
 39             class<?>[] parametertypes = method.getparametertypes();// 参数列表的class类型
 40             class<?> returntype = method.getreturntype();// 返回值类型
 41             methodstr += "public final " + returntype.getname() + " " + methodname + "(";
 42             // :参数列表名字符串
 43             for (class<?> type : parametertypes) {
 44                 paramcount += 1;
 45                 tempstr += "," + type.getname() + " param" + paramcount;
 46                 paramstr += ",param" + paramcount;
 47                 classparamstr += "," + type.getname() + ".class";
 48             }
 49             //:
 50             if (!paramstr.isempty()) {
 51                 paramstr = paramstr.substring(1);
 52             }
 53             if (!tempstr.isempty()) {
 54                 tempstr = tempstr.substring(1);
 55             }
 56             if (classparamstr.isempty()) {
 57                 classparamstr = "null";
 58             } else {
 59                 classparamstr = classparamstr.substring(1);
 60             }
 61             //:判断返回值是否时void,是则不需要return
 62             //方法的拼接
 63             if (returntype.getname().equals("void")) {
 64                 methodstr = methodstr + tempstr + ")\n{\n" + "\ttry{\n\tthis.h.invoke(this,m" + i + ",new object[]{"
 65                         + paramstr + "});" + "} catch (throwable e) {\r\n" + "            e.printstacktrace();\r\n"
 66                         + "        }\n}\n";
 67             } else {
 68                 methodstr = methodstr + tempstr + ")\n{\nobject result=null;\n\ttry{\n\tresult=this.h.invoke(this,m" + i
 69                         + ",new object[]{" + paramstr + "});" + "} catch (throwable e) {\r\n"
 70                         + "            e.printstacktrace();\r\n" + "}\nreturn (" + returntype.getname() + ")result;}\n";
 71             }
 72             // :构建静态代码块
 73             if (!classparamstr.equals("null")) {
 74                 staticcodestr += "m" + i + " = class.forname(\"" + classname + "\").getmethod(\"" + methodname
 75                         + "\",new class<?>[]{" + classparamstr + "});";
 76             } else {
 77                 staticcodestr += "m" + i + " = class.forname(\"" + classname + "\").getmethod(\"" + methodname + "\");";
 78             }
 79             classparamstr = "";
 80         }
 81         //静态代码块的拼接
 82         staticcodestr += "} catch (nosuchmethodexception e) {\r\n" + "            e.printstacktrace();\r\n"
 83                 + "        } catch (securityexception e) {\r\n" + "            e.printstacktrace();\r\n"
 84                 + "        } catch (classnotfoundexception e) {\r\n" + "            e.printstacktrace();\r\n" + "        }}";
 85         //总和成java文件的内容
 86         packagestr = packagestr + classstr + member_var + counstructstr + methodstr + staticcodestr + "\n}";
 87         //通过流写入成文件
 88         filewriter fout = null;
 89         try {
 90             fout = new filewriter(new file("src/" + package1 + "/" + simplename + "$proxy0.java"));
 91         } catch (ioexception e) {
 92 
 93             e.printstacktrace();
 94         }
 95         bufferedwriter out = new bufferedwriter(fout);
 96         try {
 97             out.write(packagestr);
 98         } catch (ioexception e) {
 99             e.printstacktrace();
100         }
101         try {
102             out.close();
103             fout.close();
104         } catch (ioexception e) {
105             e.printstacktrace();
106         }
107     }
108 }

 

/***
 *这个类是用来制定你的代理对象,在调用方法时需要进行哪些前置处理和后置处理
 *
*/
1 package proxybase; 2 3 import java.lang.reflect.invocationhandler; 4 import java.lang.reflect.method; 5 6 public class hadler<t> implements invocationhandler { 7 private t target; 8 //通过new hadler将被代理的那个对象传入, 9 public hadler(t target) { 10 super(); 11 this.target = target; 12 } 13 private void before() { 14 system.out.println("先吃饭"); 15 } 16 private void after() { 17 system.out.println("再睡觉"); 18 } 19 //这里根据自己的逻辑来制定相应的invoke方法,视情况而定,此处的写法只是来简单测试代理对象。 20 @override 21 public object invoke(object proxy, method method, object[] args) throws throwable { 22 before(); 23 object invoke = method.invoke(target,args); 24 after(); 25 return invoke; 26 } 27 }

这里时生成后的代理类文件person$proxy0.java

package proxybase;

import java.lang.reflect.invocationhandler;
import java.lang.reflect.method;

public class hadler<t> implements invocationhandler {
    private t target;
    //通过new hadler将被代理的那个对象传入,
    public hadler(t target) {
        super();
        this.target = target;
    }
    private void before() {
        system.out.println("先吃饭");
    }
    private void after() {
        system.out.println("再睡觉");
    }
    //这里根据自己的逻辑来制定相应的invoke方法,视情况而定,此处的写法只是来简单测试代理对象。
    @override
    public object invoke(object proxy, method method, object[] args) throws throwable {
        before();
        object invoke = method.invoke(target,args);
        after();
        return invoke;
    }
}

接下来是写一个接口,jdk中的动态代理是针对接口代理的,而cglib是针对类进行代理的,这个接口将会被代理,分别写了四个方法来测试,无参,一参,两参,和一个有返回值

的方法,都是用来测试gennerateclass类生成的是否正确,(目前只测试了这几种,如果大神发现有误,还望联系斧正)

1 package proxy;
2 
3 
4 public interface person {
5     void study2();
6     void study2(int a);
7     void study3(int b ,string a);
8     int returnint(int a);
9 }

接下来写一个person的实现类,然后通过代理类来代理这个实现类对象,进行一些前置处理和后置处理。

 1 package proxy;
 2 
 3 public class student implements person {
 4     public void study2() {
 5         system.out.println("正在考试中");
 6     }
 7 
 8     @override
 9     public void study2(int a) {
10         system.out.println(a);
11     }
12 
13     @override
14     public void study3(int b, string a) {
15         system.out.println(a+b);
16     }
17 
18     @override
19     public int returnint(int a) {
20         
21         return a;
22     }
23 }

最后就是测试和使用所写的代理类了

第一步,创建一个person类型的对象student,

第二步,创建一个invocationhandler的实现类对象,并将student传入进去,这个student会将生成实现类中的成员变量target进行赋值初始化。

第三步,调用myproxy中的newinstance方法来获得代理类对象(注意:newinstance 中的参数要是实现类的类类型来获得他的实现interface接口的类类型,即person,生成代理类的java文件就是依据该接口生成的)

第四步, 测试生成的代理类对象,结果如下,通过原生student和代理类对象stu调用相同方法进行对比

 1 public static void main(string[] args) {
 2         person student = new student();
 3         
 4         invocationhandler h = new hadler<person>(student);
 5         person stu = (person) myproxy.newinstance(person.class.getclassloader(), student.class.getinterfaces(), h);
 6         stu.study2();
 7         system.out.println("-------");
 8         student.study2();
 9         stu.study2(4);
10         stu.study3(4, "a");
11         int a = stu.returnint(2015);
12         system.out.println(a);
13     }

运行结果:

先吃饭
正在考试中
再睡觉
-------
正在考试中
先吃饭
4
再睡觉
先吃饭
a4
再睡觉
先吃饭
再睡觉
2015