Skip to content

Commit d9d811a

Browse files
committed
Add Stage 5 Lesson 1
1 parent e5404cc commit d9d811a

File tree

11 files changed

+650
-0
lines changed

11 files changed

+650
-0
lines changed

「一入 Java 深似海 」/代码/segmentfault/deep-in-java/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
<module>stage-2</module>
1515
<module>stage-3</module>
1616
<module>stage-4</module>
17+
<module>stage-5</module>
1718
</modules>
1819

1920
<build>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<parent>
6+
<artifactId>deep-in-java</artifactId>
7+
<groupId>com.segmentfault</groupId>
8+
<version>1.0-SNAPSHOT</version>
9+
</parent>
10+
<modelVersion>4.0.0</modelVersion>
11+
12+
<artifactId>stage-5</artifactId>
13+
<packaging>pom</packaging>
14+
<name>「一入 Java 深似海 」系列 :: 第五期</name>
15+
<modules>
16+
<module>stage-5-lesson-1</module>
17+
</modules>
18+
19+
</project>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<parent>
6+
<artifactId>stage-5</artifactId>
7+
<groupId>com.segmentfault</groupId>
8+
<version>1.0-SNAPSHOT</version>
9+
</parent>
10+
<modelVersion>4.0.0</modelVersion>
11+
12+
<artifactId>stage-5-lesson-1</artifactId>
13+
<name>「一入 Java 深似海 」系列 :: 第五期 :: 第一节</name>
14+
15+
<dependencies>
16+
17+
<!-- Apache Commons IO 类库 -->
18+
<dependency>
19+
<groupId>commons-io</groupId>
20+
<artifactId>commons-io</artifactId>
21+
<version>2.6</version>
22+
</dependency>
23+
24+
</dependencies>
25+
26+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.segmentfault.deep.in.java;
2+
3+
/**
4+
* Class 与 ClassLoader 之间的关系
5+
*/
6+
public class ClassAndClassLoaderDemo {
7+
8+
public static void main(String[] args) {
9+
10+
// 获取加载 Object.class 的 ClassLoader
11+
// Object 是被 Bootstrap ClassLoader 加载,其 Java 表现形式为 null
12+
getClassLoader(Object.class);
13+
// 获取加载原生类型 int 的 ClassLoader
14+
// int.class 是被 Bootstrap ClassLoader 加载,其 Java 表现形式为 null
15+
getClassLoader(int.class);
16+
17+
// 当前 ClassAndClassLoaderDemo?
18+
getClassLoader(ClassAndClassLoaderDemo.class);
19+
// 加载 ClassAndClassLoaderDemo.class 的 ClassLoader
20+
// 是否与系统 ClassLoader 相同
21+
System.out.println(ClassAndClassLoaderDemo.class.getClassLoader()
22+
== ClassLoader.getSystemClassLoader());
23+
24+
}
25+
26+
private static void getClassLoader(Class klass) {
27+
System.out.printf("当前类[%s] 被 %s ClassLoader 加载\n", klass,
28+
klass.getClassLoader());
29+
}
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.segmentfault.deep.in.java;
2+
3+
/**
4+
* ClassLoader 与 ClassPath 之间的关系示例代码
5+
*/
6+
public class ClassLoaderAndClassPathDemo {
7+
8+
9+
public static void main(String[] args) {
10+
// 通常,在 JVM 进程中添加 -verbose:class 参数来显示加载的 Class
11+
// 所在的位置(source),如:
12+
// [0.397s][info][class,load] com.segmentfault.deep.in.java.ClassLoaderAndClassPathDemo source: file:/E:/workspace/github/mercyblitz/segmentfault-lessons/%e3%80%8c%e4%b8%80%e5%85%a5%20Java%20%e6%b7%b1%e4%bc%bc%e6%b5%b7%20%e3%80%8d/%e4%bb%a3%e7%a0%81/segmentfault/deep-in-java/stage-5/stage-5-lesson-1/target/classes/
13+
// Bootstrap ClassLoader 加载的 Class 将会抛出 java.lang.NullPointerException
14+
// getClassLocation(Object.class);
15+
// getClassLocation(int.class);
16+
// 类资源与 URL 有关联,是否意味着 ClassLoader 与 URL 存在关联
17+
getClassLocation(ClassLoaderAndClassPathDemo.class);
18+
// Spring Boot spring-boot-loader
19+
// 文件目录:Expose -> File Handler
20+
// 文件:JAR、WAR、EAR Jar Handler
21+
// URL 抽象 Java 资源管理
22+
23+
24+
}
25+
26+
private static void getClassLocation(Class<?> klass) {
27+
System.out.printf("类[%s] 资源所在的位置:%s\n", klass,
28+
klass.getProtectionDomain().getCodeSource().getLocation());
29+
}
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package com.segmentfault.deep.in.java;
2+
3+
import java.util.ServiceLoader;
4+
5+
/**
6+
* ClassLoader 示例代码
7+
*/
8+
public class ClassLoaderDemo {
9+
10+
public static void main(String[] args) {
11+
// 系统 ClassLoader
12+
// Java 8 结果:sun.misc.Launcher$AppClassLoader@18b4aac2
13+
// Java 12 结果:jdk.internal.loader.ClassLoaders$AppClassLoader@3fee733d
14+
System.out.println(ClassLoader.getSystemClassLoader()); // 只读
15+
// 应用 ClassLoader
16+
// Java 8 结果:sun.misc.Launcher$AppClassLoader@18b4aac2
17+
// Java 12 结果:jdk.internal.loader.ClassLoaders$AppClassLoader@3fee733d
18+
System.out.println(Thread.currentThread().getContextClassLoader()); // 可修改
19+
20+
// 如何实现类隔离,通过修改 Thread 上下文 ClassLoader
21+
22+
23+
// ClassLoader previousClassLoader = Thread.currentThread().getContextLoader();
24+
// previousClassLoader 能够加载 User.class V1 版本(user-api-1.0.0.jar 文件中,在 /classpath1 目录下)
25+
// User.class V2 版本 (user-api-2.0.0.jar 文件中,在 /classpath2 目录下)
26+
// loadUser 操作加载 User.class V2 版本
27+
28+
// previousClassLoader ClassPath -> /classpath1
29+
// newClassLoader ClassPath -> /classpath2
30+
31+
// 通常,系统或者应用(包括自定义) ClassLoader 均为 URLClassLoader 子类
32+
}
33+
34+
private static void changeClassLoader(ClassLoader newClassLoader) {
35+
Thread currentThread = Thread.currentThread();
36+
// 当前 ClassLoader 无法加载 User.class 类,不过该类能被 newClassLoader 加载
37+
ClassLoader previousClassLoader = currentThread.getContextClassLoader();
38+
try {
39+
currentThread.setContextClassLoader(newClassLoader); // 需要 setContextClassLoader 安全权限
40+
// 利用新的 ClassLoader 来加载类
41+
} catch (SecurityException e) {
42+
43+
} finally {
44+
currentThread.setContextClassLoader(previousClassLoader);
45+
}
46+
}
47+
48+
private static void loadUser() { // 兼容或适配老的 ClassLoader 代码
49+
// JAXB 通过线程上下文 ClassLoader 切换不同实现 SPI
50+
// JAXB 1.x 2.x
51+
// JDK 提供的 API 1.x
52+
// 第三方包实现 2.x
53+
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
54+
try {
55+
classLoader.loadClass("User"); // 使用 V2
56+
} catch (ClassNotFoundException e) {
57+
e.printStackTrace();
58+
}
59+
}
60+
}
61+
62+
//class User { // V1
63+
//
64+
//}
65+
66+
// Class User { // V2
67+
// }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package com.segmentfault.deep.in.java;
2+
3+
import org.apache.commons.io.FileUtils;
4+
5+
import java.io.File;
6+
import java.io.IOException;
7+
import java.util.stream.Stream;
8+
9+
/**
10+
* 类加载过程
11+
*/
12+
public class ClassLoadingDemo {
13+
14+
public static void main(String[] args) throws ClassNotFoundException {
15+
16+
// 当前 main 线程 ClassLoader
17+
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
18+
// 加载某个 Class 对象
19+
// User user = ... -> load class
20+
21+
// 当前工程相对路径:stage-5/stage-5-lesson-1
22+
// 当前工程绝对路径:${user.dir}/stage-5/stage-5-lesson-1
23+
// 当前工程ClassPath :${user.dir}/stage-5/stage-5-lesson-1/target/classes
24+
// User 类全名:com.segmentfault.deep.in.java.User
25+
// User.class 文件路径:${ClassPath}/com/segmentfault/deep/in/java/User.class
26+
27+
String className = "com.segmentfault.deep.in.java.User";
28+
// com/segmentfault/deep/in/java/User.class
29+
String classFileName = className.replace('.', '/').concat(".class");
30+
String classPath = System.getProperty("user.dir") + "/stage-5/stage-5-lesson-1/target/classes";
31+
// User.class 类文件的绝对路径
32+
File classFile = new File(classPath, classFileName);
33+
34+
// ClassLoader 也是对象,也会被 GC 管理
35+
MyClassLoader myClassLoader = new MyClassLoader();
36+
// .class 文件变为字节流 byte[],再定义 Class 对象
37+
Class<?> userClass = myClassLoader.defineClass(className, classFile);
38+
39+
System.out.println("当前类对象:" + userClass);
40+
Stream.of(userClass.getDeclaredFields())
41+
.forEach(field -> {
42+
System.out.println("当前字段信息:" + field);
43+
});
44+
45+
Class<?> userClassFromThreadContextClassLoader = classLoader.loadClass(className);
46+
// User.class 被 MyClassLoader 加载后,是否与线程上下文加载的 User.class 对象是否一致?
47+
// 这个现象能够解释 Spring spring-boot-devtools 模块 Class!=Class 问题
48+
System.out.println("userClass == userClassFromThreadContextClassLoader ? "
49+
+ (userClass == userClassFromThreadContextClassLoader));
50+
51+
// 重新替换掉线程上下文 ClassLoader
52+
// myClassLoader -> Thread.currentThread().getContextClassLoader()
53+
Thread.currentThread().setContextClassLoader(myClassLoader);
54+
// 老的线程上下文 ClassLoader 是 MyClassLoader 的 parent,由于双亲委派,及时是 MyClassLoader 重新调用
55+
// loadClass(String) 方法,也不会重新加载
56+
Class<?> userClassFromMyClassLoader = classLoader.loadClass(className);
57+
System.out.println("userClass == userClassFromMyClassLoader ? " +
58+
(userClass == userClassFromMyClassLoader));
59+
60+
// 已加载 Class 是如何实现,目标方法: java.lang.ClassLoader.findLoadedClass0
61+
System.out.println(
62+
"userClassFromThreadContextClassLoader == userClassFromMyClassLoader ? " +
63+
(userClassFromThreadContextClassLoader == userClassFromMyClassLoader));
64+
}
65+
66+
static class MyClassLoader extends ClassLoader {
67+
68+
public MyClassLoader() {
69+
// 当前线程上下文 ClassLoader 作为 Parent
70+
super(Thread.currentThread().getContextClassLoader());
71+
}
72+
73+
// 文件 -> 定义某个 Class
74+
public Class<?> defineClass(String name, File classFile) {
75+
// File classFile -> byte[]
76+
byte[] bytes = loadBytes(classFile);
77+
// 利用 ClassLoader defineClass 方法来定义 Class
78+
// 可用于动态加载
79+
return super.defineClass(name, bytes, 0, bytes.length);
80+
81+
}
82+
83+
private byte[] loadBytes(File classFile) {
84+
byte[] bytes = null;
85+
try {
86+
bytes = FileUtils.readFileToByteArray(classFile);
87+
} catch (IOException e) {
88+
throw new RuntimeException(e);
89+
}
90+
return bytes;
91+
}
92+
}
93+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.segmentfault.deep.in.java;
2+
3+
/**
4+
* 类对象示例代码
5+
*/
6+
public class ClassObjectDemo {
7+
8+
public static void main(String[] args) {
9+
10+
// ClassLoader 在加载类过程(验证)中,去重操作
11+
// 验证:运行时校验 .class 文件(已经编译结果)
12+
// .class 文件版版本 Java 5 泛型,JVM 版本过低版本不兼容
13+
// 处理:参考《深入 Java 虚拟机》第二版
14+
// 双亲委派(类加载以及类存储)
15+
Class<?> objectClass = Object.class;
16+
17+
// ClassLoader
18+
19+
// 原生类型也有类对象
20+
Class<?> intClass = int.class;
21+
22+
isPrimitive(objectClass);
23+
isPrimitive(intClass);
24+
25+
// Object.class 和 int.class 均被 Bootstrap ClassLoader
26+
// Bootstrap ClassLoader 在 Java 9 之前,就是 rt.jar
27+
// 除 Bootstrap ClassLoader 之外,System ClassLoader, Application ClassLoader
28+
}
29+
30+
private static void isPrimitive(Class klass) {
31+
System.out.printf("类[%s] 是否属于原生类型:%s\n", klass.getName(), klass.isPrimitive());
32+
}
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.segmentfault.deep.in.java;
2+
3+
/**
4+
* V1 版本拥有 ID 字段
5+
*/
6+
public class User {
7+
8+
private long id;
9+
10+
public long getId() {
11+
return id;
12+
}
13+
14+
public void setId(long id) {
15+
this.id = id;
16+
}
17+
}

0 commit comments

Comments
 (0)