forked from mercyblitz/java-training-camp
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'mercyblitz:main' into main
- Loading branch information
Showing
1 changed file
with
300 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,300 @@ | ||
# 主要内容 | ||
## Java Instrument 机制 | ||
理解 Java Instrument 机制,并掌握字节码提升编程 | ||
#### Java ClassLoading | ||
##### Class Loading | ||
##### Class Definition | ||
##### Resource Loading | ||
#### Java Reflection | ||
#### Java Dynamic Proxy | ||
#### Java Bytecode | ||
#### Java Agent | ||
|
||
- JProfiler | ||
- Pinpoint | ||
- Skywalking | ||
|
||
|
||
|
||
## Web 服务链路重构 | ||
基于字节码提升工具 Spring Cloud Open Feign 以及 Spring WebMVC | ||
## 第三方服务链路重构 | ||
重构 Redis、JDBC 以及 MyBatis 服务链路实现 | ||
|
||
|
||
## | ||
|
||
# 关联技术 | ||
## Byte Buddy | ||
Byte Buddy is a code generation and manipulation library for creating and modifying Java classes during the runtime of a Java application and without the help of a compiler. | ||
## Java Instrumentation | ||
### 官方文档 | ||
[https://docs.oracle.com/javase/8/docs/technotes/guides/instrumentation/index.html](https://docs.oracle.com/javase/8/docs/technotes/guides/instrumentation/index.html) | ||
## Java Reflection | ||
在面向对象的编程模型中,提供一个中元数据的编程方法 | ||
### 官方文档 | ||
[https://docs.oracle.com/javase/8/docs/technotes/guides/reflection/index.html](https://docs.oracle.com/javase/8/docs/technotes/guides/reflection/index.html) | ||
|
||
### 元信息(Meta) | ||
Java 8 之前存放在永久代,Java 8+ 开始存放在 Metaspace(可使用 JVM 之外的内存) | ||
#### Class - 类对象 | ||
|
||
- Class 对象是由 ClassLoader 来加载(验证、加载以及存储) | ||
- ClassLoader 相当于 Class 的一个字典(Map),每个 Class 在它所加载的 ClassLoader 是一个单例 | ||
- 相同全类名的 Class 对象可能在一个 JVM 进程中存在多个,取决于多少个 ClassLoader 加载过(它)。 | ||
> Spring Boot devtools 工具的话,可能会遇到一个问题 Class A 不是 Class A | ||
- 如果需要卸载某个 Class 的话,需要 GC 掉某个 ClassLoader,比如 Java Based 某些编译工具,Groovy - ClassLoader | ||
- 成员: | ||
- 字段 - Field | ||
- 可执行成员 - Executable | ||
- 构造器 - Constructor | ||
- 方法 - Method | ||
#### Field - 字段 | ||
#### Constructor - 构造器 | ||
#### Method - 方法 | ||
|
||
- 一个 Method 属于一个 Class 对象,单个 Class 对象属于某个 ClassLoader,一个 Method 在一个 ClassLoader 仅有一个,Method 对象在 ClassLoader 是单例共享对象,可是 Java 对象至少存在一个 | ||
|
||
##### 实例代码 | ||
```java | ||
class A { | ||
|
||
@Override | ||
public String toString(){ | ||
return "A"; | ||
} | ||
|
||
private String getDescription(){ | ||
return "..."; | ||
} | ||
|
||
} | ||
|
||
public class Main { | ||
|
||
public static void main(String[] args){ | ||
|
||
Method toStringMethod = ... ; // A 类 toString() 方法,该方法是继承于 Object#toString() | ||
Method getDescriptionMethod = ... ;// | ||
// Java 反射默认不会打破 Java 面向对象封装性, | ||
// 所以当 toStringMethod 被调用时,不会报错 | ||
// 相反,getDescriptionMethod 被调用时,会报错 | ||
// Java 反射在运行时做可访问性,需要得到当前调用栈的上下文,以当前为例: | ||
// Main#main -> A#getDescription | ||
// 因此,当 getDescriptionMethod 被调用时,运行时需要获得 Caller Class, | ||
// 即 Main Class | ||
|
||
// 编译时检查 | ||
A a = new A(); | ||
a.toString(); // 编译时检查可访问性,因为该方法是 public 方法,所以编译通过 | ||
|
||
a.getDescription(); // 编译时检查可访问性,由于该方法是 private 方法,所以编译不通过 | ||
} | ||
|
||
} | ||
``` | ||
|
||
## Java ClassLoader | ||
### Java ClassLoading | ||
### Resource Loading | ||
|
||
## Java Tool API | ||
### Java Compiler | ||
Dubbo Service 自动代码生成 Swager API | ||
Dubbo Service 通过反射获取元信息 -> 生成 Java Source 内容 -> 编译成 Java Class -> 注册到 Swagger 中心 | ||
#### Java 编译过程 | ||
生成语法分析树 | ||
Java 注解处理 | ||
字节代码生成 | ||
|
||
### Java Annotation Processor(APT) | ||
#### 核心 API | ||
##### 处理器接口 - javax.annotation.processing.Processor | ||
#### 参考实现 | ||
|
||
- Dubbo dubbo-metadata-processor | ||
- Spring Framework - spring-context-indexer | ||
- Spring Boot - spring-boot-configuration-processor | ||
|
||
|
||
### Java Debugger API(JDB) | ||
|
||
## Java Tool Interface | ||
[https://docs.oracle.com/javase/8/docs/technotes/guides/jvmti/index.html](https://docs.oracle.com/javase/8/docs/technotes/guides/jvmti/index.html) | ||
|
||
## Java Runtime Code Generation | ||
### Java Dynamic Proxy | ||
#### 核心 API | ||
##### 代理工厂 API - java.lang.reflect.Proxy | ||
###### 依赖 | ||
|
||
- ClassLoader - 加载 Interfaces ,定义并加载新生成的 Java 代理类 | ||
- Interfaces - 新生成的 Java 代理类实现的接口(集合) | ||
- InvocationHandler - Interfaces 方法的调用拦截器(还需要包括 java.lang.Object) | ||
###### 核心方法 | ||
查找并且生成 Java 代理类 - java.lang.reflect.Proxy#getProxyClass0 | ||
```java | ||
private static Class<?> getProxyClass0(ClassLoader loader, | ||
Class<?>... interfaces) { | ||
if (interfaces.length > 65535) { | ||
throw new IllegalArgumentException("interface limit exceeded"); | ||
} | ||
|
||
// If the proxy class defined by the given loader implementing | ||
// the given interfaces exists, this will simply return the cached copy; | ||
// otherwise, it will create the proxy class via the ProxyClassFactory | ||
return proxyClassCache.get(loader, interfaces); | ||
} | ||
``` | ||
内部使用 API | ||
|
||
- java.lang.reflect.WeakCache | ||
- K - ClassLoader | ||
- P - Class[] 接口集合 | ||
- V - 生成代理 Class | ||
##### 代理类工厂 API - java.lang.reflect.Proxy.ProxyClassFactory | ||
|
||
- 类命名 | ||
- 固定前缀:$Proxy | ||
|
||
##### 代理类生成器 API - sun.misc.ProxyGenerator | ||
###### 配置参数 | ||
|
||
- Java System Property 保存字节生成文件 - sun.misc.ProxyGenerator.saveGeneratedFiles | ||
###### 主要方法 | ||
|
||
- 生成 Class 文件 - generateClassFile | ||
```java | ||
/* | ||
* Record that proxy methods are needed for the hashCode, equals, | ||
* and toString methods of java.lang.Object. This is done before | ||
* the methods from the proxy interfaces so that the methods from | ||
* java.lang.Object take precedence over duplicate methods in the | ||
* proxy interfaces. | ||
*/ | ||
addProxyMethod(hashCodeMethod, Object.class); | ||
addProxyMethod(equalsMethod, Object.class); | ||
addProxyMethod(toStringMethod, Object.class); | ||
|
||
/* | ||
* Now record all of the methods from the proxy interfaces, giving | ||
* earlier interfaces precedence over later ones with duplicate | ||
* methods. | ||
*/ | ||
for (Class<?> intf : interfaces) { | ||
for (Method m : intf.getMethods()) { | ||
addProxyMethod(m, intf); | ||
} | ||
} | ||
|
||
``` | ||
|
||
- 添加代理方法 - addProxyMethod | ||
```java | ||
private void addProxyMethod(Method m, Class<?> fromClass) { | ||
String name = m.getName(); | ||
Class<?>[] parameterTypes = m.getParameterTypes(); | ||
Class<?> returnType = m.getReturnType(); | ||
Class<?>[] exceptionTypes = m.getExceptionTypes(); | ||
|
||
String sig = name + getParameterDescriptors(parameterTypes); | ||
List<ProxyMethod> sigmethods = proxyMethods.get(sig); | ||
if (sigmethods != null) { | ||
for (ProxyMethod pm : sigmethods) { | ||
if (returnType == pm.returnType) { | ||
/* | ||
* Found a match: reduce exception types to the | ||
* greatest set of exceptions that can thrown | ||
* compatibly with the throws clauses of both | ||
* overridden methods. | ||
*/ | ||
List<Class<?>> legalExceptions = new ArrayList<>(); | ||
collectCompatibleTypes( | ||
exceptionTypes, pm.exceptionTypes, legalExceptions); | ||
collectCompatibleTypes( | ||
pm.exceptionTypes, exceptionTypes, legalExceptions); | ||
pm.exceptionTypes = new Class<?>[legalExceptions.size()]; | ||
pm.exceptionTypes = | ||
legalExceptions.toArray(pm.exceptionTypes); | ||
return; | ||
} | ||
} | ||
} else { | ||
sigmethods = new ArrayList<>(3); | ||
proxyMethods.put(sig, sigmethods); | ||
} | ||
sigmethods.add(new ProxyMethod(name, parameterTypes, returnType, | ||
exceptionTypes, fromClass)); | ||
} | ||
``` | ||
|
||
- 生成的实例代码 | ||
```java | ||
public final class $Proxy32 extends Proxy implements RedisConnection { | ||
|
||
private final h; // | ||
|
||
private static Method isPipelinedMethod = ... ; | ||
|
||
public $Proxy32(InvocationHandler h){ | ||
this.h = h; | ||
} | ||
|
||
public boolean isPipelined(){ | ||
this.h.invoke(this,isPipelinedMethod,new Object[0]); | ||
} | ||
//... | ||
} | ||
``` | ||
### Java 注解实现 | ||
隶属于 Java Dynamic Proxy | ||
```java | ||
public final class $Proxy6 extends Proxy implements ContextConfiguration { | ||
private static Method m1; | ||
private static Method m3; | ||
private static Method m9; | ||
private static Method m5; | ||
private static Method m7; | ||
private static Method m10; | ||
private static Method m2; | ||
private static Method m11; | ||
private static Method m8; | ||
private static Method m6; | ||
private static Method m0; | ||
private static Method m4; | ||
|
||
public $Proxy6(InvocationHandler var1) throws { | ||
super(var1); | ||
} | ||
|
||
... | ||
public final Class annotationType() throws { | ||
try { | ||
return (Class)super.h.invoke(this, m11, (Object[])null); | ||
} catch (RuntimeException | Error var2) { | ||
throw var2; | ||
} catch (Throwable var3) { | ||
throw new UndeclaredThrowableException(var3); | ||
} | ||
} | ||
... | ||
} | ||
``` | ||
### | ||
|
||
|
||
### ASM | ||
Java 字节码“汇编”,可认为字节码生成框架的“鼻祖”或“元祖” | ||
|
||
### | ||
### CGLIB | ||
### Javassist | ||
|
||
|
||
## Java 5 -> Java 6 | ||
|
||
## Java 工具 | ||
### JProfiler | ||
### JRebel | ||
|