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

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

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

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

package proxy;

public interface People {
public void zhaoduixiang()throws Throwable; }

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

package proxy;

public class ZhangSan implements People {

	public void zhaoduixiang() throws Throwable{
System.out.println(" 我只要漂亮的"); } }

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

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

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类 。

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会自动删除,所以我们要把它写入到一个对应的文件中 ,代码如下):

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:

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

package proxy;

import java.lang.reflect.Method;

public interface MyInvocationHandler {
public Object invoke(Object proxy,Method method,Object args)
throws Throwable;
}

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

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

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、创建一个测试:

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老师,老师讲的很好,我学了很多。

springmvc 动态代理 JDK实现与模拟JDK纯手写实现。的更多相关文章

  1. Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM)

    class文件简介及加载 Java编译器编译好Java文件之后,产生.class 文件在磁盘中.这种class文件是二进制文件,内容是只有JVM虚拟机能够识别的机器码.JVM虚拟机读取字节码文件,取出 ...

  2. Java 动态代理机制详解(JDK 和CGLIB,Javassist,ASM)

    class文件简介及加载 Java编译器编译好Java文件之后,产生.class 文件在磁盘中.这种class文件是二进制文件,内容是只有JVM虚拟机能够识别的机器码.JVM虚拟机读取字节码文件,取出 ...

  3. 设计模式7---Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM)

    class文件简介及加载 Java编译器编译好Java文件之后,产生.class 文件在磁盘中.这种class文件是二进制文件,内容是只有JVM虚拟机能够识别的机器码.JVM虚拟机读取字节码文件,取出 ...

  4. JVM插码之四:Java动态代理机制的对比(JDK 和CGLIB,Javassist,ASM)

    一.class文件简介及加载 Java编译器编译好Java文件之后,产生.class 文件在磁盘中.这种class文件是二进制文件,内容是只有JVM虚拟机能够识别的机器码.JVM虚拟机读取字节码文件, ...

  5. 动态代理学习(二)JDK动态代理源码分析

    上篇文章我们学习了如何自己实现一个动态代理,这篇文章我们从源码角度来分析下JDK的动态代理 先看一个Demo: public class MyInvocationHandler implements ...

  6. Java动态代理(三)——模拟AOP实现

    以下案例模拟AOP实现 目录结构 接口PersonService package com.ljq.service; public interface PersonService { public vo ...

  7. 纯手写SpringMVC到SpringBoot框架项目实战

    引言 Spring Boot其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置. 通过这种方式,springboot ...

  8. 纯手写SpringMVC架构,用注解实现springmvc过程

    1.第一步,首先搭建如下架构,其中,annotation中放置自己编写的注解,主要包括service controller qualifier RequestMapping 第二步:完成对应的anno ...

  9. 纯手写SpringMVC框架,用注解实现springmvc过程

    闲话不多说,直接上代码! 1.第一步,首先搭建如下架构,其中,annotation中放置自己编写的注解,主要包括service controller qualifier RequestMapping ...

随机推荐

  1. @Html.Partial和@Html.Action区别

    1.首先看一下它们的对等关系 @Html.Partial 对应 @{Html.RenderPartial();}@Html.Action 对应 @{Html.RenderAction();} 以上相互 ...

  2. 终端下vim无法输入问题解决

    最近回归vim时发现会偶尔出现vim无法输入,但光标在动的情况,一度怀疑是spf13的问题,后来经搜索,才发现是因为vim下,快捷键 Ctrl+s 的功能是停止输入,在IDE下编程时间长了,都有潜意识 ...

  3. oracle 11g crs检测结果

    +ASM1@testdb11a /oracle/media/grid$ ./runcluvfy.sh stage -pre crsinst -n testdb11a,testdb11b -verbos ...

  4. RHCS 6.5 由于resource-agents-3.9.2-40.el6版本过低导致rgmanager[61164]: [fs] umount failed - REBOOTING问题的解决

    問題描述: RHEL 6.5版本RHCS在disable或者relocate service的時候,會導致節點重啟,查看日誌顯示umount掛载點失敗,日誌如下: Nov 29 16:03:50 ph ...

  5. ubuntu wifi连接不上或经常断网,重启就好

    问题1.知道wifi密码,驱动也有,可以点击连接,总是提示"连接断开,您现在处于离线状态". 1.打开终端"ctrl+alt+T" 2.输入: sudo vim ...

  6. js中替换返回json中的空格为 

    使用.replace(/\s/g, ' ');来替换空格.在IE中 不起作用,可以指定编码将字体设置为:{font-family: Simsun;}

  7. 使用代理和block写一个alertView

    代理: MyAlertView.h: @property (nonatomic,assign)id delegate; @protocol MyAlertViewDelegate <NSObje ...

  8. BZOJ 2115 [Wc2011] Xor ——线性基

    [题目分析] 显然,一个路径走过两边是不需要计算的,所以我么找到一条1-n的路径,然后向该异或值不断异或简单环即可. 但是找出所有简单环是相当复杂的,我们只需要dfs一遍,找出所有的环路即可,因为所有 ...

  9. C# 的EF框架怎么连接Oracle数据库

    安装odp.net ODP.NET你不需要安装Oracle,不需要配置oracle.key文件,不需要配置TnsNames.Ora文件 不需要配置环境变量:完全的傻瓜式的在没有安装oracle数据库或 ...

  10. Sharepoint+Office Infopath+快速搭建问卷调查系统

    项目背景 要开发供公司内部使用的N多个在线调查问卷,要求信息在统一的平台上方便跟踪及管理. 公司内部上了Sharepoint系统及大家习惯了使用infopath及Quick app for share ...