Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in / Register
Toggle navigation
S
spring-boot
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
DEMO
spring-boot
Commits
bce4bb88
Commit
bce4bb88
authored
Jun 04, 2015
by
Phillip Webb
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Polish start stop support
parent
09a29a72
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
274 additions
and
232 deletions
+274
-232
SpringApplicationLifecycleAutoConfiguration.java
.../context/SpringApplicationLifecycleAutoConfiguration.java
+6
-5
SpringApplicationLifecycleAutoConfigurationTests.java
...ext/SpringApplicationLifecycleAutoConfigurationTests.java
+12
-14
RunProcess.java
...ava/org/springframework/boot/loader/tools/RunProcess.java
+8
-9
SampleApplication.java
...t-stop-fork/src/main/java/org/test/SampleApplication.java
+8
-6
SampleApplication.java
.../start-stop/src/main/java/org/test/SampleApplication.java
+8
-6
AbstractRunMojo.java
.../java/org/springframework/boot/maven/AbstractRunMojo.java
+13
-13
RunArguments.java
...ain/java/org/springframework/boot/maven/RunArguments.java
+1
-1
RunMojo.java
...src/main/java/org/springframework/boot/maven/RunMojo.java
+5
-4
SpringApplicationLifecycleClient.java
...ramework/boot/maven/SpringApplicationLifecycleClient.java
+29
-26
StartMojo.java
...c/main/java/org/springframework/boot/maven/StartMojo.java
+134
-103
StopMojo.java
...rc/main/java/org/springframework/boot/maven/StopMojo.java
+27
-24
SpringApplicationLifecycleRegistrar.java
...ork/boot/context/SpringApplicationLifecycleRegistrar.java
+13
-12
SpringApplicationLifecycleRegistrarTests.java
...oot/context/SpringApplicationLifecycleRegistrarTests.java
+10
-9
No files found.
spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/context/SpringApplicationLifecycleAutoConfiguration.java
View file @
bce4bb88
...
@@ -43,7 +43,8 @@ import org.springframework.jmx.export.MBeanExporter;
...
@@ -43,7 +43,8 @@ import org.springframework.jmx.export.MBeanExporter;
class
SpringApplicationLifecycleAutoConfiguration
{
class
SpringApplicationLifecycleAutoConfiguration
{
/**
/**
* The property to use to customize the {@code ObjectName} of the application lifecycle mbean.
* The property to use to customize the {@code ObjectName} of the application
* lifecycle mbean.
*/
*/
static
final
String
JMX_NAME_PROPERTY
=
"spring.context.lifecycle.jmx-name"
;
static
final
String
JMX_NAME_PROPERTY
=
"spring.context.lifecycle.jmx-name"
;
...
@@ -61,10 +62,10 @@ class SpringApplicationLifecycleAutoConfiguration {
...
@@ -61,10 +62,10 @@ class SpringApplicationLifecycleAutoConfiguration {
@Bean
@Bean
public
SpringApplicationLifecycleRegistrar
springApplicationLifecycleRegistrar
()
public
SpringApplicationLifecycleRegistrar
springApplicationLifecycleRegistrar
()
throws
MalformedObjectNameException
{
throws
MalformedObjectNameException
{
String
jmxName
=
this
.
environment
String
jmxName
=
this
.
environment
.
getProperty
(
JMX_NAME_PROPERTY
,
DEFAULT_JMX_NAME
);
.
getProperty
(
JMX_NAME_PROPERTY
,
DEFAULT_JMX_NAME
);
if
(
mbeanExporter
!=
null
)
{
// Make sure to not register that MBean twice
if
(
this
.
mbeanExporter
!=
null
)
{
// Make sure to not register that MBean twice
mbeanExporter
.
addExcludedBean
(
jmxName
);
this
.
mbeanExporter
.
addExcludedBean
(
jmxName
);
}
}
return
new
SpringApplicationLifecycleRegistrar
(
jmxName
);
return
new
SpringApplicationLifecycleRegistrar
(
jmxName
);
}
}
...
...
spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/context/SpringApplicationLifecycleAutoConfigurationTests.java
View file @
bce4bb88
...
@@ -17,6 +17,7 @@
...
@@ -17,6 +17,7 @@
package
org
.
springframework
.
boot
.
autoconfigure
.
context
;
package
org
.
springframework
.
boot
.
autoconfigure
.
context
;
import
java.lang.management.ManagementFactory
;
import
java.lang.management.ManagementFactory
;
import
javax.management.InstanceNotFoundException
;
import
javax.management.InstanceNotFoundException
;
import
javax.management.MBeanServer
;
import
javax.management.MBeanServer
;
import
javax.management.MalformedObjectNameException
;
import
javax.management.MalformedObjectNameException
;
...
@@ -28,7 +29,6 @@ import org.junit.Before;
...
@@ -28,7 +29,6 @@ import org.junit.Before;
import
org.junit.Rule
;
import
org.junit.Rule
;
import
org.junit.Test
;
import
org.junit.Test
;
import
org.junit.rules.ExpectedException
;
import
org.junit.rules.ExpectedException
;
import
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration
;
import
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration
;
import
org.springframework.boot.test.EnvironmentTestUtils
;
import
org.springframework.boot.test.EnvironmentTestUtils
;
import
org.springframework.context.annotation.AnnotationConfigApplicationContext
;
import
org.springframework.context.annotation.AnnotationConfigApplicationContext
;
...
@@ -65,17 +65,16 @@ public class SpringApplicationLifecycleAutoConfigurationTests {
...
@@ -65,17 +65,16 @@ public class SpringApplicationLifecycleAutoConfigurationTests {
}
}
@Test
@Test
public
void
notRegisteredByDefault
()
throws
MalformedObjectNameException
,
InstanceNotFoundException
{
public
void
notRegisteredByDefault
()
throws
MalformedObjectNameException
,
InstanceNotFoundException
{
load
();
load
();
this
.
thrown
.
expect
(
InstanceNotFoundException
.
class
);
thrown
.
expect
(
InstanceNotFoundException
.
class
);
this
.
mBeanServer
.
getObjectInstance
(
createDefaultObjectName
());
this
.
mBeanServer
.
getObjectInstance
(
createDefaultObjectName
());
}
}
@Test
@Test
public
void
registeredWithProperty
()
throws
Exception
{
public
void
registeredWithProperty
()
throws
Exception
{
load
(
ENABLE_LIFECYCLE_PROP
);
load
(
ENABLE_LIFECYCLE_PROP
);
ObjectName
objectName
=
createDefaultObjectName
();
ObjectName
objectName
=
createDefaultObjectName
();
ObjectInstance
objectInstance
=
this
.
mBeanServer
.
getObjectInstance
(
objectName
);
ObjectInstance
objectInstance
=
this
.
mBeanServer
.
getObjectInstance
(
objectName
);
assertNotNull
(
"Lifecycle bean should have been registered"
,
objectInstance
);
assertNotNull
(
"Lifecycle bean should have been registered"
,
objectInstance
);
...
@@ -84,18 +83,17 @@ public class SpringApplicationLifecycleAutoConfigurationTests {
...
@@ -84,18 +83,17 @@ public class SpringApplicationLifecycleAutoConfigurationTests {
@Test
@Test
public
void
registerWithCustomJmxName
()
throws
InstanceNotFoundException
{
public
void
registerWithCustomJmxName
()
throws
InstanceNotFoundException
{
String
customJmxName
=
"org.acme:name=FooBar"
;
String
customJmxName
=
"org.acme:name=FooBar"
;
System
.
setProperty
(
SpringApplicationLifecycleAutoConfiguration
.
JMX_NAME_PROPERTY
,
customJmxName
);
System
.
setProperty
(
SpringApplicationLifecycleAutoConfiguration
.
JMX_NAME_PROPERTY
,
customJmxName
);
try
{
try
{
load
(
ENABLE_LIFECYCLE_PROP
);
load
(
ENABLE_LIFECYCLE_PROP
);
try
{
try
{
this
.
mBeanServer
.
getObjectInstance
(
createObjectName
(
customJmxName
));
this
.
mBeanServer
.
getObjectInstance
(
createObjectName
(
customJmxName
));
}
}
catch
(
InstanceNotFoundException
e
)
{
catch
(
InstanceNotFoundException
e
x
)
{
fail
(
"lifecycle MBean should have been exposed with custom name"
);
fail
(
"lifecycle MBean should have been exposed with custom name"
);
}
}
this
.
thrown
.
expect
(
InstanceNotFoundException
.
class
);
// Should not be exposed
thrown
.
expect
(
InstanceNotFoundException
.
class
);
// Should not be exposed
this
.
mBeanServer
.
getObjectInstance
(
createDefaultObjectName
());
this
.
mBeanServer
.
getObjectInstance
(
createDefaultObjectName
());
}
}
finally
{
finally
{
...
@@ -111,18 +109,18 @@ public class SpringApplicationLifecycleAutoConfigurationTests {
...
@@ -111,18 +109,18 @@ public class SpringApplicationLifecycleAutoConfigurationTests {
try
{
try
{
return
new
ObjectName
(
jmxName
);
return
new
ObjectName
(
jmxName
);
}
}
catch
(
MalformedObjectNameException
e
)
{
catch
(
MalformedObjectNameException
e
x
)
{
throw
new
IllegalStateException
(
"Invalid jmx name "
+
jmxName
,
e
);
throw
new
IllegalStateException
(
"Invalid jmx name "
+
jmxName
,
e
x
);
}
}
}
}
private
void
load
(
String
...
environment
)
{
private
void
load
(
String
...
environment
)
{
AnnotationConfigApplicationContext
applicationContext
=
new
AnnotationConfigApplicationContext
();
AnnotationConfigApplicationContext
applicationContext
=
new
AnnotationConfigApplicationContext
();
EnvironmentTestUtils
.
addEnvironment
(
applicationContext
,
environment
);
EnvironmentTestUtils
.
addEnvironment
(
applicationContext
,
environment
);
applicationContext
.
register
(
JmxAutoConfiguration
.
class
,
SpringApplicationLifecycleAutoConfiguration
.
class
);
applicationContext
.
register
(
JmxAutoConfiguration
.
class
,
SpringApplicationLifecycleAutoConfiguration
.
class
);
applicationContext
.
refresh
();
applicationContext
.
refresh
();
this
.
context
=
applicationContext
;
this
.
context
=
applicationContext
;
}
}
}
}
spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/RunProcess.java
View file @
bce4bb88
...
@@ -55,13 +55,6 @@ public class RunProcess {
...
@@ -55,13 +55,6 @@ public class RunProcess {
return
run
(
waitForProcess
,
Arrays
.
asList
(
args
));
return
run
(
waitForProcess
,
Arrays
.
asList
(
args
));
}
}
/**
* Kill this process.
*/
public
void
kill
()
{
doKill
();
}
protected
int
run
(
boolean
waitForProcess
,
Collection
<
String
>
args
)
throws
IOException
{
protected
int
run
(
boolean
waitForProcess
,
Collection
<
String
>
args
)
throws
IOException
{
ProcessBuilder
builder
=
new
ProcessBuilder
(
this
.
command
);
ProcessBuilder
builder
=
new
ProcessBuilder
(
this
.
command
);
builder
.
command
().
addAll
(
args
);
builder
.
command
().
addAll
(
args
);
...
@@ -131,7 +124,7 @@ public class RunProcess {
...
@@ -131,7 +124,7 @@ public class RunProcess {
return
true
;
return
true
;
}
}
}
}
catch
(
Exception
e
)
{
catch
(
Exception
e
x
)
{
return
true
;
return
true
;
}
}
return
false
;
return
false
;
...
@@ -180,6 +173,13 @@ public class RunProcess {
...
@@ -180,6 +173,13 @@ public class RunProcess {
}
}
/**
* Kill this process.
*/
public
void
kill
()
{
doKill
();
}
private
boolean
doKill
()
{
private
boolean
doKill
()
{
// destroy the running process
// destroy the running process
Process
process
=
this
.
process
;
Process
process
=
this
.
process
;
...
@@ -194,7 +194,6 @@ public class RunProcess {
...
@@ -194,7 +194,6 @@ public class RunProcess {
Thread
.
currentThread
().
interrupt
();
Thread
.
currentThread
().
interrupt
();
}
}
}
}
return
false
;
return
false
;
}
}
...
...
spring-boot-tools/spring-boot-maven-plugin/src/it/start-stop-fork/src/main/java/org/test/SampleApplication.java
View file @
bce4bb88
...
@@ -22,8 +22,7 @@ import javax.management.MBeanServer;
...
@@ -22,8 +22,7 @@ import javax.management.MBeanServer;
import
javax.management.ObjectName
;
import
javax.management.ObjectName
;
/**
/**
* This sample app simulates the JMX Mbean that is exposed by the Spring
* This sample app simulates the JMX Mbean that is exposed by the Spring Boot application.
* Boot application.
*/
*/
public
class
SampleApplication
{
public
class
SampleApplication
{
...
@@ -31,7 +30,8 @@ public class SampleApplication {
...
@@ -31,7 +30,8 @@ public class SampleApplication {
public
static
void
main
(
String
[]
args
)
throws
Exception
{
public
static
void
main
(
String
[]
args
)
throws
Exception
{
MBeanServer
mbs
=
ManagementFactory
.
getPlatformMBeanServer
();
MBeanServer
mbs
=
ManagementFactory
.
getPlatformMBeanServer
();
ObjectName
name
=
new
ObjectName
(
"org.springframework.boot:type=Lifecycle,name=springApplicationLifecycle"
);
ObjectName
name
=
new
ObjectName
(
"org.springframework.boot:type=Lifecycle,name=springApplicationLifecycle"
);
SpringApplicationLifecycle
mbean
=
new
SpringApplicationLifecycle
();
SpringApplicationLifecycle
mbean
=
new
SpringApplicationLifecycle
();
mbs
.
registerMBean
(
mbean
,
name
);
mbs
.
registerMBean
(
mbean
,
name
);
...
@@ -41,7 +41,8 @@ public class SampleApplication {
...
@@ -41,7 +41,8 @@ public class SampleApplication {
int
waitAttempts
=
0
;
int
waitAttempts
=
0
;
while
(!
mbean
.
shutdownInvoked
)
{
while
(!
mbean
.
shutdownInvoked
)
{
if
(
waitAttempts
>
10
)
{
if
(
waitAttempts
>
10
)
{
throw
new
IllegalStateException
(
"Shutdown should have been invoked by now"
);
throw
new
IllegalStateException
(
"Shutdown should have been invoked by now"
);
}
}
synchronized
(
lock
)
{
synchronized
(
lock
)
{
lock
.
wait
(
250
);
lock
.
wait
(
250
);
...
@@ -50,7 +51,6 @@ public class SampleApplication {
...
@@ -50,7 +51,6 @@ public class SampleApplication {
}
}
}
}
public
interface
SpringApplicationLifecycleMXBean
{
public
interface
SpringApplicationLifecycleMXBean
{
boolean
isReady
();
boolean
isReady
();
...
@@ -76,5 +76,7 @@ public class SampleApplication {
...
@@ -76,5 +76,7 @@ public class SampleApplication {
this
.
shutdownInvoked
=
true
;
this
.
shutdownInvoked
=
true
;
System
.
out
.
println
(
"Shutdown requested"
);
System
.
out
.
println
(
"Shutdown requested"
);
}
}
}
}
}
\ No newline at end of file
}
spring-boot-tools/spring-boot-maven-plugin/src/it/start-stop/src/main/java/org/test/SampleApplication.java
View file @
bce4bb88
...
@@ -21,8 +21,7 @@ import javax.management.MBeanServer;
...
@@ -21,8 +21,7 @@ import javax.management.MBeanServer;
import
javax.management.ObjectName
;
import
javax.management.ObjectName
;
/**
/**
* This sample app simulates the JMX Mbean that is exposed by the Spring
* This sample app simulates the JMX Mbean that is exposed by the Spring Boot application.
* Boot application.
*/
*/
public
class
SampleApplication
{
public
class
SampleApplication
{
...
@@ -30,7 +29,8 @@ public class SampleApplication {
...
@@ -30,7 +29,8 @@ public class SampleApplication {
public
static
void
main
(
String
[]
args
)
throws
Exception
{
public
static
void
main
(
String
[]
args
)
throws
Exception
{
MBeanServer
mbs
=
ManagementFactory
.
getPlatformMBeanServer
();
MBeanServer
mbs
=
ManagementFactory
.
getPlatformMBeanServer
();
ObjectName
name
=
new
ObjectName
(
"org.springframework.boot:type=Lifecycle,name=springApplicationLifecycle"
);
ObjectName
name
=
new
ObjectName
(
"org.springframework.boot:type=Lifecycle,name=springApplicationLifecycle"
);
SpringApplicationLifecycle
mbean
=
new
SpringApplicationLifecycle
();
SpringApplicationLifecycle
mbean
=
new
SpringApplicationLifecycle
();
mbs
.
registerMBean
(
mbean
,
name
);
mbs
.
registerMBean
(
mbean
,
name
);
...
@@ -40,7 +40,8 @@ public class SampleApplication {
...
@@ -40,7 +40,8 @@ public class SampleApplication {
int
waitAttempts
=
0
;
int
waitAttempts
=
0
;
while
(!
mbean
.
shutdownInvoked
)
{
while
(!
mbean
.
shutdownInvoked
)
{
if
(
waitAttempts
>
10
)
{
if
(
waitAttempts
>
10
)
{
throw
new
IllegalStateException
(
"Shutdown should have been invoked by now"
);
throw
new
IllegalStateException
(
"Shutdown should have been invoked by now"
);
}
}
synchronized
(
lock
)
{
synchronized
(
lock
)
{
lock
.
wait
(
250
);
lock
.
wait
(
250
);
...
@@ -49,7 +50,6 @@ public class SampleApplication {
...
@@ -49,7 +50,6 @@ public class SampleApplication {
}
}
}
}
public
interface
SpringApplicationLifecycleMXBean
{
public
interface
SpringApplicationLifecycleMXBean
{
boolean
isReady
();
boolean
isReady
();
...
@@ -75,5 +75,7 @@ public class SampleApplication {
...
@@ -75,5 +75,7 @@ public class SampleApplication {
this
.
shutdownInvoked
=
true
;
this
.
shutdownInvoked
=
true
;
System
.
out
.
println
(
"Shutdown requested"
);
System
.
out
.
println
(
"Shutdown requested"
);
}
}
}
}
}
\ No newline at end of file
}
spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java
View file @
bce4bb88
...
@@ -36,7 +36,6 @@ import org.apache.maven.plugins.annotations.Parameter;
...
@@ -36,7 +36,6 @@ import org.apache.maven.plugins.annotations.Parameter;
import
org.apache.maven.project.MavenProject
;
import
org.apache.maven.project.MavenProject
;
import
org.apache.maven.shared.artifact.filter.collection.AbstractArtifactFeatureFilter
;
import
org.apache.maven.shared.artifact.filter.collection.AbstractArtifactFeatureFilter
;
import
org.apache.maven.shared.artifact.filter.collection.FilterArtifacts
;
import
org.apache.maven.shared.artifact.filter.collection.FilterArtifacts
;
import
org.springframework.boot.loader.tools.FileUtils
;
import
org.springframework.boot.loader.tools.FileUtils
;
import
org.springframework.boot.loader.tools.MainClassFinder
;
import
org.springframework.boot.loader.tools.MainClassFinder
;
...
@@ -137,8 +136,7 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
...
@@ -137,8 +136,7 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
* @return {@code true} if the application process should be forked
* @return {@code true} if the application process should be forked
*/
*/
protected
boolean
isFork
()
{
protected
boolean
isFork
()
{
return
(
Boolean
.
TRUE
.
equals
(
this
.
fork
)
return
(
Boolean
.
TRUE
.
equals
(
this
.
fork
)
||
(
this
.
fork
==
null
&&
(
hasAgent
()
||
hasJvmArgs
())));
||
(
this
.
fork
==
null
&&
(
hasAgent
()
||
hasJvmArgs
())));
}
}
private
boolean
hasAgent
()
{
private
boolean
hasAgent
()
{
...
@@ -165,7 +163,7 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
...
@@ -165,7 +163,7 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
}
}
CodeSource
source
=
loaded
.
getProtectionDomain
().
getCodeSource
();
CodeSource
source
=
loaded
.
getProtectionDomain
().
getCodeSource
();
if
(
source
!=
null
)
{
if
(
source
!=
null
)
{
this
.
agent
=
new
File
[]
{
new
File
(
source
.
getLocation
().
getFile
())
};
this
.
agent
=
new
File
[]
{
new
File
(
source
.
getLocation
().
getFile
())
};
}
}
}
}
}
}
...
@@ -178,7 +176,8 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
...
@@ -178,7 +176,8 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
}
}
}
}
private
void
run
(
String
startClassName
)
throws
MojoExecutionException
,
MojoFailureException
{
private
void
run
(
String
startClassName
)
throws
MojoExecutionException
,
MojoFailureException
{
findAgent
();
findAgent
();
if
(
isFork
())
{
if
(
isFork
())
{
doRunWithForkedJvm
(
startClassName
);
doRunWithForkedJvm
(
startClassName
);
...
@@ -196,8 +195,8 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
...
@@ -196,8 +195,8 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
}
}
}
}
private
void
doRunWithForkedJvm
(
String
startClassName
)
private
void
doRunWithForkedJvm
(
String
startClassName
)
throws
MojoExecutionException
,
throws
MojoExecutionException
,
MojoFailureException
{
MojoFailureException
{
List
<
String
>
args
=
new
ArrayList
<
String
>();
List
<
String
>
args
=
new
ArrayList
<
String
>();
addAgents
(
args
);
addAgents
(
args
);
addJvmArgs
(
args
);
addJvmArgs
(
args
);
...
@@ -213,8 +212,8 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
...
@@ -213,8 +212,8 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
* @throws MojoExecutionException
* @throws MojoExecutionException
* @throws MojoFailureException
* @throws MojoFailureException
*/
*/
protected
abstract
void
runWithForkedJvm
(
List
<
String
>
args
)
throws
MojoExecutionException
,
MojoFailureException
;
protected
abstract
void
runWithForkedJvm
(
List
<
String
>
args
)
throws
MojoExecutionException
,
MojoFailureException
;
/**
/**
* Run with the current VM, using the specified arguments.
* Run with the current VM, using the specified arguments.
...
@@ -277,8 +276,8 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
...
@@ -277,8 +276,8 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
args
.
add
(
"-cp"
);
args
.
add
(
"-cp"
);
args
.
add
(
classpath
.
toString
());
args
.
add
(
classpath
.
toString
());
}
}
catch
(
Exception
e
)
{
catch
(
Exception
e
x
)
{
throw
new
MojoExecutionException
(
"Could not build classpath"
,
e
);
throw
new
MojoExecutionException
(
"Could not build classpath"
,
e
x
);
}
}
}
}
...
@@ -358,8 +357,8 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
...
@@ -358,8 +357,8 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
getLog
().
debug
(
sb
.
toString
().
trim
());
getLog
().
debug
(
sb
.
toString
().
trim
());
}
}
private
static
class
TestArtifactFilter
extends
AbstractArtifactFeatureFilter
{
private
static
class
TestArtifactFilter
extends
AbstractArtifactFeatureFilter
{
public
TestArtifactFilter
()
{
public
TestArtifactFilter
()
{
super
(
""
,
Artifact
.
SCOPE_TEST
);
super
(
""
,
Artifact
.
SCOPE_TEST
);
}
}
...
@@ -368,6 +367,7 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
...
@@ -368,6 +367,7 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
protected
String
getArtifactFeature
(
Artifact
artifact
)
{
protected
String
getArtifactFeature
(
Artifact
artifact
)
{
return
artifact
.
getScope
();
return
artifact
.
getScope
();
}
}
}
}
/**
/**
...
@@ -423,7 +423,7 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
...
@@ -423,7 +423,7 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
if
(!
mainMethod
.
isAccessible
())
{
if
(!
mainMethod
.
isAccessible
())
{
mainMethod
.
setAccessible
(
true
);
mainMethod
.
setAccessible
(
true
);
}
}
mainMethod
.
invoke
(
null
,
new
Object
[]
{
this
.
args
});
mainMethod
.
invoke
(
null
,
new
Object
[]
{
this
.
args
});
}
}
catch
(
NoSuchMethodException
ex
)
{
catch
(
NoSuchMethodException
ex
)
{
Exception
wrappedEx
=
new
Exception
(
Exception
wrappedEx
=
new
Exception
(
...
...
spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunArguments.java
View file @
bce4bb88
...
@@ -42,7 +42,7 @@ class RunArguments {
...
@@ -42,7 +42,7 @@ class RunArguments {
}
}
public
LinkedList
<
String
>
getArgs
()
{
public
LinkedList
<
String
>
getArgs
()
{
return
args
;
return
this
.
args
;
}
}
public
String
[]
asArray
()
{
public
String
[]
asArray
()
{
...
...
spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java
View file @
bce4bb88
...
@@ -24,7 +24,6 @@ import org.apache.maven.plugins.annotations.Execute;
...
@@ -24,7 +24,6 @@ import org.apache.maven.plugins.annotations.Execute;
import
org.apache.maven.plugins.annotations.LifecyclePhase
;
import
org.apache.maven.plugins.annotations.LifecyclePhase
;
import
org.apache.maven.plugins.annotations.Mojo
;
import
org.apache.maven.plugins.annotations.Mojo
;
import
org.apache.maven.plugins.annotations.ResolutionScope
;
import
org.apache.maven.plugins.annotations.ResolutionScope
;
import
org.springframework.boot.loader.tools.JavaExecutable
;
import
org.springframework.boot.loader.tools.JavaExecutable
;
import
org.springframework.boot.loader.tools.RunProcess
;
import
org.springframework.boot.loader.tools.RunProcess
;
...
@@ -41,15 +40,17 @@ public class RunMojo extends AbstractRunMojo {
...
@@ -41,15 +40,17 @@ public class RunMojo extends AbstractRunMojo {
@Override
@Override
protected
void
runWithForkedJvm
(
List
<
String
>
args
)
throws
MojoExecutionException
{
protected
void
runWithForkedJvm
(
List
<
String
>
args
)
throws
MojoExecutionException
{
try
{
try
{
new
RunProcess
(
new
JavaExecutable
().
toString
()).
run
(
true
,
args
new
RunProcess
(
new
JavaExecutable
().
toString
()).
run
(
true
,
.
toArray
(
new
String
[
args
.
size
()]));
args
.
toArray
(
new
String
[
args
.
size
()]));
}
}
catch
(
Exception
ex
)
{
catch
(
Exception
ex
)
{
throw
new
MojoExecutionException
(
"Could not exec java"
,
ex
);
throw
new
MojoExecutionException
(
"Could not exec java"
,
ex
);
}
}
}
}
protected
void
runWithMavenJvm
(
String
startClassName
,
String
...
arguments
)
throws
MojoExecutionException
{
@Override
protected
void
runWithMavenJvm
(
String
startClassName
,
String
...
arguments
)
throws
MojoExecutionException
{
IsolatedThreadGroup
threadGroup
=
new
IsolatedThreadGroup
(
startClassName
);
IsolatedThreadGroup
threadGroup
=
new
IsolatedThreadGroup
(
startClassName
);
Thread
launchThread
=
new
Thread
(
threadGroup
,
new
LaunchRunner
(
startClassName
,
Thread
launchThread
=
new
Thread
(
threadGroup
,
new
LaunchRunner
(
startClassName
,
arguments
),
startClassName
+
".main()"
);
arguments
),
startClassName
+
".main()"
);
...
...
spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/SpringApplicationLifecycleClient.java
View file @
bce4bb88
...
@@ -17,6 +17,7 @@
...
@@ -17,6 +17,7 @@
package
org
.
springframework
.
boot
.
maven
;
package
org
.
springframework
.
boot
.
maven
;
import
java.io.IOException
;
import
java.io.IOException
;
import
javax.management.AttributeNotFoundException
;
import
javax.management.AttributeNotFoundException
;
import
javax.management.InstanceNotFoundException
;
import
javax.management.InstanceNotFoundException
;
import
javax.management.MBeanException
;
import
javax.management.MBeanException
;
...
@@ -35,20 +36,19 @@ import org.apache.maven.plugin.MojoExecutionException;
...
@@ -35,20 +36,19 @@ import org.apache.maven.plugin.MojoExecutionException;
* information about the lifecycle of a given Spring application.
* information about the lifecycle of a given Spring application.
*
*
* @author Stephane Nicoll
* @author Stephane Nicoll
* @since 1.3.0
*/
*/
class
SpringApplicationLifecycleClient
{
class
SpringApplicationLifecycleClient
{
//Note: see org.springframework.boot.autoconfigure.test.SpringApplicationLifecycleAutoConfiguration
// Note: see SpringApplicationLifecycleAutoConfiguration
static
final
String
DEFAULT_OBJECT_NAME
=
static
final
String
DEFAULT_OBJECT_NAME
=
"org.springframework.boot:type=Lifecycle,name=springApplicationLifecycle"
;
"org.springframework.boot:type=Lifecycle,name=springApplicationLifecycle"
;
private
final
MBeanServerConnection
mBeanServerC
onnection
;
private
final
MBeanServerConnection
c
onnection
;
private
final
ObjectName
objectName
;
private
final
ObjectName
objectName
;
public
SpringApplicationLifecycleClient
(
MBeanServerConnection
mBeanServerConnection
,
String
jmxName
)
{
public
SpringApplicationLifecycleClient
(
MBeanServerConnection
connection
,
this
.
mBeanServerConnection
=
mBeanServerConnection
;
String
jmxName
)
{
this
.
connection
=
connection
;
this
.
objectName
=
toObjectName
(
jmxName
);
this
.
objectName
=
toObjectName
(
jmxName
);
}
}
...
@@ -66,30 +66,32 @@ class SpringApplicationLifecycleClient {
...
@@ -66,30 +66,32 @@ class SpringApplicationLifecycleClient {
}
}
/**
/**
* Check if the spring application managed by this instance is ready.
* Check if the spring application managed by this instance is ready.
Returns
*
<p>Returns {@code false} if the mbean is not yet deployed so this method
*
{@code false} if the mbean is not yet deployed so this method should be repeatedly
*
should be repeatedly
called until a timeout is reached.
* called until a timeout is reached.
* @return {@code true} if the application is ready to service requests
* @return {@code true} if the application is ready to service requests
* @throws MojoExecutionException if the JMX service could not be contacted
* @throws MojoExecutionException if the JMX service could not be contacted
*/
*/
public
boolean
isReady
()
throws
MojoExecutionException
{
public
boolean
isReady
()
throws
MojoExecutionException
{
try
{
try
{
return
(
Boolean
)
this
.
mBeanServerC
onnection
.
getAttribute
(
this
.
objectName
,
"Ready"
);
return
(
Boolean
)
this
.
c
onnection
.
getAttribute
(
this
.
objectName
,
"Ready"
);
}
}
catch
(
InstanceNotFoundException
e
)
{
catch
(
InstanceNotFoundException
e
x
)
{
return
false
;
// Instance not available yet
return
false
;
// Instance not available yet
}
}
catch
(
AttributeNotFoundException
e
)
{
catch
(
AttributeNotFoundException
ex
)
{
throw
new
IllegalStateException
(
"Unexpected: attribute 'Ready' not available"
,
e
);
throw
new
IllegalStateException
(
"Unexpected: attribute 'Ready' not available"
,
ex
);
}
}
catch
(
ReflectionException
e
)
{
catch
(
ReflectionException
ex
)
{
throw
new
MojoExecutionException
(
"Failed to retrieve Ready attribute"
,
e
.
getCause
());
throw
new
MojoExecutionException
(
"Failed to retrieve Ready attribute"
,
ex
.
getCause
());
}
}
catch
(
MBeanException
e
)
{
catch
(
MBeanException
e
x
)
{
throw
new
MojoExecutionException
(
e
.
getMessage
(),
e
);
throw
new
MojoExecutionException
(
e
x
.
getMessage
(),
ex
);
}
}
catch
(
IOException
e
)
{
catch
(
IOException
e
x
)
{
throw
new
MojoExecutionException
(
e
.
getMessage
(),
e
);
throw
new
MojoExecutionException
(
e
x
.
getMessage
(),
ex
);
}
}
}
}
...
@@ -99,15 +101,16 @@ class SpringApplicationLifecycleClient {
...
@@ -99,15 +101,16 @@ class SpringApplicationLifecycleClient {
* @throws IOException if an I/O error occurs
* @throws IOException if an I/O error occurs
* @throws InstanceNotFoundException if the lifecycle mbean cannot be found
* @throws InstanceNotFoundException if the lifecycle mbean cannot be found
*/
*/
public
void
stop
()
throws
MojoExecutionException
,
IOException
,
InstanceNotFoundException
{
public
void
stop
()
throws
MojoExecutionException
,
IOException
,
InstanceNotFoundException
{
try
{
try
{
this
.
mBeanServerC
onnection
.
invoke
(
this
.
objectName
,
"shutdown"
,
null
,
null
);
this
.
c
onnection
.
invoke
(
this
.
objectName
,
"shutdown"
,
null
,
null
);
}
}
catch
(
ReflectionException
e
)
{
catch
(
ReflectionException
e
x
)
{
throw
new
MojoExecutionException
(
"Shutdown failed"
,
e
.
getCause
());
throw
new
MojoExecutionException
(
"Shutdown failed"
,
e
x
.
getCause
());
}
}
catch
(
MBeanException
e
)
{
catch
(
MBeanException
e
x
)
{
throw
new
MojoExecutionException
(
"Could not invoke shutdown operation"
,
e
);
throw
new
MojoExecutionException
(
"Could not invoke shutdown operation"
,
e
x
);
}
}
}
}
...
...
spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java
View file @
bce4bb88
...
@@ -22,6 +22,8 @@ import java.net.ConnectException;
...
@@ -22,6 +22,8 @@ import java.net.ConnectException;
import
java.net.URLClassLoader
;
import
java.net.URLClassLoader
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.List
;
import
java.util.concurrent.Callable
;
import
javax.management.MBeanServerConnection
;
import
javax.management.MBeanServerConnection
;
import
javax.management.ReflectionException
;
import
javax.management.ReflectionException
;
import
javax.management.remote.JMXConnector
;
import
javax.management.remote.JMXConnector
;
...
@@ -32,15 +34,14 @@ import org.apache.maven.plugins.annotations.LifecyclePhase;
...
@@ -32,15 +34,14 @@ import org.apache.maven.plugins.annotations.LifecyclePhase;
import
org.apache.maven.plugins.annotations.Mojo
;
import
org.apache.maven.plugins.annotations.Mojo
;
import
org.apache.maven.plugins.annotations.Parameter
;
import
org.apache.maven.plugins.annotations.Parameter
;
import
org.apache.maven.plugins.annotations.ResolutionScope
;
import
org.apache.maven.plugins.annotations.ResolutionScope
;
import
org.springframework.boot.loader.tools.JavaExecutable
;
import
org.springframework.boot.loader.tools.JavaExecutable
;
import
org.springframework.boot.loader.tools.RunProcess
;
import
org.springframework.boot.loader.tools.RunProcess
;
/**
/**
* Start a spring application. Contrary to the {@code run} goal, this does not
* Start a spring application. Contrary to the {@code run} goal, this does not
block and
*
block and allows other goal to operate on the application. This goal is typically
*
allows other goal to operate on the application. This goal is typically used in
*
used in integration test scenario where the application is started before a test
*
integration test scenario where the application is started before a test suite and
* s
uite and s
topped after.
* stopped after.
*
*
* @author Stephane Nicoll
* @author Stephane Nicoll
* @since 1.3.0
* @since 1.3.0
...
@@ -54,30 +55,30 @@ public class StartMojo extends AbstractRunMojo {
...
@@ -54,30 +55,30 @@ public class StartMojo extends AbstractRunMojo {
private
static
final
String
JMX_NAME_PROPERTY_PREFIX
=
"--spring.context.lifecycle.jmx-name="
;
private
static
final
String
JMX_NAME_PROPERTY_PREFIX
=
"--spring.context.lifecycle.jmx-name="
;
/**
/**
* The JMX name of the automatically deployed MBean managing the lifecycle
* The JMX name of the automatically deployed MBean managing the lifecycle
of the
*
of the
spring application.
* spring application.
*/
*/
@Parameter
@Parameter
private
String
jmxName
=
SpringApplicationLifecycleClient
.
DEFAULT_OBJECT_NAME
;
private
String
jmxName
=
SpringApplicationLifecycleClient
.
DEFAULT_OBJECT_NAME
;
/**
/**
* The port to use to expose the platform MBeanServer if the application
* The port to use to expose the platform MBeanServer if the application
needs to be
*
needs to be
forked.
* forked.
*/
*/
@Parameter
@Parameter
private
int
jmxPort
=
9001
;
private
int
jmxPort
=
9001
;
/**
/**
* The number of milli-seconds to wait between each attempt to check if the
* The number of milli-seconds to wait between each attempt to check if the
spring
*
spring
application is ready.
* application is ready.
*/
*/
@Parameter
@Parameter
private
long
wait
=
500
;
private
long
wait
=
500
;
/**
/**
* The maximum number of attempts to check if the spring application is
* The maximum number of attempts to check if the spring application is
ready.
*
ready. Combined with the "wait" argument, this gives a global timeout
*
Combined with the "wait" argument, this gives a global timeout value (30 sec by
*
value (30 sec by
default)
* default)
*/
*/
@Parameter
@Parameter
private
int
maxAttempts
=
60
;
private
int
maxAttempts
=
60
;
...
@@ -85,26 +86,30 @@ public class StartMojo extends AbstractRunMojo {
...
@@ -85,26 +86,30 @@ public class StartMojo extends AbstractRunMojo {
private
final
Object
lock
=
new
Object
();
private
final
Object
lock
=
new
Object
();
@Override
@Override
protected
void
runWithForkedJvm
(
List
<
String
>
args
)
throws
MojoExecutionException
,
MojoFailureException
{
protected
void
runWithForkedJvm
(
List
<
String
>
args
)
throws
MojoExecutionException
,
RunProcess
runProcess
;
MojoFailureException
{
try
{
RunProcess
runProcess
=
runProcess
(
args
);
runProcess
=
new
RunProcess
(
new
JavaExecutable
().
toString
());
runProcess
.
run
(
false
,
args
.
toArray
(
new
String
[
args
.
size
()]));
}
catch
(
Exception
ex
)
{
throw
new
MojoExecutionException
(
"Could not exec java"
,
ex
);
}
try
{
try
{
waitForSpringApplication
();
waitForSpringApplication
();
}
}
catch
(
MojoExecutionException
e
)
{
catch
(
MojoExecutionException
e
x
)
{
runProcess
.
kill
();
runProcess
.
kill
();
throw
e
;
throw
e
x
;
}
}
catch
(
MojoFailureException
e
)
{
catch
(
MojoFailureException
e
x
)
{
runProcess
.
kill
();
runProcess
.
kill
();
throw
e
;
throw
ex
;
}
}
private
RunProcess
runProcess
(
List
<
String
>
args
)
throws
MojoExecutionException
{
try
{
RunProcess
runProcess
=
new
RunProcess
(
new
JavaExecutable
().
toString
());
runProcess
.
run
(
false
,
args
.
toArray
(
new
String
[
args
.
size
()]));
return
runProcess
;
}
catch
(
Exception
ex
)
{
throw
new
MojoExecutionException
(
"Could not exec java"
,
ex
);
}
}
}
}
...
@@ -113,7 +118,8 @@ public class StartMojo extends AbstractRunMojo {
...
@@ -113,7 +118,8 @@ public class StartMojo extends AbstractRunMojo {
RunArguments
applicationArguments
=
super
.
resolveApplicationArguments
();
RunArguments
applicationArguments
=
super
.
resolveApplicationArguments
();
applicationArguments
.
getArgs
().
addLast
(
ENABLE_MBEAN_PROPERTY
);
applicationArguments
.
getArgs
().
addLast
(
ENABLE_MBEAN_PROPERTY
);
if
(
isFork
())
{
if
(
isFork
())
{
applicationArguments
.
getArgs
().
addLast
(
JMX_NAME_PROPERTY_PREFIX
+
this
.
jmxName
);
applicationArguments
.
getArgs
().
addLast
(
JMX_NAME_PROPERTY_PREFIX
+
this
.
jmxName
);
}
}
return
applicationArguments
;
return
applicationArguments
;
}
}
...
@@ -124,7 +130,7 @@ public class StartMojo extends AbstractRunMojo {
...
@@ -124,7 +130,7 @@ public class StartMojo extends AbstractRunMojo {
if
(
isFork
())
{
if
(
isFork
())
{
List
<
String
>
remoteJmxArguments
=
new
ArrayList
<
String
>();
List
<
String
>
remoteJmxArguments
=
new
ArrayList
<
String
>();
remoteJmxArguments
.
add
(
"-Dcom.sun.management.jmxremote"
);
remoteJmxArguments
.
add
(
"-Dcom.sun.management.jmxremote"
);
remoteJmxArguments
.
add
(
"-Dcom.sun.management.jmxremote.port="
+
jmxPort
);
remoteJmxArguments
.
add
(
"-Dcom.sun.management.jmxremote.port="
+
this
.
jmxPort
);
remoteJmxArguments
.
add
(
"-Dcom.sun.management.jmxremote.authenticate=false"
);
remoteJmxArguments
.
add
(
"-Dcom.sun.management.jmxremote.authenticate=false"
);
remoteJmxArguments
.
add
(
"-Dcom.sun.management.jmxremote.ssl=false"
);
remoteJmxArguments
.
add
(
"-Dcom.sun.management.jmxremote.ssl=false"
);
jvmArguments
.
getArgs
().
addAll
(
remoteJmxArguments
);
jvmArguments
.
getArgs
().
addAll
(
remoteJmxArguments
);
...
@@ -132,18 +138,19 @@ public class StartMojo extends AbstractRunMojo {
...
@@ -132,18 +138,19 @@ public class StartMojo extends AbstractRunMojo {
return
jvmArguments
;
return
jvmArguments
;
}
}
@Override
protected
void
runWithMavenJvm
(
String
startClassName
,
String
...
arguments
)
throws
MojoExecutionException
{
protected
void
runWithMavenJvm
(
String
startClassName
,
String
...
arguments
)
throws
MojoExecutionException
{
IsolatedThreadGroup
threadGroup
=
new
IsolatedThreadGroup
(
startClassName
);
IsolatedThreadGroup
threadGroup
=
new
IsolatedThreadGroup
(
startClassName
);
Thread
launchThread
=
new
Thread
(
threadGroup
,
new
LaunchRunner
(
startClassName
,
Thread
launchThread
=
new
Thread
(
threadGroup
,
new
LaunchRunner
(
startClassName
,
arguments
),
startClassName
+
".main()"
);
arguments
),
startClassName
+
".main()"
);
launchThread
.
setContextClassLoader
(
new
URLClassLoader
(
getClassPathUrls
()));
launchThread
.
setContextClassLoader
(
new
URLClassLoader
(
getClassPathUrls
()));
launchThread
.
start
();
launchThread
.
start
();
waitForSpringApplication
(
this
.
wait
,
this
.
maxAttempts
);
waitForSpringApplication
(
this
.
wait
,
this
.
maxAttempts
);
}
}
private
void
waitForSpringApplication
(
long
wait
,
int
maxAttempts
)
throws
MojoExecutionException
{
private
void
waitForSpringApplication
(
long
wait
,
int
maxAttempts
)
throws
MojoExecutionException
{
SpringApplicationLifecycleClient
helper
=
new
SpringApplicationLifecycleClient
(
SpringApplicationLifecycleClient
helper
=
new
SpringApplicationLifecycleClient
(
ManagementFactory
.
getPlatformMBeanServer
(),
this
.
jmxName
);
ManagementFactory
.
getPlatformMBeanServer
(),
this
.
jmxName
);
getLog
().
debug
(
"Waiting for spring application to start..."
);
getLog
().
debug
(
"Waiting for spring application to start..."
);
...
@@ -151,21 +158,26 @@ public class StartMojo extends AbstractRunMojo {
...
@@ -151,21 +158,26 @@ public class StartMojo extends AbstractRunMojo {
if
(
helper
.
isReady
())
{
if
(
helper
.
isReady
())
{
return
;
return
;
}
}
getLog
().
debug
(
"Spring application is not ready yet, waiting "
+
wait
+
"ms (attempt "
+
(
i
+
1
)
+
")"
);
String
message
=
"Spring application is not ready yet, waiting "
+
wait
+
"ms (attempt "
+
(
i
+
1
)
+
")"
;
getLog
().
debug
(
message
);
synchronized
(
this
.
lock
)
{
synchronized
(
this
.
lock
)
{
try
{
try
{
this
.
lock
.
wait
(
wait
);
this
.
lock
.
wait
(
wait
);
}
}
catch
(
InterruptedException
e
)
{
catch
(
InterruptedException
ex
)
{
throw
new
IllegalStateException
(
"Interrupted while waiting for Spring Boot app to start."
);
throw
new
IllegalStateException
(
"Interrupted while waiting for Spring Boot app to start."
);
}
}
}
}
}
}
throw
new
MojoExecutionException
(
"Spring application did not start before the configured "
+
throw
new
MojoExecutionException
(
"timeout ("
+
(
wait
*
maxAttempts
)
+
"ms"
);
"Spring application did not start before the configured timeout ("
+
(
wait
*
maxAttempts
)
+
"ms"
);
}
}
private
void
waitForSpringApplication
()
throws
MojoFailureException
,
MojoExecutionException
{
private
void
waitForSpringApplication
()
throws
MojoFailureException
,
MojoExecutionException
{
try
{
try
{
if
(
Boolean
.
TRUE
.
equals
(
isFork
()))
{
if
(
Boolean
.
TRUE
.
equals
(
isFork
()))
{
waitForForkedSpringApplication
();
waitForForkedSpringApplication
();
...
@@ -174,114 +186,133 @@ public class StartMojo extends AbstractRunMojo {
...
@@ -174,114 +186,133 @@ public class StartMojo extends AbstractRunMojo {
doWaitForSpringApplication
(
ManagementFactory
.
getPlatformMBeanServer
());
doWaitForSpringApplication
(
ManagementFactory
.
getPlatformMBeanServer
());
}
}
}
}
catch
(
IOException
e
)
{
catch
(
IOException
ex
)
{
throw
new
MojoFailureException
(
"Could not contact Spring Boot application"
,
e
);
throw
new
MojoFailureException
(
"Could not contact Spring Boot application"
,
ex
);
}
}
catch
(
Exception
e
)
{
catch
(
Exception
ex
)
{
throw
new
MojoExecutionException
(
"Could not figure out if the application has started"
,
e
);
throw
new
MojoExecutionException
(
"Could not figure out if the application has started"
,
ex
);
}
}
}
}
private
void
waitForForkedSpringApplication
()
throws
IOException
,
MojoFailureException
,
MojoExecutionException
{
private
void
waitForForkedSpringApplication
()
throws
IOException
,
final
JMXConnector
jmxConnector
;
MojoFailureException
,
MojoExecutionException
{
try
{
try
{
getLog
().
debug
(
"Connecting to local MBeanServer at port "
+
this
.
jmxPort
);
getLog
().
debug
(
"Connecting to local MBeanServer at port "
+
this
.
jmxPort
);
jmxConnector
=
execute
(
wait
,
maxAttempts
,
new
RetryCallback
<
JMXConnector
>()
{
JMXConnector
connector
=
execute
(
this
.
wait
,
this
.
maxAttempts
,
@Override
new
CreateJmxConnector
(
this
.
jmxPort
));
public
JMXConnector
retry
()
throws
Exception
{
if
(
connector
==
null
)
{
try
{
throw
new
MojoExecutionException
(
return
SpringApplicationLifecycleClient
.
createLocalJmxConnector
(
jmxPort
);
"JMX MBean server was not reachable before the configured "
}
+
"timeout ("
+
(
this
.
wait
*
this
.
maxAttempts
)
+
"ms"
);
catch
(
IOException
e
)
{
if
(
hasCauseWithType
(
e
,
ConnectException
.
class
))
{
// Not there yet
getLog
().
debug
(
"MBean server at port "
+
jmxPort
+
" is not up yet..."
);
return
null
;
}
else
{
throw
e
;
}
}
}
});
if
(
jmxConnector
==
null
)
{
throw
new
MojoExecutionException
(
"JMX MBean server was not reachable before the configured "
+
"timeout ("
+
(
this
.
wait
*
this
.
maxAttempts
)
+
"ms"
);
}
}
getLog
().
debug
(
"Connected to local MBeanServer at port "
+
this
.
jmxPort
);
getLog
().
debug
(
"Connected to local MBeanServer at port "
+
this
.
jmxPort
);
try
{
try
{
MBeanServerConnection
mBeanServerConnection
=
jmxC
onnector
.
getMBeanServerConnection
();
MBeanServerConnection
connection
=
c
onnector
.
getMBeanServerConnection
();
doWaitForSpringApplication
(
mBeanServerC
onnection
);
doWaitForSpringApplication
(
c
onnection
);
}
}
finally
{
finally
{
jmxC
onnector
.
close
();
c
onnector
.
close
();
}
}
}
}
catch
(
IOException
e
)
{
catch
(
IOException
e
x
)
{
throw
e
;
throw
e
x
;
}
}
catch
(
Exception
e
)
{
catch
(
Exception
ex
)
{
throw
new
MojoExecutionException
(
"Failed to connect to MBean server at port "
+
this
.
jmxPort
,
e
);
throw
new
MojoExecutionException
(
"Failed to connect to MBean server at port "
+
this
.
jmxPort
,
ex
);
}
}
}
}
private
void
doWaitForSpringApplication
(
MBeanServerConnection
connection
)
private
void
doWaitForSpringApplication
(
MBeanServerConnection
connection
)
throws
IOException
,
MojoExecutionException
,
MojoFailureException
{
throws
IOException
,
MojoExecutionException
,
MojoFailureException
{
final
SpringApplicationLifecycleClient
client
=
new
SpringApplicationLifecycleClient
(
final
SpringApplicationLifecycleClient
client
=
connection
,
this
.
jmxName
);
new
SpringApplicationLifecycleClient
(
connection
,
this
.
jmxName
);
try
{
try
{
execute
(
this
.
wait
,
this
.
maxAttempts
,
new
RetryCallback
<
Boolean
>()
{
execute
(
this
.
wait
,
this
.
maxAttempts
,
new
Callable
<
Boolean
>()
{
@Override
@Override
public
Boolean
retry
()
throws
Exception
{
public
Boolean
call
()
throws
Exception
{
boolean
ready
=
client
.
isReady
();
return
(
client
.
isReady
()
?
true
:
null
);
// Wait until the app is ready
return
(
ready
?
true
:
null
);
}
}
});
});
}
}
catch
(
ReflectionException
e
)
{
catch
(
ReflectionException
ex
)
{
throw
new
MojoExecutionException
(
"Unable to retrieve Ready attribute"
,
e
.
getCause
());
throw
new
MojoExecutionException
(
"Unable to retrieve 'ready' attribute"
,
ex
.
getCause
());
}
}
catch
(
Exception
e
)
{
catch
(
Exception
e
x
)
{
throw
new
MojoFailureException
(
"Could not invoke shutdown operation"
,
e
);
throw
new
MojoFailureException
(
"Could not invoke shutdown operation"
,
e
x
);
}
}
}
}
public
<
T
>
T
execute
(
long
wait
,
int
maxAttempts
,
RetryCallback
<
T
>
callback
)
throws
Exception
{
/**
* Execute a task, retrying it on failure.
* @param wait the wait time
* @param maxAttempts the maximum number of attempts
* @param callback the task to execute (possibly multiple times). The callback should
* return {@code null} to indicate that another attempt should be made
* @return the result
* @throws Exception
*/
public
<
T
>
T
execute
(
long
wait
,
int
maxAttempts
,
Callable
<
T
>
callback
)
throws
Exception
{
getLog
().
debug
(
"Waiting for spring application to start..."
);
getLog
().
debug
(
"Waiting for spring application to start..."
);
for
(
int
i
=
0
;
i
<
maxAttempts
;
i
++)
{
for
(
int
i
=
0
;
i
<
maxAttempts
;
i
++)
{
T
result
=
callback
.
retry
();
T
result
=
callback
.
call
();
if
(
result
!=
null
)
{
if
(
result
!=
null
)
{
return
result
;
return
result
;
}
}
getLog
().
debug
(
"Spring application is not ready yet, waiting "
+
wait
+
"ms (attempt "
+
(
i
+
1
)
+
")"
);
String
message
=
"Spring application is not ready yet, waiting "
+
wait
+
"ms (attempt "
+
(
i
+
1
)
+
")"
;
getLog
().
debug
(
message
);
synchronized
(
this
.
lock
)
{
synchronized
(
this
.
lock
)
{
try
{
try
{
this
.
lock
.
wait
(
wait
);
this
.
lock
.
wait
(
wait
);
}
}
catch
(
InterruptedException
e
)
{
catch
(
InterruptedException
ex
)
{
throw
new
IllegalStateException
(
"Interrupted while waiting for Spring Boot app to start."
);
throw
new
IllegalStateException
(
"Interrupted while waiting for Spring Boot app to start."
);
}
}
}
}
}
}
throw
new
MojoExecutionException
(
"Spring application did not start before the configured "
+
throw
new
MojoExecutionException
(
"timeout ("
+
(
wait
*
maxAttempts
)
+
"ms"
);
"Spring application did not start before the configured "
+
"timeout ("
+
(
wait
*
maxAttempts
)
+
"ms"
);
}
}
private
static
boolean
hasCauseWithType
(
Throwable
t
,
Class
<?
extends
Exception
>
type
)
{
private
class
CreateJmxConnector
implements
Callable
<
JMXConnector
>
{
return
type
.
isAssignableFrom
(
t
.
getClass
())
||
t
.
getCause
()
!=
null
&&
hasCauseWithType
(
t
.
getCause
(),
type
);
}
private
final
int
port
;
public
CreateJmxConnector
(
int
port
)
{
this
.
port
=
port
;
}
@Override
public
JMXConnector
call
()
throws
Exception
{
try
{
return
SpringApplicationLifecycleClient
.
createLocalJmxConnector
(
this
.
port
);
}
catch
(
IOException
ex
)
{
if
(
hasCauseWithType
(
ex
,
ConnectException
.
class
))
{
String
message
=
"MBean server at port "
+
this
.
port
+
" is not up yet..."
;
getLog
().
debug
(
message
);
return
null
;
}
throw
ex
;
}
}
interface
RetryCallback
<
T
>
{
private
boolean
hasCauseWithType
(
Throwable
t
,
Class
<?
extends
Exception
>
type
)
{
return
type
.
isAssignableFrom
(
t
.
getClass
())
||
t
.
getCause
()
!=
null
&&
hasCauseWithType
(
t
.
getCause
(),
type
);
}
/**
* Attempt to execute an operation. Throws an exception in case of fatal
* exception, returns {@code null} to indicate another attempt should be
* made if possible.
*/
T
retry
()
throws
Exception
;
}
}
}
}
spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StopMojo.java
View file @
bce4bb88
...
@@ -18,6 +18,7 @@ package org.springframework.boot.maven;
...
@@ -18,6 +18,7 @@ package org.springframework.boot.maven;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.lang.management.ManagementFactory
;
import
java.lang.management.ManagementFactory
;
import
javax.management.InstanceNotFoundException
;
import
javax.management.InstanceNotFoundException
;
import
javax.management.MBeanServerConnection
;
import
javax.management.MBeanServerConnection
;
import
javax.management.remote.JMXConnector
;
import
javax.management.remote.JMXConnector
;
...
@@ -40,23 +41,23 @@ import org.apache.maven.plugins.annotations.Parameter;
...
@@ -40,23 +41,23 @@ import org.apache.maven.plugins.annotations.Parameter;
public
class
StopMojo
extends
AbstractMojo
{
public
class
StopMojo
extends
AbstractMojo
{
/**
/**
* Flag to indicate if the run processes should be forked. Must be aligned to the
value
* Flag to indicate if the run processes should be forked. Must be aligned to the
* used to {@link StartMojo start} the process
*
value
used to {@link StartMojo start} the process
* @since 1.2
* @since 1.2
*/
*/
@Parameter
(
property
=
"fork"
)
@Parameter
(
property
=
"fork"
)
private
Boolean
fork
;
private
Boolean
fork
;
/**
/**
* The JMX name of the automatically deployed MBean managing the lifecycle
* The JMX name of the automatically deployed MBean managing the lifecycle
of the
*
of the
application.
* application.
*/
*/
@Parameter
@Parameter
private
String
jmxName
=
SpringApplicationLifecycleClient
.
DEFAULT_OBJECT_NAME
;
private
String
jmxName
=
SpringApplicationLifecycleClient
.
DEFAULT_OBJECT_NAME
;
/**
/**
* The port to use to lookup the platform MBeanServer if the application
* The port to use to lookup the platform MBeanServer if the application
has been
*
has been
forked.
* forked.
*/
*/
@Parameter
@Parameter
private
int
jmxPort
=
9001
;
private
int
jmxPort
=
9001
;
...
@@ -72,36 +73,38 @@ public class StopMojo extends AbstractMojo {
...
@@ -72,36 +73,38 @@ public class StopMojo extends AbstractMojo {
stop
();
stop
();
}
}
}
}
catch
(
IOException
e
)
{
catch
(
IOException
e
x
)
{
// The response won't be received as the server has died - ignoring
// The response won't be received as the server has died - ignoring
getLog
().
debug
(
"Service is not reachable anymore ("
+
e
.
getMessage
()
+
")"
);
getLog
().
debug
(
"Service is not reachable anymore ("
+
e
x
.
getMessage
()
+
")"
);
}
}
}
}
private
void
stop
()
throws
IOException
,
MojoFailureException
,
MojoExecutionException
{
private
void
stopForkedProcess
()
throws
IOException
,
MojoFailureException
,
doStop
(
ManagementFactory
.
getPlatformMBeanServer
());
MojoExecutionException
{
}
JMXConnector
connector
=
SpringApplicationLifecycleClient
.
createLocalJmxConnector
(
this
.
jmxPort
);
private
void
stopForkedProcess
()
throws
IOException
,
MojoFailureException
,
MojoExecutionException
{
JMXConnector
jmxConnector
=
SpringApplicationLifecycleClient
.
createLocalJmxConnector
(
this
.
jmxPort
);
try
{
try
{
MBeanServerConnection
mBeanServerConnection
=
jmxC
onnector
.
getMBeanServerConnection
();
MBeanServerConnection
connection
=
c
onnector
.
getMBeanServerConnection
();
doStop
(
mBeanServerC
onnection
);
doStop
(
c
onnection
);
}
}
finally
{
finally
{
jmxC
onnector
.
close
();
c
onnector
.
close
();
}
}
}
}
private
void
doStop
(
MBeanServerConnection
connection
)
private
void
stop
()
throws
IOException
,
MojoFailureException
,
MojoExecutionException
{
throws
IOException
,
MojoExecutionException
{
doStop
(
ManagementFactory
.
getPlatformMBeanServer
());
SpringApplicationLifecycleClient
helper
=
new
SpringApplicationLifecycleClient
(
connection
,
this
.
jmxName
);
}
private
void
doStop
(
MBeanServerConnection
connection
)
throws
IOException
,
MojoExecutionException
{
try
{
try
{
helper
.
stop
();
new
SpringApplicationLifecycleClient
(
connection
,
this
.
jmxName
)
.
stop
();
}
}
catch
(
InstanceNotFoundException
e
)
{
catch
(
InstanceNotFoundException
ex
)
{
throw
new
MojoExecutionException
(
"Spring application lifecycle JMX bean not found (fork is "
+
throw
new
MojoExecutionException
(
""
+
this
.
fork
+
"). Could not stop application gracefully"
,
e
);
"Spring application lifecycle JMX bean not found (fork is "
+
""
+
this
.
fork
+
"). Could not stop application gracefully"
,
ex
);
}
}
}
}
...
...
spring-boot/src/main/java/org/springframework/boot/context/SpringApplicationLifecycleRegistrar.java
View file @
bce4bb88
...
@@ -17,13 +17,13 @@
...
@@ -17,13 +17,13 @@
package
org
.
springframework
.
boot
.
context
;
package
org
.
springframework
.
boot
.
context
;
import
java.lang.management.ManagementFactory
;
import
java.lang.management.ManagementFactory
;
import
javax.management.MBeanServer
;
import
javax.management.MBeanServer
;
import
javax.management.MalformedObjectNameException
;
import
javax.management.MalformedObjectNameException
;
import
javax.management.ObjectName
;
import
javax.management.ObjectName
;
import
org.apache.commons.logging.Log
;
import
org.apache.commons.logging.Log
;
import
org.apache.commons.logging.LogFactory
;
import
org.apache.commons.logging.LogFactory
;
import
org.springframework.beans.BeansException
;
import
org.springframework.beans.BeansException
;
import
org.springframework.beans.factory.DisposableBean
;
import
org.springframework.beans.factory.DisposableBean
;
import
org.springframework.beans.factory.InitializingBean
;
import
org.springframework.beans.factory.InitializingBean
;
...
@@ -52,50 +52,51 @@ public class SpringApplicationLifecycleRegistrar implements ApplicationContextAw
...
@@ -52,50 +52,51 @@ public class SpringApplicationLifecycleRegistrar implements ApplicationContextAw
private
boolean
ready
=
false
;
private
boolean
ready
=
false
;
public
SpringApplicationLifecycleRegistrar
(
String
name
)
throws
MalformedObjectNameException
{
public
SpringApplicationLifecycleRegistrar
(
String
name
)
throws
MalformedObjectNameException
{
this
.
objectName
=
new
ObjectName
(
name
);
this
.
objectName
=
new
ObjectName
(
name
);
}
}
@Override
@Override
public
void
setApplicationContext
(
ApplicationContext
applicationContext
)
throws
BeansException
{
public
void
setApplicationContext
(
ApplicationContext
applicationContext
)
Assert
.
isTrue
(
applicationContext
instanceof
ConfigurableApplicationContext
,
throws
BeansException
{
Assert
.
state
(
applicationContext
instanceof
ConfigurableApplicationContext
,
"ApplicationContext does not implement ConfigurableApplicationContext"
);
"ApplicationContext does not implement ConfigurableApplicationContext"
);
this
.
applicationContext
=
(
ConfigurableApplicationContext
)
applicationContext
;
this
.
applicationContext
=
(
ConfigurableApplicationContext
)
applicationContext
;
}
}
@Override
@Override
public
void
onApplicationEvent
(
ApplicationReadyEvent
event
)
{
public
void
onApplicationEvent
(
ApplicationReadyEvent
event
)
{
ready
=
true
;
this
.
ready
=
true
;
}
}
@Override
@Override
public
void
afterPropertiesSet
()
throws
Exception
{
public
void
afterPropertiesSet
()
throws
Exception
{
MBeanServer
server
=
ManagementFactory
.
getPlatformMBeanServer
();
MBeanServer
server
=
ManagementFactory
.
getPlatformMBeanServer
();
server
.
registerMBean
(
new
SpringApplicationLifecycle
(),
objectName
);
server
.
registerMBean
(
new
SpringApplicationLifecycle
(),
this
.
objectName
);
if
(
logger
.
isDebugEnabled
())
{
if
(
logger
.
isDebugEnabled
())
{
logger
.
debug
(
"Application lifecycle MBean registered with name '"
+
objectName
+
"'"
);
logger
.
debug
(
"Application lifecycle MBean registered with name '"
+
this
.
objectName
+
"'"
);
}
}
}
}
@Override
@Override
public
void
destroy
()
throws
Exception
{
public
void
destroy
()
throws
Exception
{
ManagementFactory
.
getPlatformMBeanServer
().
unregisterMBean
(
objectName
);
ManagementFactory
.
getPlatformMBeanServer
().
unregisterMBean
(
this
.
objectName
);
}
}
private
class
SpringApplicationLifecycle
implements
SpringApplicationLifecycleMXBean
{
private
class
SpringApplicationLifecycle
implements
SpringApplicationLifecycleMXBean
{
@Override
@Override
public
boolean
isReady
()
{
public
boolean
isReady
()
{
return
ready
;
return
SpringApplicationLifecycleRegistrar
.
this
.
ready
;
}
}
@Override
@Override
public
void
shutdown
()
{
public
void
shutdown
()
{
logger
.
info
(
"Application shutdown requested."
);
logger
.
info
(
"Application shutdown requested."
);
applicationContext
.
close
();
SpringApplicationLifecycleRegistrar
.
this
.
applicationContext
.
close
();
}
}
}
}
}
}
spring-boot/src/test/java/org/springframework/boot/context/SpringApplicationLifecycleRegistrarTests.java
View file @
bce4bb88
...
@@ -17,6 +17,7 @@
...
@@ -17,6 +17,7 @@
package
org
.
springframework
.
boot
.
context
;
package
org
.
springframework
.
boot
.
context
;
import
java.lang.management.ManagementFactory
;
import
java.lang.management.ManagementFactory
;
import
javax.management.InstanceNotFoundException
;
import
javax.management.InstanceNotFoundException
;
import
javax.management.MBeanServer
;
import
javax.management.MBeanServer
;
import
javax.management.MalformedObjectNameException
;
import
javax.management.MalformedObjectNameException
;
...
@@ -27,7 +28,6 @@ import org.junit.Before;
...
@@ -27,7 +28,6 @@ import org.junit.Before;
import
org.junit.Rule
;
import
org.junit.Rule
;
import
org.junit.Test
;
import
org.junit.Test
;
import
org.junit.rules.ExpectedException
;
import
org.junit.rules.ExpectedException
;
import
org.springframework.boot.SpringApplication
;
import
org.springframework.boot.SpringApplication
;
import
org.springframework.context.ApplicationListener
;
import
org.springframework.context.ApplicationListener
;
import
org.springframework.context.ConfigurableApplicationContext
;
import
org.springframework.context.ConfigurableApplicationContext
;
...
@@ -75,15 +75,18 @@ public class SpringApplicationLifecycleRegistrarTests {
...
@@ -75,15 +75,18 @@ public class SpringApplicationLifecycleRegistrarTests {
@Override
@Override
public
void
onApplicationEvent
(
ContextRefreshedEvent
event
)
{
public
void
onApplicationEvent
(
ContextRefreshedEvent
event
)
{
try
{
try
{
assertFalse
(
"Application should not be ready yet"
,
isCurrentApplicationReady
(
objectName
));
assertFalse
(
"Application should not be ready yet"
,
isCurrentApplicationReady
(
objectName
));
}
}
catch
(
Exception
e
)
{
catch
(
Exception
ex
)
{
throw
new
IllegalStateException
(
"Could not contact spring application lifecycle bean"
,
e
);
throw
new
IllegalStateException
(
"Could not contact spring application lifecycle bean"
,
ex
);
}
}
}
}
});
});
this
.
context
=
application
.
run
();
this
.
context
=
application
.
run
();
assertTrue
(
"application should be ready now"
,
isCurrentApplicationReady
(
objectName
));
assertTrue
(
"application should be ready now"
,
isCurrentApplicationReady
(
objectName
));
}
}
@Test
@Test
...
@@ -95,8 +98,7 @@ public class SpringApplicationLifecycleRegistrarTests {
...
@@ -95,8 +98,7 @@ public class SpringApplicationLifecycleRegistrarTests {
assertTrue
(
"application should be running"
,
this
.
context
.
isRunning
());
assertTrue
(
"application should be running"
,
this
.
context
.
isRunning
());
invokeShutdown
(
objectName
);
invokeShutdown
(
objectName
);
assertFalse
(
"application should not be running"
,
this
.
context
.
isRunning
());
assertFalse
(
"application should not be running"
,
this
.
context
.
isRunning
());
this
.
thrown
.
expect
(
InstanceNotFoundException
.
class
);
// JMX cleanup
thrown
.
expect
(
InstanceNotFoundException
.
class
);
// JMX cleanup
this
.
mBeanServer
.
getObjectInstance
(
objectName
);
this
.
mBeanServer
.
getObjectInstance
(
objectName
);
}
}
...
@@ -127,16 +129,15 @@ public class SpringApplicationLifecycleRegistrarTests {
...
@@ -127,16 +129,15 @@ public class SpringApplicationLifecycleRegistrarTests {
}
}
}
}
@Configuration
@Configuration
static
class
Config
{
static
class
Config
{
@Bean
@Bean
public
SpringApplicationLifecycleRegistrar
springApplicationLifecycle
()
public
SpringApplicationLifecycleRegistrar
springApplicationLifecycle
()
throws
MalformedObjectNameException
{
throws
MalformedObjectNameException
{
return
new
SpringApplicationLifecycleRegistrar
(
OBJECT_NAME
);
return
new
SpringApplicationLifecycleRegistrar
(
OBJECT_NAME
);
}
}
}
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment