spring-boot4-skill 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +144 -0
- package/bin/create-spring-app.js +48 -0
- package/lib/generator.js +188 -0
- package/lib/prompts.js +115 -0
- package/lib/templates.js +45 -0
- package/package.json +44 -0
- package/skills/java-spring-framework/SKILL.md +56 -0
- package/skills/java-spring-framework/references/build-templates.md +304 -0
- package/skills/java-spring-framework/references/spring-boot-4.md +347 -0
- package/skills/java-spring-framework/references/spring-framework-7.md +314 -0
- package/skills/java-spring-framework/references/spring-modulith.md +220 -0
- package/skills-lock.json +20 -0
- package/templates/gradle-kotlin/build.gradle.kts.template +113 -0
- package/templates/gradle-kotlin/compose.yaml.template +40 -0
- package/templates/gradle-kotlin/settings.gradle.kts.template +1 -0
- package/templates/gradle-kotlin/src/main/java/com/example/app/Application.java.template +19 -0
- package/templates/gradle-kotlin/src/main/resources/application.yaml.template +60 -0
- package/templates/gradle-kotlin/src/test/java/com/example/app/ApplicationTests.java.template +17 -0
- package/templates/maven/pom.xml.template +159 -0
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
# Build Templates — Spring Boot 4 / Spring Framework 7 (2026)
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
1. [Gradle KTS — Full Application Template](#1-gradle-kts--full-application-template)
|
|
7
|
+
2. [Maven POM — Full Application Template](#2-maven-pom--full-application-template)
|
|
8
|
+
3. [Key BOM Versions (2026)](#3-key-bom-versions-2026)
|
|
9
|
+
4. [Spring Initializr CLI Quick Start](#4-spring-initializr-cli-quick-start)
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 1. Gradle KTS — Full Application Template
|
|
14
|
+
|
|
15
|
+
```kotlin
|
|
16
|
+
// build.gradle.kts
|
|
17
|
+
import org.springframework.boot.gradle.tasks.bundling.BootJar
|
|
18
|
+
|
|
19
|
+
plugins {
|
|
20
|
+
java
|
|
21
|
+
id("org.springframework.boot") version "4.0.3"
|
|
22
|
+
id("io.spring.dependency-management") version "1.1.7"
|
|
23
|
+
id("org.graalvm.buildtools.native") version "0.10.4" // optional: native image
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
group = "com.example"
|
|
27
|
+
version = "0.0.1-SNAPSHOT"
|
|
28
|
+
|
|
29
|
+
java {
|
|
30
|
+
toolchain {
|
|
31
|
+
languageVersion = JavaLanguageVersion.of(25)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Enable preview features (Structured Concurrency, Scoped Values GA in Java 25)
|
|
36
|
+
tasks.withType<JavaCompile> {
|
|
37
|
+
options.compilerArgs.addAll(listOf("--enable-preview"))
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
tasks.withType<Test> {
|
|
41
|
+
jvmArgs("--enable-preview")
|
|
42
|
+
useJUnitPlatform()
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
tasks.named<BootJar>("bootJar") {
|
|
46
|
+
jvmArguments.addAll(listOf("--enable-preview"))
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
repositories {
|
|
50
|
+
mavenCentral()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
dependencyManagement {
|
|
54
|
+
imports {
|
|
55
|
+
mavenBom("org.springframework.modulith:spring-modulith-bom:2.0.3")
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
dependencies {
|
|
60
|
+
// --- Web ---
|
|
61
|
+
implementation("org.springframework.boot:spring-boot-starter-web")
|
|
62
|
+
// implementation("org.springframework.boot:spring-boot-starter-webflux") // reactive
|
|
63
|
+
|
|
64
|
+
// --- Data ---
|
|
65
|
+
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
|
|
66
|
+
implementation("org.springframework.boot:spring-boot-starter-jdbc")
|
|
67
|
+
runtimeOnly("org.postgresql:postgresql")
|
|
68
|
+
// runtimeOnly("com.h2database:h2") // dev/test
|
|
69
|
+
|
|
70
|
+
// --- Validation ---
|
|
71
|
+
implementation("org.springframework.boot:spring-boot-starter-validation")
|
|
72
|
+
|
|
73
|
+
// --- Security ---
|
|
74
|
+
implementation("org.springframework.boot:spring-boot-starter-security")
|
|
75
|
+
implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server")
|
|
76
|
+
|
|
77
|
+
// --- Observability ---
|
|
78
|
+
implementation("org.springframework.boot:spring-boot-starter-actuator")
|
|
79
|
+
implementation("io.micrometer:micrometer-tracing-bridge-otel")
|
|
80
|
+
implementation("io.opentelemetry:opentelemetry-exporter-otlp")
|
|
81
|
+
runtimeOnly("io.micrometer:micrometer-registry-prometheus")
|
|
82
|
+
|
|
83
|
+
// --- Null Safety ---
|
|
84
|
+
implementation("org.jspecify:jspecify:1.0.0")
|
|
85
|
+
|
|
86
|
+
// --- Spring Modulith (optional) ---
|
|
87
|
+
implementation("org.springframework.modulith:spring-modulith-starter-core")
|
|
88
|
+
implementation("org.springframework.modulith:spring-modulith-starter-jpa")
|
|
89
|
+
|
|
90
|
+
// --- Dev Tools ---
|
|
91
|
+
developmentOnly("org.springframework.boot:spring-boot-devtools")
|
|
92
|
+
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
|
|
93
|
+
|
|
94
|
+
// --- Testing ---
|
|
95
|
+
testImplementation("org.springframework.boot:spring-boot-starter-test")
|
|
96
|
+
testImplementation("org.springframework.security:spring-security-test")
|
|
97
|
+
testImplementation("org.springframework.modulith:spring-modulith-starter-test")
|
|
98
|
+
testImplementation("org.testcontainers:postgresql")
|
|
99
|
+
testImplementation("org.testcontainers:junit-jupiter")
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## 2. Maven POM — Full Application Template
|
|
106
|
+
|
|
107
|
+
```xml
|
|
108
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
109
|
+
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
|
110
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
111
|
+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
|
|
112
|
+
https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
113
|
+
<modelVersion>4.0.0</modelVersion>
|
|
114
|
+
|
|
115
|
+
<parent>
|
|
116
|
+
<groupId>org.springframework.boot</groupId>
|
|
117
|
+
<artifactId>spring-boot-starter-parent</artifactId>
|
|
118
|
+
<version>4.0.3</version>
|
|
119
|
+
<relativePath/>
|
|
120
|
+
</parent>
|
|
121
|
+
|
|
122
|
+
<groupId>com.example</groupId>
|
|
123
|
+
<artifactId>my-app</artifactId>
|
|
124
|
+
<version>0.0.1-SNAPSHOT</version>
|
|
125
|
+
<packaging>jar</packaging>
|
|
126
|
+
|
|
127
|
+
<properties>
|
|
128
|
+
<java.version>25</java.version>
|
|
129
|
+
<spring-modulith.version>2.0.3</spring-modulith.version>
|
|
130
|
+
<jspecify.version>1.0.0</jspecify.version>
|
|
131
|
+
</properties>
|
|
132
|
+
|
|
133
|
+
<dependencyManagement>
|
|
134
|
+
<dependencies>
|
|
135
|
+
<dependency>
|
|
136
|
+
<groupId>org.springframework.modulith</groupId>
|
|
137
|
+
<artifactId>spring-modulith-bom</artifactId>
|
|
138
|
+
<version>${spring-modulith.version}</version>
|
|
139
|
+
<scope>import</scope>
|
|
140
|
+
<type>pom</type>
|
|
141
|
+
</dependency>
|
|
142
|
+
</dependencies>
|
|
143
|
+
</dependencyManagement>
|
|
144
|
+
|
|
145
|
+
<dependencies>
|
|
146
|
+
<!-- Web -->
|
|
147
|
+
<dependency>
|
|
148
|
+
<groupId>org.springframework.boot</groupId>
|
|
149
|
+
<artifactId>spring-boot-starter-web</artifactId>
|
|
150
|
+
</dependency>
|
|
151
|
+
|
|
152
|
+
<!-- Data -->
|
|
153
|
+
<dependency>
|
|
154
|
+
<groupId>org.springframework.boot</groupId>
|
|
155
|
+
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
|
156
|
+
</dependency>
|
|
157
|
+
<dependency>
|
|
158
|
+
<groupId>org.postgresql</groupId>
|
|
159
|
+
<artifactId>postgresql</artifactId>
|
|
160
|
+
<scope>runtime</scope>
|
|
161
|
+
</dependency>
|
|
162
|
+
|
|
163
|
+
<!-- Validation -->
|
|
164
|
+
<dependency>
|
|
165
|
+
<groupId>org.springframework.boot</groupId>
|
|
166
|
+
<artifactId>spring-boot-starter-validation</artifactId>
|
|
167
|
+
</dependency>
|
|
168
|
+
|
|
169
|
+
<!-- Security -->
|
|
170
|
+
<dependency>
|
|
171
|
+
<groupId>org.springframework.boot</groupId>
|
|
172
|
+
<artifactId>spring-boot-starter-security</artifactId>
|
|
173
|
+
</dependency>
|
|
174
|
+
<dependency>
|
|
175
|
+
<groupId>org.springframework.boot</groupId>
|
|
176
|
+
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
|
|
177
|
+
</dependency>
|
|
178
|
+
|
|
179
|
+
<!-- Observability -->
|
|
180
|
+
<dependency>
|
|
181
|
+
<groupId>org.springframework.boot</groupId>
|
|
182
|
+
<artifactId>spring-boot-starter-actuator</artifactId>
|
|
183
|
+
</dependency>
|
|
184
|
+
<dependency>
|
|
185
|
+
<groupId>io.micrometer</groupId>
|
|
186
|
+
<artifactId>micrometer-tracing-bridge-otel</artifactId>
|
|
187
|
+
</dependency>
|
|
188
|
+
<dependency>
|
|
189
|
+
<groupId>io.opentelemetry</groupId>
|
|
190
|
+
<artifactId>opentelemetry-exporter-otlp</artifactId>
|
|
191
|
+
</dependency>
|
|
192
|
+
|
|
193
|
+
<!-- Null Safety -->
|
|
194
|
+
<dependency>
|
|
195
|
+
<groupId>org.jspecify</groupId>
|
|
196
|
+
<artifactId>jspecify</artifactId>
|
|
197
|
+
<version>${jspecify.version}</version>
|
|
198
|
+
</dependency>
|
|
199
|
+
|
|
200
|
+
<!-- Spring Modulith -->
|
|
201
|
+
<dependency>
|
|
202
|
+
<groupId>org.springframework.modulith</groupId>
|
|
203
|
+
<artifactId>spring-modulith-starter-core</artifactId>
|
|
204
|
+
</dependency>
|
|
205
|
+
|
|
206
|
+
<!-- Testing -->
|
|
207
|
+
<dependency>
|
|
208
|
+
<groupId>org.springframework.boot</groupId>
|
|
209
|
+
<artifactId>spring-boot-starter-test</artifactId>
|
|
210
|
+
<scope>test</scope>
|
|
211
|
+
</dependency>
|
|
212
|
+
<dependency>
|
|
213
|
+
<groupId>org.springframework.modulith</groupId>
|
|
214
|
+
<artifactId>spring-modulith-starter-test</artifactId>
|
|
215
|
+
<scope>test</scope>
|
|
216
|
+
</dependency>
|
|
217
|
+
<dependency>
|
|
218
|
+
<groupId>org.testcontainers</groupId>
|
|
219
|
+
<artifactId>postgresql</artifactId>
|
|
220
|
+
<scope>test</scope>
|
|
221
|
+
</dependency>
|
|
222
|
+
</dependencies>
|
|
223
|
+
|
|
224
|
+
<build>
|
|
225
|
+
<plugins>
|
|
226
|
+
<plugin>
|
|
227
|
+
<groupId>org.springframework.boot</groupId>
|
|
228
|
+
<artifactId>spring-boot-maven-plugin</artifactId>
|
|
229
|
+
</plugin>
|
|
230
|
+
<plugin>
|
|
231
|
+
<groupId>org.apache.maven.plugins</groupId>
|
|
232
|
+
<artifactId>maven-compiler-plugin</artifactId>
|
|
233
|
+
<configuration>
|
|
234
|
+
<compilerArgs>
|
|
235
|
+
<arg>--enable-preview</arg>
|
|
236
|
+
</compilerArgs>
|
|
237
|
+
</configuration>
|
|
238
|
+
</plugin>
|
|
239
|
+
</plugins>
|
|
240
|
+
</build>
|
|
241
|
+
|
|
242
|
+
<!-- GraalVM Native Image (optional) -->
|
|
243
|
+
<profiles>
|
|
244
|
+
<profile>
|
|
245
|
+
<id>native</id>
|
|
246
|
+
<build>
|
|
247
|
+
<plugins>
|
|
248
|
+
<plugin>
|
|
249
|
+
<groupId>org.graalvm.buildtools</groupId>
|
|
250
|
+
<artifactId>native-maven-plugin</artifactId>
|
|
251
|
+
</plugin>
|
|
252
|
+
</plugins>
|
|
253
|
+
</build>
|
|
254
|
+
</profile>
|
|
255
|
+
</profiles>
|
|
256
|
+
</project>
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## 3. Key BOM Versions (2026)
|
|
262
|
+
|
|
263
|
+
| Library | Version |
|
|
264
|
+
|---|---|
|
|
265
|
+
| Spring Boot | 4.0.3 |
|
|
266
|
+
| Spring Framework | 7.0.5 |
|
|
267
|
+
| Spring Modulith | 2.0.3 |
|
|
268
|
+
| Spring Security | 7.x (managed by Boot) |
|
|
269
|
+
| Spring Data | 4.x (managed by Boot) |
|
|
270
|
+
| Hibernate ORM | 7.0 |
|
|
271
|
+
| JSpecify | 1.0.0 |
|
|
272
|
+
| Jackson | 3.x |
|
|
273
|
+
| GraalVM Build Tools | 0.10.4 |
|
|
274
|
+
| Testcontainers | 1.21.x |
|
|
275
|
+
| JUnit 5 | 5.12.x |
|
|
276
|
+
| Micrometer | 1.15.x |
|
|
277
|
+
| io.spring.dependency-management | 1.1.7 |
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
## 4. Spring Initializr CLI Quick Start
|
|
282
|
+
|
|
283
|
+
```bash
|
|
284
|
+
# Using Spring CLI (spring init)
|
|
285
|
+
spring init \
|
|
286
|
+
--boot-version=4.0.3 \
|
|
287
|
+
--java-version=25 \
|
|
288
|
+
--build=gradle-project-kotlin \
|
|
289
|
+
--dependencies=web,data-jpa,postgresql,security,actuator,validation,devtools \
|
|
290
|
+
--group-id=com.example \
|
|
291
|
+
--artifact-id=my-service \
|
|
292
|
+
--name=MyService \
|
|
293
|
+
my-service
|
|
294
|
+
|
|
295
|
+
# Or via curl to start.spring.io
|
|
296
|
+
curl https://start.spring.io/starter.tgz \
|
|
297
|
+
-d type=gradle-project-kotlin \
|
|
298
|
+
-d bootVersion=4.0.3 \
|
|
299
|
+
-d javaVersion=25 \
|
|
300
|
+
-d dependencies=web,data-jpa,postgresql,security,actuator,validation \
|
|
301
|
+
-d groupId=com.example \
|
|
302
|
+
-d artifactId=my-service \
|
|
303
|
+
| tar -xzvf -
|
|
304
|
+
```
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
# Spring Boot 4.0.x — Feature Reference
|
|
2
|
+
|
|
3
|
+
**Version**: 4.0.3 (Stable) | **Framework**: Spring 7.0.x | **Java baseline**: 17 (25 recommended)
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
1. [Platform Requirements](#1-platform-requirements)
|
|
9
|
+
2. [Auto-Configuration Changes](#2-auto-configuration-changes)
|
|
10
|
+
3. [Testing — @SpringBootTest & Slices](#3-testing--springboottest--slices)
|
|
11
|
+
4. [Actuator & Observability](#4-actuator--observability)
|
|
12
|
+
5. [GraalVM Native Image](#5-graalvm-native-image)
|
|
13
|
+
6. [Virtual Threads (Project Loom)](#6-virtual-threads-project-loom)
|
|
14
|
+
7. [Structured Concurrency (Java 25)](#7-structured-concurrency-java-25)
|
|
15
|
+
8. [Scoped Values (Java 25)](#8-scoped-values-java-25)
|
|
16
|
+
9. [Docker Compose Support](#9-docker-compose-support)
|
|
17
|
+
10. [Spring Security 7 Basics](#10-spring-security-7-basics)
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 1. Platform Requirements
|
|
22
|
+
|
|
23
|
+
| Component | Version |
|
|
24
|
+
|---|---|
|
|
25
|
+
| Java (minimum) | 17 |
|
|
26
|
+
| Java (recommended) | 25 |
|
|
27
|
+
| GraalVM | 24+ |
|
|
28
|
+
| Spring Framework | 7.0.x |
|
|
29
|
+
| Jakarta EE | 11 |
|
|
30
|
+
| Servlet | 6.1 |
|
|
31
|
+
| JPA (Hibernate ORM) | 3.2 / 7.0 |
|
|
32
|
+
| Bean Validation | 3.1 |
|
|
33
|
+
| Jackson | 3.x |
|
|
34
|
+
| Kotlin | 2.2 |
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## 2. Auto-Configuration Changes
|
|
39
|
+
|
|
40
|
+
### Functional Bean Registration (Native-Friendly)
|
|
41
|
+
|
|
42
|
+
Avoid `@ComponentScan` when targeting GraalVM. Use functional registration in `ApplicationContext` initialization:
|
|
43
|
+
|
|
44
|
+
```java
|
|
45
|
+
@SpringBootApplication(proxyBeanMethods = false)
|
|
46
|
+
public class Application {
|
|
47
|
+
|
|
48
|
+
public static void main(String[] args) {
|
|
49
|
+
new SpringApplicationBuilder(Application.class)
|
|
50
|
+
.initializers(ctx -> {
|
|
51
|
+
ctx.registerBean(UserService.class, UserServiceImpl::new);
|
|
52
|
+
ctx.registerBean(UserRepository.class, UserRepositoryImpl::new);
|
|
53
|
+
})
|
|
54
|
+
.run(args);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Condition-Based Auto-Configuration
|
|
60
|
+
|
|
61
|
+
```java
|
|
62
|
+
@AutoConfiguration
|
|
63
|
+
@ConditionalOnClass(DataSource.class)
|
|
64
|
+
@ConditionalOnMissingBean(JdbcClient.class)
|
|
65
|
+
public class JdbcClientAutoConfiguration {
|
|
66
|
+
|
|
67
|
+
@Bean
|
|
68
|
+
JdbcClient jdbcClient(DataSource dataSource) {
|
|
69
|
+
return JdbcClient.create(dataSource);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## 3. Testing — @SpringBootTest & Slices
|
|
77
|
+
|
|
78
|
+
### Full Context Test
|
|
79
|
+
|
|
80
|
+
```java
|
|
81
|
+
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
|
82
|
+
class ApplicationIntegrationTest {
|
|
83
|
+
|
|
84
|
+
@Autowired RestTestClient client;
|
|
85
|
+
|
|
86
|
+
@Test
|
|
87
|
+
void healthEndpointIsUp() {
|
|
88
|
+
client.get().uri("/actuator/health")
|
|
89
|
+
.exchange().expectStatus().isOk();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Web Layer Slice
|
|
95
|
+
|
|
96
|
+
```java
|
|
97
|
+
@WebMvcTest(ProductController.class)
|
|
98
|
+
class ProductControllerTest {
|
|
99
|
+
|
|
100
|
+
@Autowired MockMvc mvc;
|
|
101
|
+
@MockitoBean ProductService productService;
|
|
102
|
+
|
|
103
|
+
@Test
|
|
104
|
+
void shouldReturn200() throws Exception {
|
|
105
|
+
given(productService.findAll()).willReturn(List.of(new Product(1L, "Widget")));
|
|
106
|
+
mvc.perform(get("/api/products"))
|
|
107
|
+
.andExpect(status().isOk())
|
|
108
|
+
.andExpect(jsonPath("$[0].name").value("Widget"));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Data Layer Slice
|
|
114
|
+
|
|
115
|
+
```java
|
|
116
|
+
@DataJpaTest
|
|
117
|
+
class UserRepositoryTest {
|
|
118
|
+
|
|
119
|
+
@Autowired UserRepository repository;
|
|
120
|
+
|
|
121
|
+
@Test
|
|
122
|
+
void shouldPersistUser() {
|
|
123
|
+
User saved = repository.save(new User("Alice", "alice@example.com"));
|
|
124
|
+
assertThat(saved.id()).isNotNull();
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## 4. Actuator & Observability
|
|
132
|
+
|
|
133
|
+
Spring Boot 4 ships first-class **Micrometer Tracing + OpenTelemetry** support.
|
|
134
|
+
|
|
135
|
+
```yaml
|
|
136
|
+
# application.yaml
|
|
137
|
+
management:
|
|
138
|
+
endpoints:
|
|
139
|
+
web:
|
|
140
|
+
exposure:
|
|
141
|
+
include: health,info,metrics,prometheus,traces
|
|
142
|
+
tracing:
|
|
143
|
+
sampling:
|
|
144
|
+
probability: 1.0
|
|
145
|
+
otlp:
|
|
146
|
+
metrics:
|
|
147
|
+
export:
|
|
148
|
+
url: http://otel-collector:4318/v1/metrics
|
|
149
|
+
tracing:
|
|
150
|
+
endpoint: http://otel-collector:4318/v1/traces
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
```kotlin
|
|
154
|
+
// build.gradle.kts
|
|
155
|
+
implementation("io.micrometer:micrometer-tracing-bridge-otel")
|
|
156
|
+
implementation("io.opentelemetry:opentelemetry-exporter-otlp")
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Custom span:
|
|
160
|
+
|
|
161
|
+
```java
|
|
162
|
+
@Service
|
|
163
|
+
public class OrderService {
|
|
164
|
+
|
|
165
|
+
private final Tracer tracer;
|
|
166
|
+
|
|
167
|
+
@Observed(name = "order.process", contextualName = "Processing order")
|
|
168
|
+
public Order process(OrderRequest request) {
|
|
169
|
+
Span span = tracer.nextSpan().name("validate").start();
|
|
170
|
+
try (Tracer.SpanInScope ws = tracer.withSpan(span)) {
|
|
171
|
+
validate(request);
|
|
172
|
+
} finally {
|
|
173
|
+
span.end();
|
|
174
|
+
}
|
|
175
|
+
return persist(request);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## 5. GraalVM Native Image
|
|
183
|
+
|
|
184
|
+
```kotlin
|
|
185
|
+
// build.gradle.kts
|
|
186
|
+
plugins {
|
|
187
|
+
id("org.graalvm.buildtools.native") version "0.10.4"
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
graalvmNative {
|
|
191
|
+
binaries {
|
|
192
|
+
named("main") {
|
|
193
|
+
imageName.set("app")
|
|
194
|
+
buildArgs.add("--enable-preview")
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Build native image:
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
./gradlew nativeCompile
|
|
204
|
+
./build/native/nativeCompile/app
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
**AOT hints** when reflection is unavoidable:
|
|
208
|
+
|
|
209
|
+
```java
|
|
210
|
+
@RegisterReflectionForBinding(MyDto.class)
|
|
211
|
+
@Configuration(proxyBeanMethods = false)
|
|
212
|
+
public class NativeHintsConfig {}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## 6. Virtual Threads (Project Loom)
|
|
218
|
+
|
|
219
|
+
Enable via single property — no code changes needed for existing Spring MVC apps:
|
|
220
|
+
|
|
221
|
+
```yaml
|
|
222
|
+
# application.yaml
|
|
223
|
+
spring:
|
|
224
|
+
threads:
|
|
225
|
+
virtual:
|
|
226
|
+
enabled: true
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Programmatic usage:
|
|
230
|
+
|
|
231
|
+
```java
|
|
232
|
+
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
|
|
233
|
+
executor.submit(() -> callExternalService());
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## 7. Structured Concurrency (Java 25)
|
|
240
|
+
|
|
241
|
+
Use `StructuredTaskScope` for fan-out patterns with lifecycle guarantees.
|
|
242
|
+
|
|
243
|
+
```java
|
|
244
|
+
import java.util.concurrent.StructuredTaskScope;
|
|
245
|
+
|
|
246
|
+
@Service
|
|
247
|
+
public class DashboardService {
|
|
248
|
+
|
|
249
|
+
public Dashboard loadDashboard(String userId) throws Exception {
|
|
250
|
+
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
|
|
251
|
+
|
|
252
|
+
var orders = scope.fork(() -> orderService.findByUser(userId));
|
|
253
|
+
var profile = scope.fork(() -> profileService.find(userId));
|
|
254
|
+
var payments = scope.fork(() -> paymentService.findByUser(userId));
|
|
255
|
+
|
|
256
|
+
scope.join().throwIfFailed();
|
|
257
|
+
|
|
258
|
+
return new Dashboard(profile.get(), orders.get(), payments.get());
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## 8. Scoped Values (Java 25)
|
|
267
|
+
|
|
268
|
+
`ScopedValue` replaces `ThreadLocal` for context propagation in virtual threads.
|
|
269
|
+
|
|
270
|
+
```java
|
|
271
|
+
public final class RequestContext {
|
|
272
|
+
public static final ScopedValue<String> TENANT_ID = ScopedValue.newInstance();
|
|
273
|
+
public static final ScopedValue<User> CURRENT_USER = ScopedValue.newInstance();
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Set in a filter
|
|
277
|
+
ScopedValue.where(RequestContext.TENANT_ID, tenantId)
|
|
278
|
+
.where(RequestContext.CURRENT_USER, user)
|
|
279
|
+
.run(() -> filterChain.doFilter(request, response));
|
|
280
|
+
|
|
281
|
+
// Read anywhere in the call stack
|
|
282
|
+
String tenant = RequestContext.TENANT_ID.get();
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## 9. Docker Compose Support
|
|
288
|
+
|
|
289
|
+
Spring Boot 4 auto-detects `compose.yaml` and starts services before the application.
|
|
290
|
+
|
|
291
|
+
```yaml
|
|
292
|
+
# compose.yaml
|
|
293
|
+
services:
|
|
294
|
+
postgres:
|
|
295
|
+
image: postgres:17
|
|
296
|
+
environment:
|
|
297
|
+
POSTGRES_DB: appdb
|
|
298
|
+
POSTGRES_USER: app
|
|
299
|
+
POSTGRES_PASSWORD: secret
|
|
300
|
+
ports: ["5432:5432"]
|
|
301
|
+
redis:
|
|
302
|
+
image: redis:8
|
|
303
|
+
ports: ["6379:6379"]
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
```yaml
|
|
307
|
+
# application.yaml
|
|
308
|
+
spring:
|
|
309
|
+
docker:
|
|
310
|
+
compose:
|
|
311
|
+
enabled: true
|
|
312
|
+
lifecycle-management: start-and-stop
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
No manual connection properties needed — Boot auto-configures `DataSource` and `RedisTemplate`.
|
|
316
|
+
|
|
317
|
+
---
|
|
318
|
+
|
|
319
|
+
## 10. Spring Security 7 Basics
|
|
320
|
+
|
|
321
|
+
Lambda DSL is the only supported style in Spring Security 7.
|
|
322
|
+
|
|
323
|
+
```java
|
|
324
|
+
@Configuration
|
|
325
|
+
@EnableWebSecurity
|
|
326
|
+
public class SecurityConfig {
|
|
327
|
+
|
|
328
|
+
@Bean
|
|
329
|
+
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
|
330
|
+
return http
|
|
331
|
+
.authorizeHttpRequests(auth -> auth
|
|
332
|
+
.requestMatchers("/api/public/**").permitAll()
|
|
333
|
+
.requestMatchers("/api/admin/**").hasRole("ADMIN")
|
|
334
|
+
.anyRequest().authenticated())
|
|
335
|
+
.oauth2ResourceServer(oauth2 -> oauth2
|
|
336
|
+
.jwt(jwt -> jwt.decoder(jwtDecoder())))
|
|
337
|
+
.sessionManagement(session -> session
|
|
338
|
+
.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
|
339
|
+
.build();
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
@Bean
|
|
343
|
+
JwtDecoder jwtDecoder() {
|
|
344
|
+
return NimbusJwtDecoder.withJwkSetUri("https://auth.example.com/.well-known/jwks.json").build();
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
```
|