静态代理

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

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. fastjson<=1.2.47反序列化RCE漏洞

    介绍:fastjson是一个Java语言编写的高性能功能完善的JSON库. 漏洞原因:fastjson在解析json的过程中,支持使用autoType来实例化某一个具体的类,并通过json来填充其属性 ...

  2. 基于C+OpenCV4.0的LineSegmentDetector算法实现

    简单记录LSD算法的实现过程,当做备忘录用,如有问题欢迎指出和讨论 LSD的基本实现流程是计算出图像的梯度和场方向,然后对梯度进行排序,然后从大到小进行区域增长,之后对增长得到的区域求最小外接矩形,如 ...

  3. LeetCode 1004. Max Consecutive Ones III

    原题链接在这里:https://leetcode.com/problems/max-consecutive-ones-iii/ 题目: Given an array A of 0s and 1s, w ...

  4. BeEF 获取同局域网内用户浏览器信息

    1.将kali网络适配器改为桥接模式 打开网络适配器,获取权限 修改桥接模式,进行应用 重启网卡 /etc/init.d/networking restart 查看IP地址 查看网络通不通 2.开启B ...

  5. RaiseFailFastException函数

    引发绕过所有异常处理程序(基于帧或矢量)的异常.引发此异常将终止应用程序并调用Windows错误报告(如果Windows错误报告正在运行). 原型: VOID WINAPI RaiseFailFast ...

  6. 移动端ios针对input虚拟键盘挡住的问题

    写移动端的时候发现input的虚拟键盘对Ios的手机不是很友好 我的是苹果6 点击的时候经常会挡住input框 针对这个问题找了很多发现都没效果 最后发现用下面这段js就可以解决了 $("i ...

  7. 洛谷 P3905 道路重建 题解

    P3905 道路重建 题目描述 从前,在一个王国中,在\(n\)个城市间有\(m\)条道路连接,而且任意两个城市之间至多有一条道路直接相连.在经过一次严重的战争之后,有\(d\)条道路被破坏了.国王想 ...

  8. nginx配置url重定向&反代

    一.重定向 正则表达式匹配: * ~ 为区分大小写匹配 * ~* 为不区分大小写匹配 * !~和!~*分别为区分大小写不匹配及不区分大小写不匹配 文件及目录匹配: * -f和!-f用来判断是否存在文件 ...

  9. CSS3 之loading动画实现思路

    效果大致如下: 主要实现方式: 该效果主要用到animation-timing-function中的steps()函数,该函数主要用于分步隐藏不同模块. 实现思路: 第一步动画: 第二步动画: 第三步 ...

  10. 修改elementUI源码新增组件/修改组件

    前言 经常我们会遇到elementUI组件库期间有5%达不到我们想要的需求,第一我们重新写组件,第二我们改源码 安装element https://github.com/ElemeFE/element ...