springmvc 动态代理 JDK实现与模拟JDK纯手写实现。

首先明白 动态代理和静态代理的区别;

     静态代理:①持有被代理类的引用  ② 代理类一开始就被加载到内存中了(非常重要)

            动态代理:JDK中的动态代理中的代理类是动态生成的。并且生成的动态代理类为$Proxy0

 静态代理实例1、创建一个接口:

 2、创建一个实现类,张三,张三能够吃饭,张三可以找对象

1
2
3
4
5
6
7
8
9
10
package proxy;
 
public class ZhangSan implements People {
 
    public void zhaoduixiang() throws Throwable{
        System.out.println(" 我只要漂亮的");
         
    }
     
}

 3、创建一个实现父类,父类持有张三的引用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package proxy;
 
public class HisDady implements People {
        ZhangSan zs;
        public HisDady(ZhangSan zs){
            this.zs=zs
        }
    public void zhaoduixiang() throws Throwable{
                before()
        zs.zhaoduixiang();
        afger()
    }
           
    public void afger() throws Throwable{
        System.out.println(" 家境要好");
         
    }
           
    public void before() throws Throwable{
        System.out.println(" 要有学历");
         
    }
           
     
}                       

 动态代理:

1、创建一个申明类ProxyHandler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package proxy;
 
import java.awt.event.InvocationEvent;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
 
 
public class ProxyHandler  implements InvocationHandler{
    People peaple=null;
    public ProxyHandler(People people){
        this.peaple=people;
    }
 
    public void before()throws Throwable{
        System.out.println("吃饭之前要洗手");
    }
    public void after()throws Throwable{
        System.out.println("吃饭以后要洗碗");
    }
 
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        before();
        method.invoke(peaple,null);
        after();
        return null;
    }
 
}

 

2、创建一个test类 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package proxy;
 
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Proxy;
 
import sun.misc.ProxyGenerator;
 
public class Test {
    public static void main(String[] args) throws Throwable{
        System.out.println("JDK写的动态代理");
         
        People people=(People) Proxy.newProxyInstance(People.class.getClassLoader(),
                new Class[]{People.class}, new ProxyHandler(new ZhangSan()));
        people.eat();
    }
    public void sleep() throws Throwable{
        System.out.println("睡觉");
    }
    public void sport()throws Throwable{
        System.out.println("睡觉");
    }
}

 执行结果:

打印如图所示,那么People一定执行了ProxyHandler 中的invoke方法,并且首先执行before()  再执行method.invoke(peaple,null);最后执行 after();

那么问题来了,为什么会这么执行了?我们明明调用的People.eat()方法啊。

解析步骤:我们打印此时的People对象的名字,看看接口对应中到底是个什么东西:

        在test中的      people.eat();后面加入:
        
        System.out.println(people.getClass().getName());

打印结果为:Proxy.$Proxy0 ,这是个什么鬼东西,原来,people对象中保存的是一个类名为 $Proxy0的对象,我们调用的是$Proxy0的eat()方法,

所以我们最好看看$Proxy0的源码:

   如何读取$Proxy0的代码(由于$Proxy0JDK会自动删除,所以我们要把它写入到一个对应的文件中 ,代码如下):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package proxy;
 
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Proxy;
 
import sun.misc.ProxyGenerator;
 
public class Test {
    public static void main(String[] args) throws Throwable{
        System.out.println("JDK写的动态代理");
         
        People people=(People) Proxy.newProxyInstance(People.class.getClassLoader(),
                new Class[]{People.class}, new ProxyHandler(new ZhangSan()));
        people.eat();
         
        System.out.println(people.getClass().getName());
        creatProxyClassFile();
    }
    public static void creatProxyClassFile(){
        byte[] data=ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{People.class});
        try {
            FileOutputStream out= new FileOutputStream("$Proxy0.class");
            out.write(data);
            out.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
         
    }
    public void sleep() throws Throwable{
        System.out.println("睡觉");
    }
    public void sport()throws Throwable{
        System.out.println("睡觉");
    }
}

 打开对应的项目工作空间,你会发现一个对应$Proxy0文件;

那么其中有什么玄妙,导致我们调用$Proxy0.eat()方法的时候,会调用invoke()方法了

我们看看Proxy0类的源码,请用反编译软件打开Proxy0.class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import proxy.People;
 
