0%

1.4.11

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<version>1.4.11</version>
<dependencies>
<dependency>
<groupId>com.github.jnr</groupId>
<artifactId>jnr-unixsocket</artifactId>
<version>0.38.14</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>default</id>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
<configuration>
<repository>${docker.image.prefix}/${project.artifactId}</repository>
<tag>${project.version}</tag>
<buildArgs>
<JAR_FILE>${project.build.finalName}.jar</JAR_FILE>
</buildArgs>
</configuration>
</plugin>
</plugins>
</build>

1.4.13

1
2
3
4
5
6
# socat
brew install socat
nohup socat TCP-LISTEN:2375,range=127.0.0.1/32,reuseaddr,fork UNIX-CLIENT:/var/run/docker.sock > /dev/null 2>&1 &
export DOCKER_HOST=tcp://127.0.0.1:2375
# build
mvn dockerfile:build
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<version>1.4.13</version>
<executions>
<execution>
<id>default</id>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
<configuration>
<repository>${docker.image.prefix}/${project.artifactId}</repository>
<tag>${project.version}</tag>
<buildArgs>
<JAR_FILE>${project.build.finalName}.jar</JAR_FILE>
</buildArgs>
</configuration>
</plugin>
</plugins>
</build>

csongyu/mdc-with-thread-pools

logging.pattern.console

1
logging.pattern.console=%d{yyyy-MMM-dd HH:mm:ss.SSS} %-5level [%thread] %X{traceNumber} %logger{15} - %msg%n

ThreadPoolTaskExecutor

1
2
3
4
5
6
7
8
9
10
11
12
13
final ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setTaskDecorator(runnable -> {
final Map<String, String> copyOfContextMap = MDC.getCopyOfContextMap();
return () -> {
try {
MDC.setContextMap(copyOfContextMap);
runnable.run();
} finally {
MDC.clear();
}
};
});
threadPoolTaskExecutor.initialize();

ThreadPoolExecutor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, Integer.MAX_VALUE, 60L,
TimeUnit.SECONDS, new LinkedBlockingQueue<>(Integer.MAX_VALUE)) {
@Override
public void execute(final Runnable command) {
final Map<String, String> copyOfContextMap = MDC.getCopyOfContextMap();
super.execute(() -> {
try {
MDC.setContextMap(copyOfContextMap);
command.run();
} finally {
MDC.clear();
}
});
}
};

What is CLASSPATH in Java

CLASSPATH in Java is the path to the directory or list of the directory which is used by ClassLoaders to find and load classes in the Java program.

What is CLASSPATH in SpringBoot

org.springframework.boot.loader.JarLauncher

Launcher for JAR based archives. This launcher assumes that dependency jars are included inside a /BOOT-INF/lib directory and that application classes are included inside a /BOOT-INF/classes directory.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# tar -zxvf fat.jar
# tree
.
├── BOOT-INF
│   ├── classes
│   │   ├── application.properties
│   │   └── ...
│   ├── classpath.idx
│   ├── layers.idx
│   └── lib
│   └── ...
├── META-INF
│   ├── MANIFEST.MF
│   └── ...
└── org
└── springframework
└── boot
└── loader
└── ...
1
2
3
4
5
6
7
8
9
# MANIFEST.MF
...
Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: xyz.csongyu.xxx.Application
Spring-Boot-Version: 2.7.0
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx
Spring-Boot-Layers-Index: BOOT-INF/layers.idx

Further verification in the code:

