透过字节码分析Java动态代理机制。
一、创建动态代理代码
1、创建接口
public interface Subject {
void request();
}
2、创建接口实现类
public class RealSubject implements Subject
{
@Override
public void request() {
System.out.println("From real subject");
}
}
3、创建DynamicSubject类
public class DynamicSubject implements InvocationHandler { private Object sub; public DynamicSubject(Object obj){
this.sub = obj;
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before calling:" + method);
method.invoke(this.sub, args);
System.out.println("after calling:" + method);
return null;
}
}
4、创建测试类
public class Client {
public static void main(String[] args) { System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true"); RealSubject rs = new RealSubject();
InvocationHandler ds = new DynamicSubject(rs); Class<?> cls = rs.getClass();
Subject subject = (Subject) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), ds);
subject.request(); System.out.println(subject.getClass());
System.out.println(subject.getClass().getSuperclass());
}
}
输出结果:
before calling:public abstract void com.example.jvm.bytecode.Subject.request()
From real subject
after calling:public abstract void com.example.jvm.bytecode.Subject.request()
class com.sun.proxy.$Proxy0
class java.lang.reflect.Proxy
查看源码,动态代理类在ProxyGenerator类的generateProxyClass生成。
public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
final byte[] var4 = var3.generateClassFile();
if(saveGeneratedFiles) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
try {
int var1 = var0.lastIndexOf(46);
Path var2;
if(var1 > 0) {
Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar), new String[0]);
Files.createDirectories(var3, new FileAttribute[0]);
var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
} else {
var2 = Paths.get(var0 + ".class", new String[0]);
} Files.write(var2, var4, new OpenOption[0]);
return null;
} catch (IOException var4x) {
throw new InternalError("I/O exception saving generated file: " + var4x);
}
}
});
} return var4;
}
可以发现saveGeneratedFiles为true时,可以将代理类保存到磁盘上。
因此在测试类中sun.misc.ProxyGenerator.saveGeneratedFiles属性设置为true
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true"); 最终生成的.class 文件位置如下图
打开$Proxy0.class
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
// package com.sun.proxy; import com.example.jvm.bytecode.Subject;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException; public final class $Proxy0 extends Proxy implements Subject {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0; public $Proxy0(InvocationHandler var1) throws {
super(var1);
} public final boolean equals(Object var1) throws {
try {
return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
} public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
} public final void request() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
} public final int hashCode() throws {
try {
return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
} 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[0]);
m3 = Class.forName("com.example.jvm.bytecode.Subject").getMethod("request", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
透过字节码分析Java动态代理机制。的更多相关文章
- 透过字节码分析java基本类型数组的内存分配方式。
我们知道java中new方式创建的对象都是在堆中创建的,而局部变量对应的值存放在栈上.那么java中的int [] arr={1,2,3}是存放在什么地方的呢,int []arr = new int[ ...
- Java 动态代理机制分析及扩展
Java 动态代理机制分析及扩展,第 1 部分 王 忠平, 软件工程师, IBM 何 平, 软件工程师, IBM 简介: 本文通过分析 Java 动态代理的机制和特点,解读动态代理类的源代码,并且模拟 ...
- [转]Java 动态代理机制分析及扩展
引言 Java 动态代理机制的出现,使得 Java 开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类.代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执 ...
- Java 动态代理机制分析及扩展--转
http://www.ibm.com/developerworks/cn/java/j-lo-proxy1/#icomments http://www.ibm.com/developerworks/c ...
- Java 动态代理机制分析及扩展,第 1 部分
Java 动态代理机制分析及扩展,第 1 部分 http://www.ibm.com/developerworks/cn/java/j-lo-proxy1/ 本文通过分析 Java 动态代理的机制和特 ...
- 详解java动态代理机制以及使用场景
详解java动态代理机制以及使用场景 https://blog.csdn.net/u011784767/article/details/78281384 深入理解java动态代理的实现机制 https ...
- 大厂高级工程师面试必问系列:Java动态代理机制和实现原理详解
代理模式 Java动态代理运用了设计模式中常用的代理模式 代理模式: 目的就是为其他对象提供一个代理用来控制对某个真实对象的访问 代理类的作用: 为委托类预处理消息 过滤消息并转发消息 进行消息被委托 ...
- Java 动态代理机制详解
在学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,依赖注入就不用多说了,而对于Spring的核心AOP来说,我们不但要知道怎么通过AOP来满足的 ...
- java动态代理机制
首先了解代理设计模式,其思想是为其他对象提供一种代理以控制对这个对象的访问. java动态代理就是遵循这种思想,spring中的AOP实现原理就是java的动态代理. 在java的动态代理机制中,有两 ...
随机推荐
- JavaScript基础,Cookies,Sessions
php和JavaScript,掌握JavaScript基础,自定义函数,流程控制语句,事件,调用JavaScript脚本,在PHP中使用JavaScript. JavaScript是网景公司开发的,是 ...
- 用js刷剑指offer(数组中的逆序对)
题目描述 题目描述 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数P.并将P对1000000007取模的结果输出. 即输出P ...
- server端和前端的区别
1.服务稳定性 server端可能会遭受各种恶意攻击和误操作 单个客户端可以意外挂掉,但是服务端不能 node中用pm2做进程守候,一旦挂掉,自己会重启 2.考虑内存和cpu(优化,扩展) 客户端独占 ...
- c# 定时关闭 MessageBox 或弹出的模态窗口
我们都知道,MessageBox弹出的窗口是模式窗口,模式窗口会自动阻塞父线程的.所以如果有以下代码: MessageBox.Show("内容',"标题"); 则只有关闭 ...
- 使用jqprint插件实现打印页面内容
业务场景 客户需要在页面有一个打印按钮,点击之后可以打印Echarts图表的内容以及文字提示信息,经谷歌搜索发现,实现方法大概有三种之多,其他两种不太熟悉,而采用的这种打印方式是一个在jQuery的基 ...
- [GCP] Goolge compute Engine
Which of the following is a PAAS option for hosting web apps on GCP? App Engine standard or flexible ...
- mybatis之关联关系映射
Mybatis关联关系映射 1.一对多 首先先用逆向生成工具生成t_hibernate_order.t_hibernate_order_item 这两张表对应的model与mapper OrderVo ...
- NTSTATUS
一.NTSTATUS 直译就是NT状态,也就是内核状态.主要是内核开发/驱动开发用到的API返回的状态.许多内核模式的标准驱动程序例程和驱动程序支持例程使用ntstatus类型作为返回值.此外,当完成 ...
- logo的一般做法
<body> <!-- h1里面嵌套a,并且有网站名,方便seo --> <h1> <a href="#">小米官网</a&g ...
- 【概率论】5-8:Beta分布(The Beta Distributions)
title: [概率论]5-8:Beta分布(The Beta Distributions) categories: - Mathematic - Probability keywords: - Th ...