目录
一、javac编译
1. 编译过程
2. 语法糖
二、Class文件
1. 文件格式
2. 常量池项目
3. 属性类型
三、Class文件实例
1. 源代码
2. javap分析Class文件
四、字节码指令
五、参考资料
一、javac编译
1. 编译过程
javac命令由Java语言编写,目的将Java源码转变成字节码(只完成源码到抽象语法树或字节码的生成),JDK12源码其运行入口是com.sun.tools.javac.Main#main。javac主体代码如下图所示。com.sun.tools.javac.main.JavaCompiler#compile核心方法。
javac编译过程:一个准备(初始化插入式注解处理器);三个处理(解析与填充符号表、处理注解处理器、语义分析与字节码生成),如下图所示。
需要注意的是:生成<init>()、<clinit>()方法在编译期完成;Lombok操作通过插入式注解处理器完成对字段的getter()和setter()方法。
2. 语法糖
二、Class文件
1. 文件格式
Class文件是字节为单位的二进制流,有两种数据类型:无符号数、表,如下图所示。Class文件不保存方法、字段最终的内存布局信息,JVM运行期才能找到内存入口地址。
Class文件格式如下表所示,主要有:常量池、字段表、方法表、属性表等。Class文件可以使用十六进制编辑器WinHex打开。注意:常量池(constant_pool)的数量是constant_pool_count减1,若为0说明“不引用任何常量池项目”;而其他表从0开始计数。
数据类型 | 名称 | 数量 | 作用及特点 |
u4 | magic | 1 | 1.魔数:确定文件是否是Class文件; 2.固定值:0xCAFEBABE。 |
u2 | minnor_version | 1 | 次版本号 |
u2 | major_version | 1 | 1.主版本号; 2.JDK向前兼容老版本,则不能向后兼容新版本。 |
u2 | constant_pool_count | 1 | 1.常量池容量计数数量; 2.索引从1开始,其他表从0开始; 3.若为0,则说明“不引用任何常量池项目”。 |
cp_info | constant_pool | constant_pool_count - 1 | 1.常量池,有两大类常量:字面量、符号引用; 2.有17种不同类型常量,如: CONSTANT_Utf8_info、 CONSTANT_Class_info、 CONSTANT_Fieldref_info、 CONSTANT_Methodref_info、...... |
u2 | access_flags | 1 | 1.类或接口的访问修饰符; 2.如:ACC_PUBLIC(是否为public修饰)。 |
u2 | this_class | 1 | 类索引:当前类的全限定名 |
u2 | super_class | 1 | 1.父类索引:当前类的父类的全限定名; 2.除java.lang.Object外,所有类的父类值都不为0。 |
u2 | interfaces_count | 1 | 1.接口索引的数量; 2.没有实现任何接口时,该值为0。 |
u2 | interfaces | interfaces_count | 1.接口索引:当前类的所有接口的全限定名; 2.接口从左往右的顺序在该表中。 |
u2 | fields_count | 1 | 类或接口的字段数量 |
field_info | fields | fields_count | 1.类或接口的字段(实例变量,类变量); 2.不包括:方法内局部变量; 3.内容有:修饰符、在常量池中索引、简单名称、描述符、属性表(attribute_info); 4.“描述符”:字段的数据类型、方法的参数列表及返回值; 5.不会列出父类或接口的字段; 6.可能含有JVM自动生成的字段,如:this字段。 |
u2 | methods_count | 1 | 类或接口的方法数量 |
method_info | methods | methods_count | 1.类或接口的方法(实例方法,类方法); 2.内容有:修饰符、在常量池中索引、简单名称、描述符、属性表(attribute_info的Code); 3.“描述符”:字段的数据类型、方法的参数列表及返回值; 4.不会列出父类或接口的方法(重写除外); 5.可能含有JVM自动生成的方法,如:<init>()、<cinit>()方法。 |
u2 | attributes_count | 1 | 属性表数量 |
attribute_info | attributes | attributes_count | 1.Class文件、字段、方法都有自己的属性; 2.属性只要不重名,任何编译器都可以添加自己的属性信息。 |
2. 常量池项目
常量池有两大类常量:字面量、符号引用。当类加载时,从常量池获得对应的符号引用,再在类创建或运行解析时,翻译到具体的内存地址中。如下表所示是17种不同类型的常量。
“描述符”作用是描述字段的数据类型、方法的参数列表(包括:数量、类型、顺序)、返回值。数组类型,每一个维度用前置的“[”标识,如:void inc(int[ ] ints)其描述符为([I)V。下表所示是描述符标识字符含义。
3. 属性类型
Class文件、字段、方法都有自己的属性,这些属性存储到属性表(attribute_info),《Java虚拟机规范》允许属性只要不重名,任何编译器都可以添加自己的属性信息。
如下表所示是常用属性介绍,其中整个Class文件中,只有Code属性描述方法体的代码,其他所有数据项目都是描述元数据。
常用属性 | 使用位置 | 含义 |
Code | 方法表 | 1.作用:描述方法体代码,注意:不是所有方法都有Code属性,如:接口、抽象类的方法等; 2.Code属性表中常用参数: max_stack:操作数栈的最大深度; max_locals:局部变量表的最大slot数量(不是空间大小); args_size:方法的参数数量,注意:若实例方法,则有this参数; code:方法体的字节码指令流; ..... |
LineNumberTable | Code属性 | 1.源码行号与字节码指令行的对应关系; 2.字节码指令的“行”:是相对于方法体开始的偏移量。 |
LocalVariableTable | Code属性 | 1.方法的局部变量描述; 2.注意:若实例方法,则有this参数; 3.结构中:start_pc(变量开始的字节码偏移量) + length(长度)决定变量的作用域。 |
StackMapTable | Code属性 | 1.目的:类加载时字节码验证阶段进行类型检查(新类型检查器); 2.含义:0或多个栈映射帧(代表字节码偏移量),即:执行到该字节码时局部变量表和操作数栈的验证类型。 |
ConstantValue | 字段表 | 1.常量值:为static修饰的变量赋值的值; 2.常量值只能是:基本数据类型、String。 |
Exceptions | 方法表 | 方法抛出的异常列表 |
InnerClasses | 类文件 | 内部类列表 |
Signature | 类、方法表、 字段表 | 1.记录泛型签名信息,如:类型变量、类型参数等; 2.反射API就是根据这个属性来获取泛型信息。 |
MethodParameters | 方法表 | 记录方法的各个形参和信息 |
Synthetic | 类、方法表、 字段表 | 1.标识方法或字段是编译器自动生成,至少有Synthetic或ACC_SYNTHETIC一个; 2.如:实例构造器<init>()、类构造器<cinit>(); |
其他:Deprecated(含有@Deprecated)、EnclosingMethod(含有局部类或匿名类)、 RuntimeVisibleAnnotations(运行时可见的注解,反射可调用)、SourceFile(记录源文件名称)、 RuntimeInvisibleAnnotations(运行时不可见的注解,反射不可调用)、 AnnotationDefault(含有注解类元素默认值)、Modlue(记录模块信息)、 BootstrapMethods(保存invokedynamic指令引用的引导方法限定符)、 ...... |
三、Class文件实例
1. 源代码
如下代码,用javac编译成Class文件。
package com.common.instance.demo.core.serviceLevel;
import com.alibaba.fastjson.JSON;
import com.log.util.LogUtil;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.*;
/**
* @description 一级业务线程池处理业务
* @author tcm
* @version 1.0.0
* @date 2021/9/29 16:01
**/
@Component
public class OneLevelAsyncContext implements InitializingBean {
private final String URI = "uri";
private final String PARAMS = "params";
private AsyncListener asyncListener;
private LinkedBlockingDeque<Runnable> queue;
private ThreadPoolExecutor executor;
public Object submitFuture(final HttpServletRequest request, final Callable<Object> task) throws ExecutionException, InterruptedException {
// 获取请求URI
final String uri = request.getRequestURI();
// 获取请求参数
final Map<String, String[]> params = request.getParameterMap();
// 开启异步上下文
final AsyncContext asyncContext = request.startAsync();
asyncContext.getRequest().setAttribute(URI, uri);
asyncContext.getRequest().setAttribute(PARAMS, params);
// 超时设置
asyncContext.setTimeout(2 * 1000);
if (Objects.nonNull(asyncListener)) {
asyncContext.addListener(this.asyncListener);
}
// 线程池处理业务
Future<Object> future = executor.submit(new Callable<Object>() {
@Override
public Object call() throws Exception {
// 业务处理
Object result = task.call();
return result;
}
});
// 完成异步上下文,否则报超时等异常
asyncContext.complete();
return future.get();
}
// 完成初始化配置
@Override
public void afterPropertiesSet() throws Exception {
// 线程池大小
int corePoolSize = Integer.parseInt("100");
// 最大线程池大小
int maxNumPoolSize = Integer.parseInt("200");
// 任务队列
queue = new LinkedBlockingDeque<Runnable>();
// 创建线程池
executor = new ThreadPoolExecutor(corePoolSize, maxNumPoolSize, 100, TimeUnit.MILLISECONDS, queue);
executor.allowCoreThreadTimeOut(true);
// 线程池饱和处理
executor.setRejectedExecutionHandler(new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
if (r instanceof CanceledCallable) {
CanceledCallable cc = ((CanceledCallable) r);
AsyncContext asyncContext = cc.asyncContext;
try {
ServletRequest request = asyncContext.getRequest();
String uri = (String) request.getAttribute(URI);
Map params = (Map) request.getAttribute(PARAMS);
LogUtil.error(String.format("async request %s, uri:%s, params:%s", "rejectedExecution", uri, JSON.toJSONString(params)));
} catch (Exception ex) {
}
try {
HttpServletResponse response = (HttpServletResponse) asyncContext.getResponse();
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
} finally {
asyncContext.complete();
}
}
}
});
// 创建监听器
if (Objects.isNull(asyncListener)) {
asyncListener = new AsyncListener() {
@Override
public void onComplete(AsyncEvent asyncEvent) throws IOException {
}
@Override
public void onTimeout(AsyncEvent asyncEvent) throws IOException {
AsyncContext asyncContext = asyncEvent.getAsyncContext();
try {
ServletRequest request = asyncContext.getRequest();
String uri = (String) request.getAttribute(URI);
Map params = (Map) request.getAttribute(PARAMS);
LogUtil.error(String.format("async request timeout, uri:%s, params:%s", uri, JSON.toJSONString(params)));
} catch (Exception e) {}
try {
HttpServletResponse resp = (HttpServletResponse) asyncContext.getResponse();
resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
} finally {
asyncContext.complete();
}
}
@Override
public void onError(AsyncEvent asyncEvent) throws IOException {
AsyncContext asyncContext = asyncEvent.getAsyncContext();
try {
ServletRequest request = asyncContext.getRequest();
String uri = (String) request.getAttribute(URI);
Map params = (Map) request.getAttribute(PARAMS);
LogUtil.error(String.format("async request error, uri:%s, params:%s", uri, JSON.toJSONString(params)));
} catch (Exception e) {}
try {
HttpServletResponse resp = (HttpServletResponse) asyncContext.getResponse();
resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
} finally {
asyncContext.complete();
}
}
@Override
public void onStartAsync(AsyncEvent asyncEvent) throws IOException {
}
};
}
}
}
2. javap分析Class文件
javap命令分析Class文件,如:javap -verbose OneLevelAsyncContext.class,代码所示。
Classfile /E:/Idea Project/instance-demo/target/classes/com/common/instance/demo/core/serviceLevel/OneLevelAsyncContext.class
Last modified 2023-7-22; size 4120 bytes
MD5 checksum ab1d73e3259040031896505e9ed1e1bb
Compiled from "OneLevelAsyncContext.java"
public class com.common.instance.demo.core.serviceLevel.OneLevelAsyncContext implements org.springframework.beans.factory.InitializingBean
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #42.#99 // java/lang/Object."<init>":()V
#2 = String #70 // uri
#3 = Fieldref #10.#100 // com/common/instance/demo/core/serviceLevel/OneLevelAsyncContext.URI:Ljava/lang/String;
#4 = String #71 // params
#5 = Fieldref #10.#101 // com/common/instance/demo/core/serviceLevel/OneLevelAsyncContext.PARAMS:Ljava/lang/String;
#6 = InterfaceMethodref #102.#103 // javax/servlet/http/HttpServletRequest.getRequestURI:()Ljava/lang/String;
#7 = InterfaceMethodref #102.#104 // javax/servlet/http/HttpServletRequest.getParameterMap:()Ljava/util/Map;
#8 = InterfaceMethodref #102.#105 // javax/servlet/http/HttpServletRequest.startAsync:()Ljavax/servlet/AsyncContext;
#9 = InterfaceMethodref #106.#107 // javax/servlet/AsyncContext.getRequest:()Ljavax/servlet/ServletRequest;
#10 = Class #108 // com/common/instance/demo/core/serviceLevel/OneLevelAsyncContext
#11 = InterfaceMethodref #109.#110 // javax/servlet/ServletRequest.setAttribute:(Ljava/lang/String;Ljava/lang/Object;)V
#12 = Long 2000l
#14 = InterfaceMethodref #106.#111 // javax/servlet/AsyncContext.setTimeout:(J)V
#15 = Fieldref #10.#112 // com/common/instance/demo/core/serviceLevel/OneLevelAsyncContext.asyncListener:Ljavax/servlet/AsyncListener;
#16 = Methodref #113.#114 // java/util/Objects.nonNull:(Ljava/lang/Object;)Z
#17 = InterfaceMethodref #106.#115 // javax/servlet/AsyncContext.addListener:(Ljavax/servlet/AsyncListener;)V
#18 = Fieldref #10.#116 // com/common/instance/demo/core/serviceLevel/OneLevelAsyncContext.executor:Ljava/util/concurrent/ThreadPoolExecutor;
#19 = Class #117 // com/common/instance/demo/core/serviceLevel/OneLevelAsyncContext$1
#20 = Methodref #19.#118 // com/common/instance/demo/core/serviceLevel/OneLevelAsyncContext$1."<init>":(Lcom/common/instance/demo/core/serviceLevel/OneLevelAsyncContext;Ljava/util/concurrent/Callable;)V
#21 = Methodref #30.#119 // java/util/concurrent/ThreadPoolExecutor.submit:(Ljava/util/concurrent/Callable;)Ljava/util/concurrent/Future;
#22 = InterfaceMethodref #106.#120 // javax/servlet/AsyncContext.complete:()V
#23 = InterfaceMethodref #121.#122 // java/util/concurrent/Future.get:()Ljava/lang/Object;
#24 = String #123 // 100
#25 = Methodref #124.#125 // java/lang/Integer.parseInt:(Ljava/lang/String;)I
#26 = String #126 // 200
#27 = Class #127 // java/util/concurrent/LinkedBlockingDeque
#28 = Methodref #27.#99 // java/util/concurrent/LinkedBlockingDeque."<init>":()V
#29 = Fieldref #10.#128 // com/common/instance/demo/core/serviceLevel/OneLevelAsyncContext.queue:Ljava/util/concurrent/LinkedBlockingDeque;
#30 = Class #129 // java/util/concurrent/ThreadPoolExecutor
#31 = Long 100l
#33 = Fieldref #130.#131 // java/util/concurrent/TimeUnit.MILLISECONDS:Ljava/util/concurrent/TimeUnit;
#34 = Methodref #30.#132 // java/util/concurrent/ThreadPoolExecutor."<init>":(IIJLjava/util/concurrent/TimeUnit;Ljava/util/concurrent/BlockingQueue;)V
#35 = Methodref #30.#133 // java/util/concurrent/ThreadPoolExecutor.allowCoreThreadTimeOut:(Z)V
#36 = Class #134 // com/common/instance/demo/core/serviceLevel/OneLevelAsyncContext$2
#37 = Methodref #36.#135 // com/common/instance/demo/core/serviceLevel/OneLevelAsyncContext$2."<init>":(Lcom/common/instance/demo/core/serviceLevel/OneLevelAsyncContext;)V
#38 = Methodref #30.#136 // java/util/concurrent/ThreadPoolExecutor.setRejectedExecutionHandler:(Ljava/util/concurrent/RejectedExecutionHandler;)V
#39 = Methodref #113.#137 // java/util/Objects.isNull:(Ljava/lang/Object;)Z
#40 = Class #138 // com/common/instance/demo/core/serviceLevel/OneLevelAsyncContext$3
#41 = Methodref #40.#135 // com/common/instance/demo/core/serviceLevel/OneLevelAsyncContext$3."<init>":(Lcom/common/instance/demo/core/serviceLevel/OneLevelAsyncContext;)V
#42 = Class #139 // java/lang/Object
#43 = Class #140 // org/springframework/beans/factory/InitializingBean
#44 = Utf8 InnerClasses
#45 = Utf8 URI
#46 = Utf8 Ljava/lang/String;
#47 = Utf8 ConstantValue
#48 = Utf8 PARAMS
#49 = Utf8 asyncListener
#50 = Utf8 Ljavax/servlet/AsyncListener;
#51 = Utf8 queue
#52 = Utf8 Ljava/util/concurrent/LinkedBlockingDeque;
#53 = Utf8 Signature
#54 = Utf8 Ljava/util/concurrent/LinkedBlockingDeque<Ljava/lang/Runnable;>;
#55 = Utf8 executor
#56 = Utf8 Ljava/util/concurrent/ThreadPoolExecutor;
#57 = Utf8 <init>
#58 = Utf8 ()V
#59 = Utf8 Code
#60 = Utf8 LineNumberTable
#61 = Utf8 LocalVariableTable
#62 = Utf8 this
#63 = Utf8 Lcom/common/instance/demo/core/serviceLevel/OneLevelAsyncContext;
#64 = Utf8 submitFuture
#65 = Utf8 (Ljavax/servlet/http/HttpServletRequest;Ljava/util/concurrent/Callable;)Ljava/lang/Object;
#66 = Utf8 request
#67 = Utf8 Ljavax/servlet/http/HttpServletRequest;
#68 = Utf8 task
#69 = Utf8 Ljava/util/concurrent/Callable;
#70 = Utf8 uri
#71 = Utf8 params
#72 = Utf8 Ljava/util/Map;
#73 = Utf8 asyncContext
#74 = Utf8 Ljavax/servlet/AsyncContext;
#75 = Utf8 future
#76 = Utf8 Ljava/util/concurrent/Future;
#77 = Utf8 LocalVariableTypeTable
#78 = Utf8 Ljava/util/concurrent/Callable<Ljava/lang/Object;>;
#79 = Utf8 Ljava/util/Map<Ljava/lang/String;[Ljava/lang/String;>;
#80 = Utf8 Ljava/util/concurrent/Future<Ljava/lang/Object;>;
#81 = Utf8 StackMapTable
#82 = Class #141 // java/lang/String
#83 = Class #142 // java/util/Map
#84 = Class #143 // javax/servlet/AsyncContext
#85 = Utf8 Exceptions
#86 = Class #144 // java/util/concurrent/ExecutionException
#87 = Class #145 // java/lang/InterruptedException
#88 = Utf8 MethodParameters
#89 = Utf8 (Ljavax/servlet/http/HttpServletRequest;Ljava/util/concurrent/Callable<Ljava/lang/Object;>;)Ljava/lang/Object;
#90 = Utf8 afterPropertiesSet
#91 = Utf8 corePoolSize
#92 = Utf8 I
#93 = Utf8 maxNumPoolSize
#94 = Class #146 // java/lang/Exception
#95 = Utf8 SourceFile
#96 = Utf8 OneLevelAsyncContext.java
#97 = Utf8 RuntimeVisibleAnnotations
#98 = Utf8 Lorg/springframework/stereotype/Component;
#99 = NameAndType #57:#58 // "<init>":()V
#100 = NameAndType #45:#46 // URI:Ljava/lang/String;
#101 = NameAndType #48:#46 // PARAMS:Ljava/lang/String;
#102 = Class #147 // javax/servlet/http/HttpServletRequest
#103 = NameAndType #148:#149 // getRequestURI:()Ljava/lang/String;
#104 = NameAndType #150:#151 // getParameterMap:()Ljava/util/Map;
#105 = NameAndType #152:#153 // startAsync:()Ljavax/servlet/AsyncContext;
#106 = Class #143 // javax/servlet/AsyncContext
#107 = NameAndType #154:#155 // getRequest:()Ljavax/servlet/ServletRequest;
#108 = Utf8 com/common/instance/demo/core/serviceLevel/OneLevelAsyncContext
#109 = Class #156 // javax/servlet/ServletRequest
#110 = NameAndType #157:#158 // setAttribute:(Ljava/lang/String;Ljava/lang/Object;)V
#111 = NameAndType #159:#160 // setTimeout:(J)V
#112 = NameAndType #49:#50 // asyncListener:Ljavax/servlet/AsyncListener;
#113 = Class #161 // java/util/Objects
#114 = NameAndType #162:#163 // nonNull:(Ljava/lang/Object;)Z
#115 = NameAndType #164:#165 // addListener:(Ljavax/servlet/AsyncListener;)V
#116 = NameAndType #55:#56 // executor:Ljava/util/concurrent/ThreadPoolExecutor;
#117 = Utf8 com/common/instance/demo/core/serviceLevel/OneLevelAsyncContext$1
#118 = NameAndType #57:#166 // "<init>":(Lcom/common/instance/demo/core/serviceLevel/OneLevelAsyncContext;Ljava/util/concurrent/Callable;)V
#119 = NameAndType #167:#168 // submit:(Ljava/util/concurrent/Callable;)Ljava/util/concurrent/Future;
#120 = NameAndType #169:#58 // complete:()V
#121 = Class #170 // java/util/concurrent/Future
#122 = NameAndType #171:#172 // get:()Ljava/lang/Object;
#123 = Utf8 100
#124 = Class #173 // java/lang/Integer
#125 = NameAndType #174:#175 // parseInt:(Ljava/lang/String;)I
#126 = Utf8 200
#127 = Utf8 java/util/concurrent/LinkedBlockingDeque
#128 = NameAndType #51:#52 // queue:Ljava/util/concurrent/LinkedBlockingDeque;
#129 = Utf8 java/util/concurrent/ThreadPoolExecutor
#130 = Class #176 // java/util/concurrent/TimeUnit
#131 = NameAndType #177:#178 // MILLISECONDS:Ljava/util/concurrent/TimeUnit;
#132 = NameAndType #57:#179 // "<init>":(IIJLjava/util/concurrent/TimeUnit;Ljava/util/concurrent/BlockingQueue;)V
#133 = NameAndType #180:#181 // allowCoreThreadTimeOut:(Z)V
#134 = Utf8 com/common/instance/demo/core/serviceLevel/OneLevelAsyncContext$2
#135 = NameAndType #57:#182 // "<init>":(Lcom/common/instance/demo/core/serviceLevel/OneLevelAsyncContext;)V
#136 = NameAndType #183:#184 // setRejectedExecutionHandler:(Ljava/util/concurrent/RejectedExecutionHandler;)V
#137 = NameAndType #185:#163 // isNull:(Ljava/lang/Object;)Z
#138 = Utf8 com/common/instance/demo/core/serviceLevel/OneLevelAsyncContext$3
#139 = Utf8 java/lang/Object
#140 = Utf8 org/springframework/beans/factory/InitializingBean
#141 = Utf8 java/lang/String
#142 = Utf8 java/util/Map
#143 = Utf8 javax/servlet/AsyncContext
#144 = Utf8 java/util/concurrent/ExecutionException
#145 = Utf8 java/lang/InterruptedException
#146 = Utf8 java/lang/Exception
#147 = Utf8 javax/servlet/http/HttpServletRequest
#148 = Utf8 getRequestURI
#149 = Utf8 ()Ljava/lang/String;
#150 = Utf8 getParameterMap
#151 = Utf8 ()Ljava/util/Map;
#152 = Utf8 startAsync
#153 = Utf8 ()Ljavax/servlet/AsyncContext;
#154 = Utf8 getRequest
#155 = Utf8 ()Ljavax/servlet/ServletRequest;
#156 = Utf8 javax/servlet/ServletRequest
#157 = Utf8 setAttribute
#158 = Utf8 (Ljava/lang/String;Ljava/lang/Object;)V
#159 = Utf8 setTimeout
#160 = Utf8 (J)V
#161 = Utf8 java/util/Objects
#162 = Utf8 nonNull
#163 = Utf8 (Ljava/lang/Object;)Z
#164 = Utf8 addListener
#165 = Utf8 (Ljavax/servlet/AsyncListener;)V
#166 = Utf8 (Lcom/common/instance/demo/core/serviceLevel/OneLevelAsyncContext;Ljava/util/concurrent/Callable;)V
#167 = Utf8 submit
#168 = Utf8 (Ljava/util/concurrent/Callable;)Ljava/util/concurrent/Future;
#169 = Utf8 complete
#170 = Utf8 java/util/concurrent/Future
#171 = Utf8 get
#172 = Utf8 ()Ljava/lang/Object;
#173 = Utf8 java/lang/Integer
#174 = Utf8 parseInt
#175 = Utf8 (Ljava/lang/String;)I
#176 = Utf8 java/util/concurrent/TimeUnit
#177 = Utf8 MILLISECONDS
#178 = Utf8 Ljava/util/concurrent/TimeUnit;
#179 = Utf8 (IIJLjava/util/concurrent/TimeUnit;Ljava/util/concurrent/BlockingQueue;)V
#180 = Utf8 allowCoreThreadTimeOut
#181 = Utf8 (Z)V
#182 = Utf8 (Lcom/common/instance/demo/core/serviceLevel/OneLevelAsyncContext;)V
#183 = Utf8 setRejectedExecutionHandler
#184 = Utf8 (Ljava/util/concurrent/RejectedExecutionHandler;)V
#185 = Utf8 isNull
{
public com.common.instance.demo.core.serviceLevel.OneLevelAsyncContext();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: ldc #2 // String uri
7: putfield #3 // Field URI:Ljava/lang/String;
10: aload_0
11: ldc #4 // String params
13: putfield #5 // Field PARAMS:Ljava/lang/String;
16: return
LineNumberTable:
line 23: 0
line 25: 4
line 26: 10
LocalVariableTable:
Start Length Slot Name Signature
0 17 0 this Lcom/common/instance/demo/core/serviceLevel/OneLevelAsyncContext;
public java.lang.Object submitFuture(javax.servlet.http.HttpServletRequest, java.util.concurrent.Callable<java.lang.Object>) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
descriptor: (Ljavax/servlet/http/HttpServletRequest;Ljava/util/concurrent/Callable;)Ljava/lang/Object;
flags: ACC_PUBLIC
Code:
stack=5, locals=7, args_size=3
0: aload_1
1: invokeinterface #6, 1 // InterfaceMethod javax/servlet/http/HttpServletRequest.getRequestURI:()Ljava/lang/String;
6: astore_3
7: aload_1
8: invokeinterface #7, 1 // InterfaceMethod javax/servlet/http/HttpServletRequest.getParameterMap:()Ljava/util/Map;
13: astore 4
15: aload_1
16: invokeinterface #8, 1 // InterfaceMethod javax/servlet/http/HttpServletRequest.startAsync:()Ljavax/servlet/AsyncContext;
21: astore 5
23: aload 5
25: invokeinterface #9, 1 // InterfaceMethod javax/servlet/AsyncContext.getRequest:()Ljavax/servlet/ServletRequest;
30: ldc #2 // String uri
32: aload_3
33: invokeinterface #11, 3 // InterfaceMethod javax/servlet/ServletRequest.setAttribute:(Ljava/lang/String;Ljava/lang/Object;)V
38: aload 5
40: invokeinterface #9, 1 // InterfaceMethod javax/servlet/AsyncContext.getRequest:()Ljavax/servlet/ServletRequest;
45: ldc #4 // String params
47: aload 4
49: invokeinterface #11, 3 // InterfaceMethod javax/servlet/ServletRequest.setAttribute:(Ljava/lang/String;Ljava/lang/Object;)V
54: aload 5
56: ldc2_w #12 // long 2000l
59: invokeinterface #14, 3 // InterfaceMethod javax/servlet/AsyncContext.setTimeout:(J)V
64: aload_0
65: getfield #15 // Field asyncListener:Ljavax/servlet/AsyncListener;
68: invokestatic #16 // Method java/util/Objects.nonNull:(Ljava/lang/Object;)Z
71: ifeq 85
74: aload 5
76: aload_0
77: getfield #15 // Field asyncListener:Ljavax/servlet/AsyncListener;
80: invokeinterface #17, 2 // InterfaceMethod javax/servlet/AsyncContext.addListener:(Ljavax/servlet/AsyncListener;)V
85: aload_0
86: getfield #18 // Field executor:Ljava/util/concurrent/ThreadPoolExecutor;
89: new #19 // class com/common/instance/demo/core/serviceLevel/OneLevelAsyncContext$1
92: dup
93: aload_0
94: aload_2
95: invokespecial #20 // Method com/common/instance/demo/core/serviceLevel/OneLevelAsyncContext$1."<init>":(Lcom/common/instance/demo/core/serviceLevel/OneLevelAsyncContext;Ljava/util/concurrent/Callable;)V
98: invokevirtual #21 // Method java/util/concurrent/ThreadPoolExecutor.submit:(Ljava/util/concurrent/Callable;)Ljava/util/concurrent/Future;
101: astore 6
103: aload 5
105: invokeinterface #22, 1 // InterfaceMethod javax/servlet/AsyncContext.complete:()V
110: aload 6
112: invokeinterface #23, 1 // InterfaceMethod java/util/concurrent/Future.get:()Ljava/lang/Object;
117: areturn
LineNumberTable:
line 34: 0
line 36: 7
line 39: 15
line 40: 23
line 41: 38
line 43: 54
line 44: 64
line 45: 74
line 49: 85
line 58: 103
line 59: 110
LocalVariableTable:
Start Length Slot Name Signature
0 118 0 this Lcom/common/instance/demo/core/serviceLevel/OneLevelAsyncContext;
0 118 1 request Ljavax/servlet/http/HttpServletRequest;
0 118 2 task Ljava/util/concurrent/Callable;
7 111 3 uri Ljava/lang/String;
15 103 4 params Ljava/util/Map;
23 95 5 asyncContext Ljavax/servlet/AsyncContext;
103 15 6 future Ljava/util/concurrent/Future;
LocalVariableTypeTable:
Start Length Slot Name Signature
0 118 2 task Ljava/util/concurrent/Callable<Ljava/lang/Object;>;
15 103 4 params Ljava/util/Map<Ljava/lang/String;[Ljava/lang/String;>;
103 15 6 future Ljava/util/concurrent/Future<Ljava/lang/Object;>;
StackMapTable: number_of_entries = 1
frame_type = 254 /* append */
offset_delta = 85
locals = [ class java/lang/String, class java/util/Map, class javax/servlet/AsyncContext ]
Exceptions:
throws java.util.concurrent.ExecutionException, java.lang.InterruptedException
MethodParameters:
Name Flags
request final
task final
Signature: #89 // (Ljavax/servlet/http/HttpServletRequest;Ljava/util/concurrent/Callable<Ljava/lang/Object;>;)Ljava/lang/Object;
public void afterPropertiesSet() throws java.lang.Exception;
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=9, locals=3, args_size=1
0: ldc #24 // String 100
2: invokestatic #25 // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
5: istore_1
6: ldc #26 // String 200
8: invokestatic #25 // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
11: istore_2
12: aload_0
13: new #27 // class java/util/concurrent/LinkedBlockingDeque
16: dup
17: invokespecial #28 // Method java/util/concurrent/LinkedBlockingDeque."<init>":()V
20: putfield #29 // Field queue:Ljava/util/concurrent/LinkedBlockingDeque;
23: aload_0
24: new #30 // class java/util/concurrent/ThreadPoolExecutor
27: dup
28: iload_1
29: iload_2
30: ldc2_w #31 // long 100l
33: getstatic #33 // Field java/util/concurrent/TimeUnit.MILLISECONDS:Ljava/util/concurrent/TimeUnit;
36: aload_0
37: getfield #29 // Field queue:Ljava/util/concurrent/LinkedBlockingDeque;
40: invokespecial #34 // Method java/util/concurrent/ThreadPoolExecutor."<init>":(IIJLjava/util/concurrent/TimeUnit;Ljava/util/concurrent/BlockingQueue;)V
43: putfield #18 // Field executor:Ljava/util/concurrent/ThreadPoolExecutor;
46: aload_0
47: getfield #18 // Field executor:Ljava/util/concurrent/ThreadPoolExecutor;
50: iconst_1
51: invokevirtual #35 // Method java/util/concurrent/ThreadPoolExecutor.allowCoreThreadTimeOut:(Z)V
54: aload_0
55: getfield #18 // Field executor:Ljava/util/concurrent/ThreadPoolExecutor;
58: new #36 // class com/common/instance/demo/core/serviceLevel/OneLevelAsyncContext$2
61: dup
62: aload_0
63: invokespecial #37 // Method com/common/instance/demo/core/serviceLevel/OneLevelAsyncContext$2."<init>":(Lcom/common/instance/demo/core/serviceLevel/OneLevelAsyncContext;)V
66: invokevirtual #38 // Method java/util/concurrent/ThreadPoolExecutor.setRejectedExecutionHandler:(Ljava/util/concurrent/RejectedExecutionHandler;)V
69: aload_0
70: getfield #15 // Field asyncListener:Ljavax/servlet/AsyncListener;
73: invokestatic #39 // Method java/util/Objects.isNull:(Ljava/lang/Object;)Z
76: ifeq 91
79: aload_0
80: new #40 // class com/common/instance/demo/core/serviceLevel/OneLevelAsyncContext$3
83: dup
84: aload_0
85: invokespecial #41 // Method com/common/instance/demo/core/serviceLevel/OneLevelAsyncContext$3."<init>":(Lcom/common/instance/demo/core/serviceLevel/OneLevelAsyncContext;)V
88: putfield #15 // Field asyncListener:Ljavax/servlet/AsyncListener;
91: return
LineNumberTable:
line 68: 0
line 70: 6
line 72: 12
line 74: 23
line 76: 46
line 78: 54
line 105: 69
line 106: 79
line 155: 91
LocalVariableTable:
Start Length Slot Name Signature
0 92 0 this Lcom/common/instance/demo/core/serviceLevel/OneLevelAsyncContext;
6 86 1 corePoolSize I
12 80 2 maxNumPoolSize I
StackMapTable: number_of_entries = 1
frame_type = 253 /* append */
offset_delta = 91
locals = [ int, int ]
Exceptions:
throws java.lang.Exception
}
SourceFile: "OneLevelAsyncContext.java"
RuntimeVisibleAnnotations:
0: #98()
InnerClasses:
#40; //class com/common/instance/demo/core/serviceLevel/OneLevelAsyncContext$3
#36; //class com/common/instance/demo/core/serviceLevel/OneLevelAsyncContext$2
#19; //class com/common/instance/demo/core/serviceLevel/OneLevelAsyncContext$1
四、字节码指令
Java各种语法、关键字、常量变量、符号运算的语义最终都会由多个字节码指令组合来表达。Java虚拟机字节码指令组成如下所示:操作码(Opcode)、操作数(Operand)。
Java虚拟机面向操作数栈而不是面向寄存器的架构,其总数不超过256条(单字节),指令分类如下表所示。
指令类型 | 指令作用 | 指令 |
加载和存储 | 局部表加载到操作数栈 | 1.iload、iload_<n>、aload、aload_<n>、......; 2._<n>:其中n表示局部变量表的slot索引位置。 |
操作数栈存储到局部表 | 1.istore、istore_<n>、astore、astore_<n>、......; 2._<n>:其中n表示局部变量表的slot索引位置。 | |
常量加载到操作数栈 | 1.iconst_<i>、aconst_null、bipush、sipush、ldc、......; 2.iconst_<i>表示:int型的常量<i>加载到操作数栈。 | |
扩充局部变量表的访问索引 | wide | |
运算指令 | 加法指令 | iadd、ladd、fadd、dadd |
减法指令 | isub、lsub、fsub、dsub | |
局部变量自增指令 | iinc | |
比较指令 | dcmpg、dcmpl、fcmpg、fcmpl、cmp | |
...... | imul、idev、irem、ineg、ishl、ior、iadd、ixor、...... | |
对象创建和访问 | 类实例创建 | new |
数组创建 | newarray、anewarray、multianewarray | |
访问实例字段或类字段 | getfield、putfield、getstatic、putstatic | |
数组元素加载到操作数栈 | iaload、aaload、...... | |
操作数栈存储到数组元素 | iastore、aastore、...... | |
获取数组长度 | arraylength | |
检查类实例类型 | instanceof、checkcast | |
操作数栈管理 | 栈顶一个或两个元素出栈 | pop、pop2 |
栈顶一个或两个元素复制或双份复制重新压入栈顶 | dup、dup2、dup_x1、dup2_x1、dup_x2、dup2_x2 | |
最顶端两个元素互换 | swap | |
控制转移 | 条件分支 | ifeq、iflt、ifnull、ificmplt、ifacmpeq、...... |
复合条件分支 | tableswitch、lookupswitch | |
无条件分支 | goto、goto_w、...... | |
方法调用和返回 | 调用对象实例方法 | invokevirtual(运行时实际类型进行动态分派 _ 重写) |
调用接口方法 | invokeinterface(运行时实现该接口的对象,找到合适则调用) | |
调用实例初始化、私有、父类方法 | invokespecial(实例初始化、私有、父类方法) | |
调用类静态方法 | invokestatic(static方法) | |
动态调用用户设定的方法 | invokedunamic(运行时动态解析调用点限定符所引用的方法) | |
方法返回 | 1.return(void、实例初始化、类或接口初始化方法); 2.ireturn、lreturn、freturn、dreturn、areturn (byte、short、char、boolean、int型返回使用ireturn) | |
异常处理 | 显示抛出异常 | athrow(throw语句 + 检测到异常状况自动抛出) |
同步处理 | synchronized加锁 (都是使用管程Monitor) | 1.方法的隐式加锁,即:方法访问标志ACC_SYNCHRONIZED; 2.语句块的显示加锁,即:monitorenter + monitorexit |
类型转换 | 宽化类型转换(安全转换) | JVM直接支持:i转l/f/d、l转f/d、f转d |
窄化类型转换(强制转换) | i2b、i2c、i2s、l2i、f2l、d2f、...... | |
注意: a.i代表int、l代表long、s代表short、b代表byte、c代表char、f代表float、d代表double、a代表reference型; b.JVM不直接支持byte、short、char、boolean类型的算术运算,转换为int型运算; c.算术指令对操作数栈顶的两个元素运算,运算后先移除这两个元素,后计算结果存入栈顶; d.invokevirtual、invokeinterface、invokespecial、invokestatic调用都固化在JVM内部;而invokedunamic是由用户所设定的引导方法决定的; e.方法无论正常结果还是异常结束,则每条monitorenter都必须对应monitorexit; f.算术运算时,使用NaN(Not a Number)运算,其结果都是NaN。 |
五、参考资料
jdk/jdk12: log
Java 进阶之字节码剖析_aload_0_C陈三岁的博客-CSDN博客
Class文件解析_class 详解_Aur_ora的博客-CSDN博客