Add start/stop goals to maven plugin

SpringApplicationLifecycle provides basic lifecycle operations on the
current Spring Boot application (that is checking if the application has
fully started and gracefully terminate the app). It can be registered as
an MBean of the platform MBean server if a specific property is set.

The Maven plugin uses that MBean to check that the application is ready
before ending the "start" phase. It uses it to trigger a proper shutdown
of the application during the "stop" phase.

If the process has to be forked, the platform MBean server is exposed on
a configurable port so that the maven plugin can connect to it.

Such change permits the maven plugin to integrate a classical integration
test scenario where the "start" goal is invoked during the
pre-integration phase and the "stop" goal during the post-integration
phase.

Closes gh-2525
This commit is contained in:
Stephane Nicoll
2015-03-12 08:31:21 +01:00
parent 129c24926e
commit e0dfe9fb86
26 changed files with 1893 additions and 382 deletions

View File

@@ -0,0 +1 @@
invoker.goals=clean verify

View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.boot.maven.it</groupId>
<artifactId>start-stop-fork</artifactId>
<version>0.0.1.BUILD-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>@project.groupId@</groupId>
<artifactId>@project.artifactId@</artifactId>
<version>@project.version@</version>
<executions>
<execution>
<id>pre-integration-test</id>
<goals>
<goal>start</goal>
</goals>
</execution>
<execution>
<id>post-integration-test</id>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
<configuration>
<fork>true</fork>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,79 @@
/*
* Copyright 2012-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.test;
import java.lang.management.ManagementFactory;
import javax.management.MBeanServer;
import javax.management.ObjectName;
/**
* This sample app simulates the JMX Mbean that is exposed by the Spring
* Boot application.
*/
public class SampleApplication {
private static final Object lock = new Object();
public static void main(String[] args) throws Exception {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
ObjectName name = new ObjectName("org.springframework.boot:type=Lifecycle,name=springApplicationLifecycle");
SpringApplicationLifecycle mbean = new SpringApplicationLifecycle();
mbs.registerMBean(mbean, name);
// Flag the app as ready
mbean.ready = true;
int waitAttempts = 0;
while (!mbean.shutdownInvoked) {
if (waitAttempts > 10) {
throw new IllegalStateException("Shutdown should have been invoked by now");
}
synchronized (lock) {
lock.wait(250);
}
waitAttempts++;
}
System.out.println("Application has terminated gracefully");
}
public interface SpringApplicationLifecycleMXBean {
boolean isReady();
void shutdown();
}
static class SpringApplicationLifecycle implements SpringApplicationLifecycleMXBean {
private boolean ready;
private boolean shutdownInvoked;
@Override
public boolean isReady() {
return this.ready;
}
@Override
public void shutdown() {
this.shutdownInvoked = true;
System.out.println("Shutdown requested");
}
}
}

View File

@@ -0,0 +1,6 @@
import static org.junit.Assert.assertTrue
def file = new File(basedir, "build.log")
assertTrue 'Shutdown should have been invoked', file.text.contains("Shutdown requested")
assertTrue 'Application should have terminated', file.text.contains("Application has terminated gracefully")

View File

@@ -0,0 +1 @@
invoker.goals=clean verify

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.boot.maven.it</groupId>
<artifactId>start-stop</artifactId>
<version>0.0.1.BUILD-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>@project.groupId@</groupId>
<artifactId>@project.artifactId@</artifactId>
<version>@project.version@</version>
<executions>
<execution>
<id>pre-integration-test</id>
<goals>
<goal>start</goal>
</goals>
</execution>
<execution>
<id>post-integration-test</id>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,79 @@
/*
* Copyright 2012-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.test;
import java.lang.management.ManagementFactory;
import javax.management.MBeanServer;
import javax.management.ObjectName;
/**
* This sample app simulates the JMX Mbean that is exposed by the Spring
* Boot application.
*/
public class SampleApplication {
private static final Object lock = new Object();
public static void main(String[] args) throws Exception {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
ObjectName name = new ObjectName("org.springframework.boot:type=Lifecycle,name=springApplicationLifecycle");
SpringApplicationLifecycle mbean = new SpringApplicationLifecycle();
mbs.registerMBean(mbean, name);
// Flag the app as ready
mbean.ready = true;
int waitAttempts = 0;
while (!mbean.shutdownInvoked) {
if (waitAttempts > 10) {
throw new IllegalStateException("Shutdown should have been invoked by now");
}
synchronized (lock) {
lock.wait(250);
}
waitAttempts++;
}
System.out.println("Application has terminated gracefully");
}
public interface SpringApplicationLifecycleMXBean {
boolean isReady();
void shutdown();
}
static class SpringApplicationLifecycle implements SpringApplicationLifecycleMXBean {
private boolean ready;
private boolean shutdownInvoked;
@Override
public boolean isReady() {
return this.ready;
}
@Override
public void shutdown() {
this.shutdownInvoked = true;
System.out.println("Shutdown requested");
}
}
}

View File

@@ -0,0 +1,6 @@
import static org.junit.Assert.assertTrue
def file = new File(basedir, "build.log")
assertTrue 'Shutdown should have been invoked', file.text.contains("Shutdown requested")
assertTrue 'Application should have terminated', file.text.contains("Application has terminated gracefully")