目录
一、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 {// 获取请求URIfinal 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>() {@Overridepublic Object call() throws Exception {// 业务处理Object result = task.call();return result;}});// 完成异步上下文,否则报超时等异常asyncContext.complete();return future.get();}// 完成初始化配置@Overridepublic 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() {@Overridepublic 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() {@Overridepublic void onComplete(AsyncEvent asyncEvent) throws IOException {}@Overridepublic 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();}}@Overridepublic 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();}}@Overridepublic 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.classLast modified 2023-7-22; size 4120 bytesMD5 checksum ab1d73e3259040031896505e9ed1e1bbCompiled from "OneLevelAsyncContext.java"
public class com.common.instance.demo.core.serviceLevel.OneLevelAsyncContext implements org.springframework.beans.factory.InitializingBeanminor version: 0major version: 52flags: 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: ()Vflags: ACC_PUBLICCode:stack=2, locals=1, args_size=10: aload_01: invokespecial #1 // Method java/lang/Object."<init>":()V4: aload_05: ldc #2 // String uri7: putfield #3 // Field URI:Ljava/lang/String;10: aload_011: ldc #4 // String params13: putfield #5 // Field PARAMS:Ljava/lang/String;16: returnLineNumberTable:line 23: 0line 25: 4line 26: 10LocalVariableTable:Start Length Slot Name Signature0 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_PUBLICCode:stack=5, locals=7, args_size=30: aload_11: invokeinterface #6, 1 // InterfaceMethod javax/servlet/http/HttpServletRequest.getRequestURI:()Ljava/lang/String;6: astore_37: aload_18: invokeinterface #7, 1 // InterfaceMethod javax/servlet/http/HttpServletRequest.getParameterMap:()Ljava/util/Map;13: astore 415: aload_116: invokeinterface #8, 1 // InterfaceMethod javax/servlet/http/HttpServletRequest.startAsync:()Ljavax/servlet/AsyncContext;21: astore 523: aload 525: invokeinterface #9, 1 // InterfaceMethod javax/servlet/AsyncContext.getRequest:()Ljavax/servlet/ServletRequest;30: ldc #2 // String uri32: aload_333: invokeinterface #11, 3 // InterfaceMethod javax/servlet/ServletRequest.setAttribute:(Ljava/lang/String;Ljava/lang/Object;)V38: aload 540: invokeinterface #9, 1 // InterfaceMethod javax/servlet/AsyncContext.getRequest:()Ljavax/servlet/ServletRequest;45: ldc #4 // String params47: aload 449: invokeinterface #11, 3 // InterfaceMethod javax/servlet/ServletRequest.setAttribute:(Ljava/lang/String;Ljava/lang/Object;)V54: aload 556: ldc2_w #12 // long 2000l59: invokeinterface #14, 3 // InterfaceMethod javax/servlet/AsyncContext.setTimeout:(J)V64: aload_065: getfield #15 // Field asyncListener:Ljavax/servlet/AsyncListener;68: invokestatic #16 // Method java/util/Objects.nonNull:(Ljava/lang/Object;)Z71: ifeq 8574: aload 576: aload_077: getfield #15 // Field asyncListener:Ljavax/servlet/AsyncListener;80: invokeinterface #17, 2 // InterfaceMethod javax/servlet/AsyncContext.addListener:(Ljavax/servlet/AsyncListener;)V85: aload_086: getfield #18 // Field executor:Ljava/util/concurrent/ThreadPoolExecutor;89: new #19 // class com/common/instance/demo/core/serviceLevel/OneLevelAsyncContext$192: dup93: aload_094: aload_295: invokespecial #20 // Method com/common/instance/demo/core/serviceLevel/OneLevelAsyncContext$1."<init>":(Lcom/common/instance/demo/core/serviceLevel/OneLevelAsyncContext;Ljava/util/concurrent/Callable;)V98: invokevirtual #21 // Method java/util/concurrent/ThreadPoolExecutor.submit:(Ljava/util/concurrent/Callable;)Ljava/util/concurrent/Future;101: astore 6103: aload 5105: invokeinterface #22, 1 // InterfaceMethod javax/servlet/AsyncContext.complete:()V110: aload 6112: invokeinterface #23, 1 // InterfaceMethod java/util/concurrent/Future.get:()Ljava/lang/Object;117: areturnLineNumberTable:line 34: 0line 36: 7line 39: 15line 40: 23line 41: 38line 43: 54line 44: 64line 45: 74line 49: 85line 58: 103line 59: 110LocalVariableTable:Start Length Slot Name Signature0 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 Signature0 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 = 1frame_type = 254 /* append */offset_delta = 85locals = [ class java/lang/String, class java/util/Map, class javax/servlet/AsyncContext ]Exceptions:throws java.util.concurrent.ExecutionException, java.lang.InterruptedExceptionMethodParameters:Name Flagsrequest finaltask finalSignature: #89 // (Ljavax/servlet/http/HttpServletRequest;Ljava/util/concurrent/Callable<Ljava/lang/Object;>;)Ljava/lang/Object;public void afterPropertiesSet() throws java.lang.Exception;descriptor: ()Vflags: ACC_PUBLICCode:stack=9, locals=3, args_size=10: ldc #24 // String 1002: invokestatic #25 // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I5: istore_16: ldc #26 // String 2008: invokestatic #25 // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I11: istore_212: aload_013: new #27 // class java/util/concurrent/LinkedBlockingDeque16: dup17: invokespecial #28 // Method java/util/concurrent/LinkedBlockingDeque."<init>":()V20: putfield #29 // Field queue:Ljava/util/concurrent/LinkedBlockingDeque;23: aload_024: new #30 // class java/util/concurrent/ThreadPoolExecutor27: dup28: iload_129: iload_230: ldc2_w #31 // long 100l33: getstatic #33 // Field java/util/concurrent/TimeUnit.MILLISECONDS:Ljava/util/concurrent/TimeUnit;36: aload_037: 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;)V43: putfield #18 // Field executor:Ljava/util/concurrent/ThreadPoolExecutor;46: aload_047: getfield #18 // Field executor:Ljava/util/concurrent/ThreadPoolExecutor;50: iconst_151: invokevirtual #35 // Method java/util/concurrent/ThreadPoolExecutor.allowCoreThreadTimeOut:(Z)V54: aload_055: getfield #18 // Field executor:Ljava/util/concurrent/ThreadPoolExecutor;58: new #36 // class com/common/instance/demo/core/serviceLevel/OneLevelAsyncContext$261: dup62: aload_063: invokespecial #37 // Method com/common/instance/demo/core/serviceLevel/OneLevelAsyncContext$2."<init>":(Lcom/common/instance/demo/core/serviceLevel/OneLevelAsyncContext;)V66: invokevirtual #38 // Method java/util/concurrent/ThreadPoolExecutor.setRejectedExecutionHandler:(Ljava/util/concurrent/RejectedExecutionHandler;)V69: aload_070: getfield #15 // Field asyncListener:Ljavax/servlet/AsyncListener;73: invokestatic #39 // Method java/util/Objects.isNull:(Ljava/lang/Object;)Z76: ifeq 9179: aload_080: new #40 // class com/common/instance/demo/core/serviceLevel/OneLevelAsyncContext$383: dup84: aload_085: invokespecial #41 // Method com/common/instance/demo/core/serviceLevel/OneLevelAsyncContext$3."<init>":(Lcom/common/instance/demo/core/serviceLevel/OneLevelAsyncContext;)V88: putfield #15 // Field asyncListener:Ljavax/servlet/AsyncListener;91: returnLineNumberTable:line 68: 0line 70: 6line 72: 12line 74: 23line 76: 46line 78: 54line 105: 69line 106: 79line 155: 91LocalVariableTable:Start Length Slot Name Signature0 92 0 this Lcom/common/instance/demo/core/serviceLevel/OneLevelAsyncContext;6 86 1 corePoolSize I12 80 2 maxNumPoolSize IStackMapTable: number_of_entries = 1frame_type = 253 /* append */offset_delta = 91locals = [ 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博客