当前位置: 移动技术网 > IT编程>软件设计>面向对象 > 动态代理类的实现和解析

动态代理类的实现和解析

2019年09月25日  | 移动技术网IT编程  | 我要评论

 静态代理类

  由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.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

 

 

 

 

 

 

 

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网