静态代理

编译阶段就生产了对应的代理类

public interface IBussiness {
void execute();
}
public class BussinessImpl implements IBussiness{
@Override
public void execute() {
System.out.println("执行业务逻辑...");
}
}
public class BussinessProxy implements IBussiness{

    private IBussiness bussinessImpl;

    public BussinessProxy(IBussiness bussinessImpl) {
this.bussinessImpl = bussinessImpl;
} @Override
public void execute() {
System.out.println("前拦截...");
bussinessImpl.execute();
System.out.println("后拦截...");
}
}
public class Test {

    public static void main(String[] args) {

        IBussiness bussiness = new BussinessImpl();
BussinessProxy proxy = new BussinessProxy(bussiness);
proxy.execute(); }
}

JDK动态代理

动态生成字节码,加载到内存中,利用反射去执行真正的方法

关键代码:

Proxy.newProxyInstance(ClassLoader, Interfaces, InvocationHandler);

生成代理类时,要将类加载器,接口和InvocationHandler传递过去,

类加载器的作用是,生成的字节码要加载到JVM当中

接口的作用是,生成的代理类要知道代理的有哪些方法

InvocationHandler的作用是,在代理类中实际执行的是InvocationHandler的invoke方法

public interface Person {
/**
* 唱歌
*/
void sing();
/**
* 跳舞
* @param name 舞曲名
* @return
*/
String dance(String name);
}
public class PersonImpl implements Person{

    @Override
public void sing() {
System.out.println("开始唱歌");
} @Override
public String dance(String name) {
System.out.println("跳" + name);
return "不好玩";
}
}
public class PersonImplProxy {

    private Person person = new PersonImpl();