public final class $Proxy0 extends Proxy
  implements People
{
  private static Method m1;
  private static Method m3;
  private static Method m0;
  private static Method m2;
 
  public $Proxy0(InvocationHandler paramInvocationHandler)
    throws
  {
    super(paramInvocationHandler);
  }
 
  public final boolean equals(Object paramObject)
    throws
  {
    try
    {
      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
 
  public final void eat()
    throws Throwable
  {
    this.h.invoke(this, m3, null);
  }
 
  public final int hashCode()
    throws
  {
    try
    {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
 
  public final String toString()
    throws
  {
    try
    {
      return (String)this.h.invoke(this, m2, null);
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
 
  static
  {
    try
    {
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m3 = Class.forName("proxy.People").getMethod("eat", new Class[0]);
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }
}

 请注意其中的一些方法和属性,比如public final void eat() throws Throwable { this.h.invoke(this, m3, null); }   ,其中 该对象的eat()方法是调用的invoke 方法,那h是什么意思, 

因为Proxy0 :public final class $Proxy0 extends Proxy,在Proxy中查看  发现:   protected InvocationHandler h;,所以h就是一个我们传入的InvocationHandler 对象,也就是调用的是InvocationHandler 的invoke方法。  这样我们就明白了为什么会出现console中打印的结果了吧。

 

纯手写动态代理,不使用任何JDK:

1、 创建一个MyInvocationHandler 接口,模拟InvocationHandler

1
2
3
4
5
6
7
8
package proxy;
 
import java.lang.reflect.Method;
 
public interface MyInvocationHandler {
    public Object invoke(Object proxy,Method method,Object args)
        throws Throwable;
}

 2、实现该接口MyProxyHandler,模拟ProxyHandler,和原来动态代理完全一个样,只是改了下代码形式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package proxy;
 
import java.lang.reflect.Method;
 
public class MyProxyHandler implements MyInvocationHandler {
    People peaple=null;
    public MyProxyHandler(People people){
        this.peaple=people;
    }
    public Object invoke(Object proxy, Method method, Object args)
            throws Throwable {     
        before();
        method.invoke(peaple,null);
        after();
        return null;
    }
    public void before(){
        System.out.println("吃饭之前要洗手");
    }
    public void after(){
        System.out.println("吃饭以后要洗碗");
    }
 
}

 3、新建一个Proxy类,MyProxy,用来模拟Proxy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package proxy;
 
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
 
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
 
import org.omg.CORBA.INTF_REPOS;
 
public class MyProxy {
    static String rt="\r\t";
    public static Object createProxyInstance(ClassLoader loader,Class intf,MyInvocationHandler handler){
        try {
            Method[] methods=intf.getMethods();
            //1用流的方式创建一个Java文件,
                String proxyClass="package proxy;"+rt
                        +"import java.lang.reflect.Method;"+rt
                        +"public class $Proxy0 implements "+intf.getName()+"{"+rt
                        +"MyInvocationHandler h;"+rt
                        +"public $Proxy0(MyInvocationHandler h)"+"{"+rt
                        +"this.h= h;"+rt+"}"
                        +getMethodString(methods,intf)+rt+"}";
            //2 把类生成文件,
            String filename="D:/WorkSpace/proxy/src/proxy/$Proxy0.java";
            File f=new File(filename);
     
            FileWriter fw=new FileWriter(f);
            fw.write(proxyClass);
            fw.flush();
            fw.close();
             
            //3编译Java文件
            JavaCompiler compiler=ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager fileMgr =compiler.getStandardFileManager(null, null, null);
            Iterable units=fileMgr.getJavaFileObjects(filename);
            CompilationTask t=compiler.getTask(null, fileMgr, null, null, null, units);
            t.call();
            fileMgr.close();
             
            //把class加载到内存中去
            MyClassLoader loader1=new MyClassLoader("D:/WorkSpace/proxy/src/proxy/");
            Class proxy0Class=loader1.findClass("$Proxy0");
            Constructor m=proxy0Class.getConstructor(MyInvocationHandler.class);
            Object o=m.newInstance(handler);
            return o;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
         
    }  
    public static String getMethodString(Method[] methods,Class intf){
        String proxyMe="";
        for(Method method: methods){
            proxyMe+="public void "+method.getName()+"() throws Throwable {"+rt
                    +"Method md= "+intf.getName()+".class.getMethod(\""+method.getName()
                    +"\",new Class[]{});"+rt
                    +"this.h.invoke(this,md,null);"+rt+"}"+rt;
                     
        }
        return proxyMe;
    }
}

 4、创建一个测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package proxy;
 
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Proxy;
 
import sun.misc.ProxyGenerator;
 
public class Test {
    public static void main(String[] args) throws Throwable{
        System.out.println("JDK写的动态代理");
         
        People people=(People) Proxy.newProxyInstance(People.class.getClassLoader(),
                new Class[]{People.class}, new ProxyHandler(new ZhangSan()));
        people.eat();
         
         
/*      People people1=(People) MyProxy.createProxyInstance(People.class
                .getClassLoader(),People.class, new MyProxyHandler(
                        new ZhangSan()));
        System.out.println(people1.getClass().getName());
        System.out.println("自己写的动态代理");
        people1.eat();  */ 
         
         
        System.out.println(people.getClass().getName());
        creatProxyClassFile();
    }
    public static void creatProxyClassFile(){
        byte[] data=ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{People.class});
        try {
            FileOutputStream out= new FileOutputStream("$Proxy0.class");
            out.write(data);
            out.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
         
    }
}

 结果:

此次是我观看动脑学院免费教学课后的练习,非常感谢Jack老师,老师讲的很好,我学了很多。

posted @   Adding  阅读(1824)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示