0
# Archive Layout Management
1
2
Strategy-based system for determining how classes and libraries are organized within different archive types. The layout system supports JAR, WAR, and expanded directory structures with extensive customization options for different deployment scenarios.
3
4
## Capabilities
5
6
### Layout Interface
7
8
Core interface defining how archive contents are organized and accessed by the Spring Boot loader.
9
10
```java { .api }
11
public interface Layout {
12
/**
13
* Get the launcher class name for this layout.
14
* The launcher is responsible for bootstrapping the application.
15
*
16
* @return the fully qualified launcher class name
17
*/
18
String getLauncherClassName();
19
20
/**
21
* Get the location where a library should be placed within the archive.
22
*
23
* @param libraryName the name of the library
24
* @param scope the scope of the library (COMPILE, RUNTIME, etc.)
25
* @return the path within the archive where the library should be placed
26
*/
27
String getLibraryLocation(String libraryName, LibraryScope scope);
28
29
/**
30
* Get the location where application classes are stored.
31
*
32
* @return the path within the archive where classes are located
33
*/
34
String getClassesLocation();
35
36
/**
37
* Get the location of the classpath index file.
38
* Default implementation returns "BOOT-INF/classpath.idx".
39
*
40
* @return the path to the classpath index file
41
*/
42
default String getClasspathIndexFileLocation() {
43
return "BOOT-INF/classpath.idx";
44
}
45
46
/**
47
* Get the location of the layers index file.
48
* Default implementation returns "BOOT-INF/layers.idx".
49
*
50
* @return the path to the layers index file
51
*/
52
default String getLayersIndexFileLocation() {
53
return "BOOT-INF/layers.idx";
54
}
55
56
/**
57
* Determine if this layout produces executable archives.
58
*
59
* @return true if the archive can be executed directly
60
*/
61
boolean isExecutable();
62
}
63
```
64
65
### Repackaging Layout
66
67
Specialized layout interface for repackaging existing archives with different class locations.
68
69
```java { .api }
70
public interface RepackagingLayout extends Layout {
71
/**
72
* Get the location where repackaged classes should be stored.
73
* This may differ from the original classes location.
74
*
75
* @return the path for repackaged classes
76
*/
77
String getRepackagedClassesLocation();
78
}
79
```
80
81
### Custom Loader Layout
82
83
Interface for layouts that provide their own loader classes instead of using the standard Spring Boot loader.
84
85
```java { .api }
86
public interface CustomLoaderLayout {
87
/**
88
* Write custom loader classes to the archive.
89
*
90
* @param writer the writer for adding loader classes
91
* @throws IOException if writing fails
92
*/
93
void writeLoadedClasses(LoaderClassesWriter writer) throws IOException;
94
}
95
```
96
97
### Standard Layouts
98
99
Pre-defined layout implementations for common archive types.
100
101
```java { .api }
102
public final class Layouts {
103
/**
104
* Get the appropriate layout for the given file based on its extension and type.
105
*
106
* @param file the file to determine layout for
107
* @return the appropriate layout
108
*/
109
public static Layout forFile(File file);
110
111
/**
112
* Standard JAR layout for executable JAR files.
113
* Places libraries in BOOT-INF/lib/ and classes in BOOT-INF/classes/.
114
*/
115
public static class Jar implements RepackagingLayout {
116
@Override
117
public String getLauncherClassName() {
118
return "org.springframework.boot.loader.launch.JarLauncher";
119
}
120
121
@Override
122
public String getLibraryLocation(String libraryName, LibraryScope scope) {
123
return "BOOT-INF/lib/";
124
}
125
126
@Override
127
public String getClassesLocation() {
128
return "BOOT-INF/classes/";
129
}
130
131
@Override
132
public String getRepackagedClassesLocation() {
133
return "BOOT-INF/classes/";
134
}
135
136
@Override
137
public boolean isExecutable() {
138
return true;
139
}
140
}
141
142
/**
143
* Expanded JAR layout for directory-based deployment.
144
* Similar to JAR layout but optimized for exploded directory structure.
145
*/
146
public static class Expanded extends Jar {
147
@Override
148
public String getLauncherClassName() {
149
return "org.springframework.boot.loader.launch.PropertiesLauncher";
150
}
151
}
152
153
/**
154
* No-operation layout that preserves original structure.
155
* Used when no repackaging is desired.
156
*/
157
public static class None extends Jar {
158
@Override
159
public boolean isExecutable() {
160
return false;
161
}
162
}
163
164
/**
165
* WAR layout for web application archives.
166
* Places libraries in WEB-INF/lib/ and classes in WEB-INF/classes/.
167
*/
168
public static class War implements Layout {
169
@Override
170
public String getLauncherClassName() {
171
return "org.springframework.boot.loader.launch.WarLauncher";
172
}
173
174
@Override
175
public String getLibraryLocation(String libraryName, LibraryScope scope) {
176
if (scope == LibraryScope.PROVIDED) {
177
return "WEB-INF/lib-provided/";
178
}
179
return "WEB-INF/lib/";
180
}
181
182
@Override
183
public String getClassesLocation() {
184
return "WEB-INF/classes/";
185
}
186
187
@Override
188
public boolean isExecutable() {
189
return true;
190
}
191
}
192
}
193
```
194
195
### Layout Factory
196
197
Factory interface for creating layout instances based on source files.
198
199
```java { .api }
200
public interface LayoutFactory {
201
/**
202
* Create an appropriate layout for the given source file.
203
*
204
* @param source the source file to create a layout for
205
* @return the created layout
206
*/
207
Layout getLayout(File source);
208
}
209
210
public class DefaultLayoutFactory implements LayoutFactory {
211
/**
212
* Create a layout based on file extension and characteristics.
213
* - .jar files use Layouts.Jar
214
* - .war files use Layouts.War
215
* - Directories use Layouts.Expanded
216
*
217
* @param source the source file
218
* @return the appropriate layout
219
*/
220
@Override
221
public Layout getLayout(File source) {
222
// Implementation determines layout based on file type
223
}
224
}
225
```
226
227
## Usage Examples
228
229
### Basic Layout Selection
230
231
```java
232
import org.springframework.boot.loader.tools.Layout;
233
import org.springframework.boot.loader.tools.Layouts;
234
import java.io.File;
235
236
// Automatic layout selection
237
File jarFile = new File("myapp.jar");
238
Layout layout = Layouts.forFile(jarFile);
239
System.out.println("Launcher: " + layout.getLauncherClassName());
240
System.out.println("Classes location: " + layout.getClassesLocation());
241
System.out.println("Executable: " + layout.isExecutable());
242
243
// Output for JAR file:
244
// Launcher: org.springframework.boot.loader.launch.JarLauncher
245
// Classes location: BOOT-INF/classes/
246
// Executable: true
247
```
248
249
### Explicit Layout Configuration
250
251
```java
252
import org.springframework.boot.loader.tools.*;
253
import java.io.File;
254
255
// Use specific layout with repackager
256
File sourceJar = new File("myapp.jar");
257
Repackager repackager = new Repackager(sourceJar);
258
259
// Force WAR layout even for JAR file
260
Layout warLayout = new Layouts.War();
261
repackager.setLayout(warLayout);
262
263
// Libraries will be placed in WEB-INF/lib/ instead of BOOT-INF/lib/
264
repackager.repackage(Libraries.NONE);
265
```
266
267
### Custom Layout Implementation
268
269
```java
270
import org.springframework.boot.loader.tools.*;
271
272
// Create custom layout for special deployment requirements
273
public class CustomLayout implements RepackagingLayout {
274
@Override
275
public String getLauncherClassName() {
276
return "com.example.CustomLauncher";
277
}
278
279
@Override
280
public String getLibraryLocation(String libraryName, LibraryScope scope) {
281
// Separate compile and runtime dependencies
282
if (scope == LibraryScope.COMPILE) {
283
return "CUSTOM-INF/compile-lib/";
284
}
285
return "CUSTOM-INF/runtime-lib/";
286
}
287
288
@Override
289
public String getClassesLocation() {
290
return "CUSTOM-INF/app-classes/";
291
}
292
293
@Override
294
public String getRepackagedClassesLocation() {
295
return "CUSTOM-INF/app-classes/";
296
}
297
298
@Override
299
public boolean isExecutable() {
300
return true;
301
}
302
}
303
304
// Use custom layout
305
File sourceJar = new File("myapp.jar");
306
Repackager repackager = new Repackager(sourceJar);
307
repackager.setLayout(new CustomLayout());
308
repackager.repackage(Libraries.NONE);
309
```
310
311
### Layout Factory Usage
312
313
```java
314
import org.springframework.boot.loader.tools.*;
315
import java.io.File;
316
317
// Custom layout factory for special file types
318
public class CustomLayoutFactory implements LayoutFactory {
319
@Override
320
public Layout getLayout(File source) {
321
if (source.getName().endsWith(".ubar")) {
322
return new Layouts.War(); // Treat .ubar files as WAR
323
}
324
if (source.getName().contains("micro")) {
325
return new Layouts.Expanded(); // Use expanded layout for micro services
326
}
327
return Layouts.forFile(source); // Default behavior
328
}
329
}
330
331
// Configure repackager with custom factory
332
File sourceFile = new File("myapp.ubar");
333
Repackager repackager = new Repackager(sourceFile);
334
repackager.setLayoutFactory(new CustomLayoutFactory());
335
repackager.repackage(Libraries.NONE);
336
```
337
338
### Understanding Library Placement
339
340
```java
341
import org.springframework.boot.loader.tools.*;
342
import java.io.File;
343
344
// Examine how different layouts handle library placement
345
Layout jarLayout = new Layouts.Jar();
346
Layout warLayout = new Layouts.War();
347
348
String libName = "spring-core-5.3.21.jar";
349
350
// JAR layout
351
String jarLibLocation = jarLayout.getLibraryLocation(libName, LibraryScope.COMPILE);
352
System.out.println("JAR layout lib location: " + jarLibLocation);
353
// Output: BOOT-INF/lib/
354
355
// WAR layout with different scopes
356
String warCompileLocation = warLayout.getLibraryLocation(libName, LibraryScope.COMPILE);
357
String warProvidedLocation = warLayout.getLibraryLocation(libName, LibraryScope.PROVIDED);
358
System.out.println("WAR compile location: " + warCompileLocation);
359
System.out.println("WAR provided location: " + warProvidedLocation);
360
// Output: WEB-INF/lib/
361
// Output: WEB-INF/lib-provided/
362
```
363
364
### Custom Loader Layout
365
366
```java
367
import org.springframework.boot.loader.tools.*;
368
import java.io.IOException;
369
370
// Layout with custom loader classes
371
public class CustomLoaderLayout implements Layout, CustomLoaderLayout {
372
@Override
373
public String getLauncherClassName() {
374
return "com.example.CustomBootstrap";
375
}
376
377
@Override
378
public String getLibraryLocation(String libraryName, LibraryScope scope) {
379
return "META-INF/libs/";
380
}
381
382
@Override
383
public String getClassesLocation() {
384
return "META-INF/classes/";
385
}
386
387
@Override
388
public boolean isExecutable() {
389
return true;
390
}
391
392
@Override
393
public void writeLoadedClasses(LoaderClassesWriter writer) throws IOException {
394
// Write custom loader classes
395
try (var stream = getClass().getResourceAsStream("/custom-loader.jar")) {
396
writer.writeLoaderClasses("custom-loader.jar");
397
}
398
}
399
}
400
```
401
402
## Layout Decision Matrix
403
404
| File Type | Default Layout | Launcher Class | Classes Location | Libraries Location |
405
|-----------|----------------|----------------|-----------------|--------------------|
406
| .jar | Layouts.Jar | JarLauncher | BOOT-INF/classes/ | BOOT-INF/lib/ |
407
| .war | Layouts.War | WarLauncher | WEB-INF/classes/ | WEB-INF/lib/ |
408
| Directory | Layouts.Expanded | PropertiesLauncher | BOOT-INF/classes/ | BOOT-INF/lib/ |
409
| Other | Layouts.Jar | JarLauncher | BOOT-INF/classes/ | BOOT-INF/lib/ |
410
411
The layout system provides the foundation for Spring Boot's flexible packaging model, enabling different deployment strategies while maintaining consistent runtime behavior.