1
2
3
4
5
6
private void printClasspath() {
final ClassLoader cl = this.getClass().getClassLoader();
final String path =
Arrays.stream(((URLClassLoader)cl).getURLs()).map(URL::getPath).collect(Collectors.joining("\n"));
LOGGER.info("ClassLoader " + cl + " loading path: " + path);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
ClassLoader org.springframework.boot.loader.LaunchedURLClassLoader@724af044 loading path:
file:/private/tmp/fat.jar!/BOOT-INF/classes!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/spring-boot-2.7.0.jar!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/spring-context-5.3.20.jar!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/spring-aop-5.3.20.jar!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/spring-beans-5.3.20.jar!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/spring-expression-5.3.20.jar!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/spring-boot-autoconfigure-2.7.0.jar!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/logback-classic-1.2.11.jar!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/logback-core-1.2.11.jar!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/slf4j-api-1.7.36.jar!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/log4j-to-slf4j-2.17.2.jar!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/log4j-api-2.17.2.jar!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/jul-to-slf4j-1.7.36.jar!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/jakarta.annotation-api-1.3.5.jar!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/spring-core-5.3.20.jar!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/spring-jcl-5.3.20.jar!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/snakeyaml-1.30.jar!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/spring-boot-jarmode-layertools-2.7.0.jar!/

Use java.lang.ClassLoader#getResource() method load file

1
2
3
4
5
6
7
8
private void loadFileByClassLoader(final String path) {
final URL url = this.getClass().getClassLoader().getResource(path);
if (Objects.isNull(url)) {
LOGGER.error("ClassLoader.getResource(): can't load");
} else {
LOGGER.info("ClassLoader.getResource(): " + url.getPath());
}
}

First scenario, load file under the CLASSPATH. Place avatar_.jpeg under the src/main/resources directory, set parameter path to avatar_.jpeg.

1
2
3
4
5
.
└── BOOT-INF
   └── classes
      ├── application.properties
     └── avatar_.jpeg
1
2
3
java -jar fat.jar

ClassLoader.getResource(): file:/private/tmp/fat.jar!/BOOT-INF/classes!/avatar_.jpeg

Second scenario, load file not in the CLASSPATH. Put avatar.jpeg and fat.jar together, set parameter path to avatar.jepg, /tmp/avatar.jpeg or ../avatar.jpeg.

1
2
3
.
├── avatar.jpeg
└── fat.jar
1
2
3
java -jar fat.jar

ClassLoader.getResource(): can't load

Add extra CLASSPATH in SpringBoot

4. PropertiesLauncher Features

Third scenario, load file not in the CLASSPATH, but specify -Dloader.path. Set parameter path to avatar.jpeg.

1
2
3
java -cp fat.jar -Dloader.path=/tmp org.springframework.boot.loader.PropertiesLauncher

ClassLoader.getResource(): /tmp/avatar.jpeg

Likewise, /tmp and /tmp/fat.jar are added to the CLASSPATH.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
ClassLoader org.springframework.boot.loader.LaunchedURLClassLoader@604ed9f0 loading path:
/tmp/
/tmp/fat.jar
file:/private/tmp/fat.jar!/BOOT-INF/classes!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/spring-boot-2.7.0.jar!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/spring-context-5.3.20.jar!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/spring-aop-5.3.20.jar!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/spring-beans-5.3.20.jar!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/spring-expression-5.3.20.jar!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/spring-boot-autoconfigure-2.7.0.jar!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/logback-classic-1.2.11.jar!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/logback-core-1.2.11.jar!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/slf4j-api-1.7.36.jar!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/log4j-to-slf4j-2.17.2.jar!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/log4j-api-2.17.2.jar!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/jul-to-slf4j-1.7.36.jar!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/jakarta.annotation-api-1.3.5.jar!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/spring-core-5.3.20.jar!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/spring-jcl-5.3.20.jar!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/snakeyaml-1.30.jar!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/spring-boot-loader-2.7.0.jar!/
file:/private/tmp/fat.jar!/BOOT-INF/lib/spring-boot-jarmode-layertools-2.7.0.jar!/

Loading the file using org.springframework.util.ResourceUtils

1
2
3
4
5
6
try {
final File file = ResourceUtils.getFile("file:../avatar.jpeg");
LOGGER.info("ResourceUtils.getFile(): " + file.getCanonicalPath());
} catch (final IOException e) {
LOGGER.error("ResourceUtils.getFile(): can't load");
}