0
# Lifecycle Management
1
2
Maven Core lifecycle management provides APIs for orchestrating build lifecycles, managing execution plans, and coordinating the execution of build phases and goals. The lifecycle system is responsible for determining which plugins and goals to execute and in what order.
3
4
## Core Lifecycle Execution
5
6
### LifecycleExecutor Interface
7
8
Primary interface for lifecycle execution and planning.
9
10
```java { .api }
11
public interface LifecycleExecutor {
12
/**
13
* Calculate execution plan for specified tasks and projects.
14
*
15
* @param session Maven session containing projects and configuration
16
* @param tasks array of tasks (phases/goals) to execute
17
* @return execution plan containing ordered mojo executions
18
* @throws PluginNotFoundException if required plugin cannot be found
19
* @throws PluginResolutionException if plugin resolution fails
20
* @throws LifecyclePhaseNotFoundException if phase is not defined
21
* @throws LifecycleNotFoundException if lifecycle is not found
22
* @throws InvalidPluginDescriptorException if plugin descriptor is invalid
23
*/
24
MavenExecutionPlan calculateExecutionPlan(MavenSession session, String... tasks)
25
throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException,
26
LifecycleNotFoundException, InvalidPluginDescriptorException;
27
28
/**
29
* Calculate execution plan for specific projects.
30
*
31
* @param session Maven session
32
* @param projects list of projects to plan for
33
* @param tasks array of tasks to execute
34
* @return execution plan
35
*/
36
MavenExecutionPlan calculateExecutionPlan(MavenSession session, List<MavenProject> projects, String... tasks)
37
throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException,
38
LifecycleNotFoundException, InvalidPluginDescriptorException;
39
40
/**
41
* Execute the Maven session.
42
*
43
* @param session Maven session to execute
44
*/
45
void execute(MavenSession session);
46
47
/**
48
* Execute forked executions for a mojo.
49
*
50
* @param mojoExecution mojo execution that requires forked executions
51
* @param session Maven session
52
* @return list of projects from forked executions
53
* @throws LifecycleExecutionException if execution fails
54
*/
55
List<MavenProject> executeForkedExecutions(MojoExecution mojoExecution, MavenSession session)
56
throws LifecycleExecutionException;
57
}
58
```
59
60
**Lifecycle Execution Example:**
61
```java
62
import org.apache.maven.lifecycle.LifecycleExecutor;
63
import org.apache.maven.lifecycle.MavenExecutionPlan;
64
65
@Component
66
private LifecycleExecutor lifecycleExecutor;
67
68
public void executeLifecyclePhases(MavenSession session) throws Exception {
69
// Calculate execution plan for compile phase
70
MavenExecutionPlan plan = lifecycleExecutor.calculateExecutionPlan(
71
session, "clean", "compile", "test");
72
73
System.out.println("Execution plan contains " + plan.size() + " mojo executions:");
74
for (MojoExecution execution : plan.getMojoExecutions()) {
75
System.out.println(" " + execution.getLifecyclePhase() + ": " +
76
execution.getPlugin().getArtifactId() + ":" + execution.getGoal());
77
}
78
79
// Execute the session (this will execute the calculated plan)
80
lifecycleExecutor.execute(session);
81
}
82
83
public void analyzeExecutionPlan(MavenSession session, String... goals) throws Exception {
84
MavenExecutionPlan plan = lifecycleExecutor.calculateExecutionPlan(session, goals);
85
86
// Group executions by lifecycle phase
87
Map<String, List<MojoExecution>> executionsByPhase = new LinkedHashMap<>();
88
89
for (MojoExecution execution : plan) {
90
String phase = execution.getLifecyclePhase();
91
executionsByPhase.computeIfAbsent(phase, k -> new ArrayList<>()).add(execution);
92
}
93
94
// Display execution plan by phase
95
System.out.println("Execution Plan Analysis:");
96
for (Map.Entry<String, List<MojoExecution>> entry : executionsByPhase.entrySet()) {
97
System.out.println("Phase: " + entry.getKey());
98
for (MojoExecution execution : entry.getValue()) {
99
Plugin plugin = execution.getPlugin();
100
System.out.println(" -> " + plugin.getGroupId() + ":" +
101
plugin.getArtifactId() + ":" + execution.getGoal() +
102
" [" + execution.getExecutionId() + "]");
103
}
104
}
105
}
106
```
107
108
## Execution Plans
109
110
### MavenExecutionPlan Class
111
112
Represents an ordered sequence of mojo executions for a build.
113
114
```java { .api }
115
public class MavenExecutionPlan implements Iterable<MojoExecution> {
116
/**
117
* Get all mojo executions in the plan.
118
*
119
* @return list of mojo executions in execution order
120
*/
121
public List<MojoExecution> getMojoExecutions();
122
123
/**
124
* Get iterator over mojo executions.
125
*
126
* @return iterator for executions
127
*/
128
public Iterator<MojoExecution> iterator();
129
130
/**
131
* Get number of executions in the plan.
132
*
133
* @return number of mojo executions
134
*/
135
public int size();
136
137
/**
138
* Check if plan is empty.
139
*
140
* @return true if no executions in plan
141
*/
142
public boolean isEmpty();
143
144
/**
145
* Find mojo executions by plugin key.
146
*
147
* @param pluginKey plugin key (groupId:artifactId)
148
* @return list of matching executions
149
*/
150
public List<MojoExecution> getMojoExecutions(String pluginKey);
151
152
/**
153
* Get last mojo execution for a plugin.
154
*
155
* @param pluginKey plugin key
156
* @return last execution or null if not found
157
*/
158
public MojoExecution findLastInPhase(String pluginKey);
159
}
160
```
161
162
**Execution Plan Usage:**
163
```java
164
public void processExecutionPlan(MavenExecutionPlan plan) {
165
System.out.println("Processing execution plan with " + plan.size() + " executions");
166
167
// Iterate through all executions
168
for (MojoExecution execution : plan) {
169
Plugin plugin = execution.getPlugin();
170
System.out.println("Will execute: " + plugin.getArtifactId() +
171
":" + execution.getGoal() +
172
" in phase: " + execution.getLifecyclePhase());
173
}
174
175
// Find specific plugin executions
176
List<MojoExecution> compilerExecutions = plan.getMojoExecutions("org.apache.maven.plugins:maven-compiler-plugin");
177
if (!compilerExecutions.isEmpty()) {
178
System.out.println("Found " + compilerExecutions.size() + " compiler plugin executions:");
179
for (MojoExecution execution : compilerExecutions) {
180
System.out.println(" " + execution.getGoal() + " [" + execution.getExecutionId() + "]");
181
}
182
}
183
184
// Check for test execution
185
MojoExecution lastSurefireExecution = plan.findLastInPhase("org.apache.maven.plugins:maven-surefire-plugin");
186
if (lastSurefireExecution != null) {
187
System.out.println("Tests will be executed by: " + lastSurefireExecution.getExecutionId());
188
}
189
}
190
```
191
192
## Lifecycle Definitions
193
194
### Lifecycle Class
195
196
Represents a complete lifecycle definition with phases and default bindings.
197
198
```java { .api }
199
public class Lifecycle {
200
/**
201
* Get lifecycle identifier.
202
*
203
* @return lifecycle ID (e.g., "default", "clean", "site")
204
*/
205
public String getId();
206
207
/**
208
* Set lifecycle identifier.
209
*
210
* @param id lifecycle ID
211
*/
212
public void setId(String id);
213
214
/**
215
* Get ordered list of phases in this lifecycle.
216
*
217
* @return list of phase names in execution order
218
*/
219
public List<String> getPhases();
220
221
/**
222
* Set phases for this lifecycle.
223
*
224
* @param phases ordered list of phase names
225
*/
226
public void setPhases(List<String> phases);
227
228
/**
229
* Get default phase bindings for packaging types.
230
*
231
* @return map from packaging type to phase bindings
232
*/
233
public Map<String, LifecyclePhase> getDefaultPhases();
234
235
/**
236
* Set default phase bindings.
237
*
238
* @param defaultPhases map of packaging-specific bindings
239
*/
240
public void setDefaultPhases(Map<String, LifecyclePhase> defaultPhases);
241
242
/**
243
* Get default bindings for a specific packaging type.
244
*
245
* @param packaging packaging type (e.g., "jar", "war", "pom")
246
* @return phase bindings for the packaging type
247
*/
248
public Map<String, String> getDefaultGoals(String packaging);
249
}
250
```
251
252
### DefaultLifecycles Class
253
254
Container for standard Maven lifecycles.
255
256
```java { .api }
257
public class DefaultLifecycles {
258
/**
259
* Get all standard lifecycles.
260
*
261
* @return list of default lifecycles (default, clean, site)
262
*/
263
public List<Lifecycle> getLifeCycles();
264
265
/**
266
* Get lifecycle by ID.
267
*
268
* @param lifecycleId lifecycle identifier
269
* @return lifecycle instance or null if not found
270
*/
271
public Lifecycle get(String lifecycleId);
272
273
/**
274
* Get phases for a specific lifecycle.
275
*
276
* @param lifecycleId lifecycle identifier
277
* @return ordered list of phase names
278
*/
279
public List<String> getLifecyclePhases(String lifecycleId);
280
}
281
```
282
283
**Lifecycle Definition Example:**
284
```java
285
import org.apache.maven.lifecycle.Lifecycle;
286
import org.apache.maven.lifecycle.DefaultLifecycles;
287
288
@Component
289
private DefaultLifecycles defaultLifecycles;
290
291
public void inspectLifecycles() {
292
// Get all standard lifecycles
293
List<Lifecycle> lifecycles = defaultLifecycles.getLifeCycles();
294
295
for (Lifecycle lifecycle : lifecycles) {
296
System.out.println("Lifecycle: " + lifecycle.getId());
297
System.out.println("Phases: " + lifecycle.getPhases());
298
299
// Show default bindings for common packaging types
300
String[] packagingTypes = {"jar", "war", "pom", "maven-plugin"};
301
for (String packaging : packagingTypes) {
302
Map<String, String> bindings = lifecycle.getDefaultGoals(packaging);
303
if (!bindings.isEmpty()) {
304
System.out.println(" Default bindings for " + packaging + ":");
305
for (Map.Entry<String, String> binding : bindings.entrySet()) {
306
System.out.println(" " + binding.getKey() + " -> " + binding.getValue());
307
}
308
}
309
}
310
}
311
}
312
313
public void analyzeDefaultLifecycle() {
314
Lifecycle defaultLifecycle = defaultLifecycles.get("default");
315
if (defaultLifecycle != null) {
316
System.out.println("Default lifecycle phases:");
317
List<String> phases = defaultLifecycle.getPhases();
318
for (int i = 0; i < phases.size(); i++) {
319
System.out.println((i + 1) + ". " + phases.get(i));
320
}
321
322
// Show JAR packaging bindings
323
Map<String, String> jarBindings = defaultLifecycle.getDefaultGoals("jar");
324
System.out.println("\nDefault JAR packaging bindings:");
325
for (Map.Entry<String, String> entry : jarBindings.entrySet()) {
326
System.out.println(" " + entry.getKey() + " -> " + entry.getValue());
327
}
328
}
329
}
330
```
331
332
## Forked Executions
333
334
Forked executions allow mojos to trigger separate lifecycle executions, typically used for pre-integration testing or parallel builds.
335
336
```java { .api }
337
public interface LifecycleExecutor {
338
/**
339
* Execute forked executions for a mojo that requires them.
340
*
341
* @param mojoExecution the mojo execution requesting forked executions
342
* @param session Maven session
343
* @return list of projects resulting from forked executions
344
* @throws LifecycleExecutionException if forked execution fails
345
*/
346
List<MavenProject> executeForkedExecutions(MojoExecution mojoExecution, MavenSession session)
347
throws LifecycleExecutionException;
348
}
349
```
350
351
**Forked Execution Example:**
352
```java
353
public void handleForkedExecution(MojoExecution mojoExecution, MavenSession session) throws Exception {
354
// Check if mojo has forked executions defined
355
MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
356
357
if (mojoDescriptor.getExecutePhase() != null || mojoDescriptor.getExecuteGoal() != null) {
358
System.out.println("Mojo " + mojoExecution.getGoal() + " requires forked execution");
359
360
// Execute forked executions
361
List<MavenProject> forkedProjects = lifecycleExecutor.executeForkedExecutions(
362
mojoExecution, session);
363
364
System.out.println("Forked execution completed for " + forkedProjects.size() + " projects:");
365
for (MavenProject project : forkedProjects) {
366
System.out.println(" " + project.getGroupId() + ":" + project.getArtifactId());
367
}
368
}
369
}
370
371
// Example: Integration test with forked lifecycle
372
public void runIntegrationTestsWithForking(MavenSession session) throws Exception {
373
// Find failsafe plugin execution (commonly uses forked executions)
374
MavenExecutionPlan plan = lifecycleExecutor.calculateExecutionPlan(
375
session, "pre-integration-test", "integration-test", "post-integration-test");
376
377
for (MojoExecution execution : plan) {
378
Plugin plugin = execution.getPlugin();
379
380
if ("maven-failsafe-plugin".equals(plugin.getArtifactId()) &&
381
"integration-test".equals(execution.getGoal())) {
382
383
System.out.println("Running integration tests with forked lifecycle");
384
385
// This may trigger forked executions to prepare test environment
386
List<MavenProject> forkedProjects = lifecycleExecutor.executeForkedExecutions(
387
execution, session);
388
389
if (!forkedProjects.isEmpty()) {
390
System.out.println("Forked executions prepared " + forkedProjects.size() +
391
" projects for integration testing");
392
}
393
}
394
}
395
}
396
```
397
398
## Custom Lifecycle Participants
399
400
### AbstractMavenLifecycleParticipant
401
402
Base class for creating custom lifecycle participants that can hook into the build process.
403
404
```java { .api }
405
public abstract class AbstractMavenLifecycleParticipant {
406
/**
407
* Called before projects are built. Allows modification of projects
408
* and execution request before lifecycle execution begins.
409
*
410
* @param session Maven session
411
* @throws MavenExecutionException if participant processing fails
412
*/
413
public void afterProjectsRead(MavenSession session) throws MavenExecutionException {
414
// Default implementation does nothing
415
}
416
417
/**
418
* Called after session is started but before lifecycle execution.
419
*
420
* @param session Maven session
421
* @throws MavenExecutionException if participant processing fails
422
*/
423
public void afterSessionStart(MavenSession session) throws MavenExecutionException {
424
// Default implementation does nothing
425
}
426
427
/**
428
* Called after session ends, regardless of success or failure.
429
*
430
* @param session Maven session
431
* @throws MavenExecutionException if participant processing fails
432
*/
433
public void afterSessionEnd(MavenSession session) throws MavenExecutionException {
434
// Default implementation does nothing
435
}
436
}
437
```
438
439
**Custom Lifecycle Participant Example:**
440
```java
441
import org.apache.maven.AbstractMavenLifecycleParticipant;
442
import org.apache.maven.MavenExecutionException;
443
import org.apache.maven.execution.MavenSession;
444
import org.codehaus.plexus.component.annotations.Component;
445
446
@Component(role = AbstractMavenLifecycleParticipant.class, hint = "custom-participant")
447
public class CustomLifecycleParticipant extends AbstractMavenLifecycleParticipant {
448
449
@Override
450
public void afterProjectsRead(MavenSession session) throws MavenExecutionException {
451
System.out.println("Custom lifecycle participant: projects read");
452
453
// Modify projects before build starts
454
for (MavenProject project : session.getProjects()) {
455
// Add custom properties
456
project.getProperties().setProperty("custom.build.timestamp",
457
String.valueOf(System.currentTimeMillis()));
458
459
// Modify build configuration if needed
460
if ("jar".equals(project.getPackaging())) {
461
System.out.println("Customizing JAR project: " + project.getArtifactId());
462
// Custom logic for JAR projects
463
}
464
}
465
}
466
467
@Override
468
public void afterSessionStart(MavenSession session) throws MavenExecutionException {
469
System.out.println("Custom lifecycle participant: session started");
470
471
// Log build information
472
System.out.println("Build started for " + session.getProjects().size() + " projects");
473
System.out.println("Goals: " + session.getRequest().getGoals());
474
475
// Validate build environment
476
validateBuildEnvironment(session);
477
}
478
479
@Override
480
public void afterSessionEnd(MavenSession session) throws MavenExecutionException {
481
System.out.println("Custom lifecycle participant: session ended");
482
483
// Cleanup or post-build processing
484
long buildTime = System.currentTimeMillis() - session.getRequest().getStartTime().getTime();
485
System.out.println("Total build time: " + buildTime + "ms");
486
487
// Generate custom reports or notifications
488
generateBuildReport(session);
489
}
490
491
private void validateBuildEnvironment(MavenSession session) throws MavenExecutionException {
492
// Custom validation logic
493
String javaVersion = System.getProperty("java.version");
494
if (javaVersion.startsWith("1.8")) {
495
throw new MavenExecutionException("Java 8 is not supported for this build",
496
(Throwable) null);
497
}
498
}
499
500
private void generateBuildReport(MavenSession session) {
501
// Custom reporting logic
502
System.out.println("=== Build Report ===");
503
for (MavenProject project : session.getProjects()) {
504
System.out.println("Project: " + project.getName() + " - " + project.getVersion());
505
}
506
}
507
}
508
```
509
510
## Types
511
512
```java { .api }
513
public interface LifecyclePhase {
514
List<Plugin> getPlugins();
515
void addPlugin(Plugin plugin);
516
String toString();
517
}
518
519
public class LifecyclePhaseNotFoundException extends Exception {
520
public LifecyclePhaseNotFoundException(String message);
521
public LifecyclePhaseNotFoundException(String message, Throwable cause);
522
}
523
524
public class LifecycleNotFoundException extends Exception {
525
public LifecycleNotFoundException(String message);
526
public LifecycleNotFoundException(String message, Throwable cause);
527
}
528
529
public class InvalidPluginDescriptorException extends Exception {
530
public InvalidPluginDescriptorException(String message);
531
public InvalidPluginDescriptorException(String message, Throwable cause);
532
}
533
534
public interface MojoDescriptor {
535
String getExecutePhase();
536
String getExecuteGoal();
537
String getExecuteLifecycle();
538
boolean requiresProject();
539
boolean requiresReports();
540
boolean aggregator();
541
boolean requiresDirectInvocation();
542
boolean requiresOnline();
543
boolean inheritedByDefault();
544
String getPhase();
545
String getSince();
546
String getDeprecated();
547
}
548
549
public interface LifecycleMapping {
550
Map<String, String> getPhases(String packaging);
551
List<String> getOptionalMojos(String packaging);
552
}
553
554
public interface LifecycleMappingDelegate {
555
Map<String, List<MojoExecution>> calculateLifecycleMappings(MavenSession session,
556
MavenProject project, Lifecycle lifecycle, String lifecyclePhase)
557
throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
558
MojoNotFoundException, InvalidPluginDescriptorException;
559
}
560
```