    /**
* 创建代理
* @return 返回值是接口类型
*/
public Person createProxy() {
/**
* 产生某个对象的代理对象
* ClassLoader loader 当前代理对象的类加载器
* Class<?>[] interfaces 代理对象的接口
* InvocationHandler h InvocationHandler对象
*/
return (Person) Proxy.newProxyInstance(PersonImplProxy.class.getClassLoader(), person.getClass().getInterfaces(), new InvocationHandler() { /**
* @param proxy 把代理对象自身传进去
* @param method 代表当前调用的方法
* @param args 当前调用方法的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 获取方法名
String methodName = method.getName();
if ("sing".equals(methodName)) {
System.out.println();
System.out.println("前置通知... 唱歌开始");
method.invoke(person, args);
System.out.println("后置通知... 唱歌结束");
} else if ("dance".equals(methodName)) {
System.out.println();
System.out.println("前置通知 ... 跳舞开始");
Object res = method.invoke(person, args);
System.out.println("后置通知 ... 跳舞结束");
return res;
}
return null;
}
});
} }
public class Test {
public static void main(String[] args) {
//设置为true后,可以保存生成的代理类的字节码,
//注意字节码文件用jd-gui.exe打开,用javap打开显示不全,javap是JDK自带的工具,他们之间的具体实现是不一样的
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
PersonImplProxy proxy = new PersonImplProxy();
Person person = proxy.createProxy();
person.sing();
System.out.println(person.dance("华尔兹三章"));
System.out.println();
System.out.println("生成的代理类的名称: " + person.getClass().getName()); } }

测试结果

生成字节码文件

将字节码文件反编译后

public final class $Proxy0 extends Proxy implements Person {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m4;
private static Method m0; public $Proxy0(InvocationHandler paramInvocationHandler) {
super(paramInvocationHandler);
} public final boolean equals(Object paramObject) {
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 String toString() {
try {
return (String) this.h.invoke(this, m2, null);
} catch (Error | RuntimeException localError) {
throw localError;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
} public final void sing() {
try {
this.h.invoke(this, m3, null);
return;
} catch (Error | RuntimeException localError) {
throw localError;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
} public final String dance(String paramString) {
try {
return (String) this.h.invoke(this, m4, new Object[] { paramString });
} catch (Error | RuntimeException localError) {
throw localError;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
} public final int hashCode() {
try {
return ((Integer) this.h.invoke(this, m0, null)).intValue();
} 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") });
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[]);
m3 = Class.forName("com.irish.deligate.Person").getMethod("sing", new Class[]);
m4 = Class.forName("com.irish.deligate.Person").getMethod("dance",
new Class[] { Class.forName("java.lang.String") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[]);
return;
} catch (NoSuchMethodException localNoSuchMethodException) {
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
} catch (ClassNotFoundException localClassNotFoundException) {
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}

可以看到代理类继承了Proxy,实现了我们传递的接口,当调用dance方法时,会转调InvocationHandler的invoke方法,将方法和参数传递过去,由invoke来具体执行代理的逻辑,InvocationHandler持有真正的对象,一般是在调用真正的对象方法前后,执行我们要进行增强的操作。

java静态代理和JDK动态代理的更多相关文章

  1. java代理(静态代理和jdk动态代理以及cglib代理)

    版权声明:本文为Fighter168原创文章,未经允许不得转载.   目录(?)[+]   说到代理,脑袋中浮现一大堆代理相关的名词,代理模式,静态代理,jdk代理,cglib代理等等. 记忆特别深刻 ...

  2. 静态代理和jdk动态代理

    要说动态代理,必须先聊聊静态代理. 静态代理 假设现在项目经理有一个需求:在项目现有所有类的方法前后打印日志. 你如何在不修改已有代码的前提下,完成这个需求? 我首先想到的是静态代理.具体做法是: 1 ...

  3. AOP的底层实现-CGLIB动态代理和JDK动态代理

    AOP是目前Spring框架中的核心之一,在应用中具有非常重要的作用,也是Spring其他组件的基础.它是一种面向切面编程的思想.关于AOP的基础知识,相信多数童鞋都已经了如指掌,我们就略过这部分,来 ...

  4. Spring 静态代理+JDK动态代理和CGLIB动态代理

    代理分为两种:静态代理 动态代理 静态代理:本质上会在硬盘上创建一个真正的物理类 动态代理:本质上是在内存中构建出一个类. 如果多个类需要进行方法增强,静态代理则需要创建多个物理类,占用磁盘空间.而动 ...

  5. java的静态代理、jdk动态代理和cglib动态代理

    Java的代理就是客户端不再直接和委托类打交道,而是通过一个中间层来访问,这个中间层就是代理.使用代理有两个好处,一是可以隐藏委托类的实现:二是可以实现客户与委托类之间的解耦,在不修改委托类代码的情况 ...

  6. 代理模式之静态代理,JDK动态代理和cglib动态代理

    代理模式,顾名思义,就是通过代理去完成某些功能.比如,你需要购买火车票,不想跑那么远到火车站售票窗口买,可以去附近的火车票代售点买,或者到携程等第三方网站买.这个时候,我们就把火车站叫做目标对象或者委 ...

  7. jdk动态代理和cglib动态代理底层实现原理详细解析(cglib动态代理篇)

    代理模式是一种很常见的模式,本文主要分析cglib动态代理的过程 1. 举例 使用cglib代理需要引入两个包,maven的话包引入如下 <!-- https://mvnrepository.c ...

  8. JDK动态代理和CGLib动态代理简单演示

    JDK1.3之后,Java提供了动态代理的技术,允许开发者在运行期间创建接口的代理实例. 一.首先我们进行JDK动态代理的演示. 现在我们有一个简单的业务接口Saying,如下: package te ...

  9. 基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别。

    基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别. 我还是喜欢基于Schema风格的Spring事务管理,但也有很多人在用基于@Tras ...

随机推荐

  1. 前端知识-控制div标签的显示与隐藏

    //将附件信息列表进行隐藏 var tAppendixDiv = document.getElementById("AppendixDiv"); tAppendixDiv.styl ...

  2. AtCoder Beginner Contest 129 解题报告

    传送门 写了四个题就跑去打球了.第五题应该能肝出来的. A - Airplane #include <bits/stdc++.h> using namespace std; inline ...

  3. xrange和range的区别?

    range: 函数说明,range([start,] stop[, step]),根据start与stop指定的范围以及step设定的步长,生成一个列表. xrange:函数说明,xrange 用法与 ...

  4. inflection point

    http://blog.thefirehoseproject.com/posts/learn-to-code-and-be-self-reliant/ kill will develop 1.repe ...

  5. BZOJ 3309: DZY Loves Math 莫比乌斯反演+打表

    有一个神奇的技巧——打表 code: #include <bits/stdc++.h> #define N 10000007 #define ll long long #define se ...

  6. am335x system upgrade kernel ethernet(四)

    1      Scope of Document This document describes ethernet hardware design and porting KZS8081 to ubo ...

  7. 洛谷 SP740 TRT - Treats for the Cows 题解

    SP740 TRT - Treats for the Cows 题目描述 FJ has purchased N (1 <= N <= 2000) yummy treats for the ...

  8. 验证和交叉验证(Validation & Cross Validation)

    之前在<训练集,验证集,测试集(以及为什么要使用验证集?)(Training Set, Validation Set, Test Set)>一文中已经提过对模型进行验证(评估)的几种方式. ...

  9. gulp初体验

    项目流程 安装nodejs -> 全局安装gulp -> 项目安装gulp以及gulp插件 -> 配置gulpfile.js -> 运行任务 常用命令简介: node -v 查 ...

  10. kerberos 配置错误记录

    服务端错误记录: 1.服务端在创建数据库的时候报如下错误: # kdb5_util -s -r HADOOP.HOME 错误提示:kdb5_util: Improper format of Kerbe ...