Support PID file location in Spring Environment
Update ApplicationPidFileWriter to support the Spring Environment, picking up the `spring.application.pidfile` property if specified. Fixes gh-1579
This commit is contained in:
parent
f9fe8ed55e
commit
026b89f58c
|
|
@ -17,20 +17,27 @@
|
|||
package org.springframework.boot.actuate.system;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.boot.ApplicationPid;
|
||||
import org.springframework.boot.context.event.ApplicationStartedEvent;
|
||||
import org.springframework.boot.bind.RelaxedPropertyResolver;
|
||||
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
|
||||
import org.springframework.boot.context.event.ApplicationPreparedEvent;
|
||||
import org.springframework.boot.context.event.SpringApplicationEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* An {@link ApplicationListener} that saves application PID into file. This application
|
||||
* listener will be triggered exactly once per JVM, and the file name can be overridden at
|
||||
* runtime with a System property or environment variable named "PIDFILE" (or "pidfile").
|
||||
* runtime with a System property or environment variable named "PIDFILE" (or "pidfile")
|
||||
* or using a {@code spring.application.pidfile} property in the Spring
|
||||
* {@link Environment}.
|
||||
*
|
||||
* @author Jakub Kubrynski
|
||||
* @author Dave Syer
|
||||
|
|
@ -38,13 +45,15 @@ import org.springframework.util.Assert;
|
|||
* @since 1.2.0
|
||||
*/
|
||||
public class ApplicationPidFileWriter implements
|
||||
ApplicationListener<ApplicationStartedEvent>, Ordered {
|
||||
ApplicationListener<SpringApplicationEvent>, Ordered {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(ApplicationPidFileWriter.class);
|
||||
|
||||
private static final String DEFAULT_FILE_NAME = "application.pid";
|
||||
|
||||
private static final String[] PROPERTY_VARIABLES = { "PIDFILE", "pidfile" };
|
||||
private static final String[] SYSTEM_PROPERTY_VARIABLES = { "PIDFILE", "pidfile" };
|
||||
|
||||
private static final String SPRING_PROPERTY = "spring.application.pidfile";
|
||||
|
||||
private static final AtomicBoolean created = new AtomicBoolean(false);
|
||||
|
||||
|
|
@ -52,12 +61,14 @@ public class ApplicationPidFileWriter implements
|
|||
|
||||
private final File file;
|
||||
|
||||
private Class<? extends SpringApplicationEvent> triggerEventType = ApplicationPreparedEvent.class;
|
||||
|
||||
/**
|
||||
* Create a new {@link ApplicationPidFileWriter} instance using the filename
|
||||
* 'application.pid'.
|
||||
*/
|
||||
public ApplicationPidFileWriter() {
|
||||
this.file = new File(DEFAULT_FILE_NAME);
|
||||
this(new File(DEFAULT_FILE_NAME));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -74,28 +85,66 @@ public class ApplicationPidFileWriter implements
|
|||
*/
|
||||
public ApplicationPidFileWriter(File file) {
|
||||
Assert.notNull(file, "File must not be null");
|
||||
String override = SystemProperties.get(PROPERTY_VARIABLES);
|
||||
if (override != null) {
|
||||
this.file = new File(override);
|
||||
}
|
||||
else {
|
||||
this.file = file;
|
||||
}
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the type of application event that will trigger writing of the PID file.
|
||||
* Defaults to {@link ApplicationPreparedEvent}. NOTE: If you use the
|
||||
* {@link ApplicationPreparedEvent} to trigger the write, you will not be able to
|
||||
* specify the PID filename in the Spring {@link Environment}.
|
||||
*/
|
||||
public void setTriggerEventType(
|
||||
Class<? extends SpringApplicationEvent> triggerEventType) {
|
||||
Assert.notNull(triggerEventType, "Trigger event type must not be null");
|
||||
this.triggerEventType = triggerEventType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationStartedEvent event) {
|
||||
if (created.compareAndSet(false, true)) {
|
||||
try {
|
||||
new ApplicationPid().write(this.file);
|
||||
this.file.deleteOnExit();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
logger.warn(String.format("Cannot create pid file %s", this.file));
|
||||
public void onApplicationEvent(SpringApplicationEvent event) {
|
||||
if (this.triggerEventType.isInstance(event)) {
|
||||
if (created.compareAndSet(false, true)) {
|
||||
try {
|
||||
writePidFile(event);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
logger.warn(String.format("Cannot create pid file %s", this.file));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void writePidFile(SpringApplicationEvent event) throws IOException {
|
||||
File pidFile = this.file;
|
||||
String override = SystemProperties.get(SYSTEM_PROPERTY_VARIABLES);
|
||||
if (override != null) {
|
||||
pidFile = new File(override);
|
||||
}
|
||||
else {
|
||||
Environment environment = getEnvironment(event);
|
||||
if (environment != null) {
|
||||
override = new RelaxedPropertyResolver(environment)
|
||||
.getProperty(SPRING_PROPERTY);
|
||||
if (override != null) {
|
||||
pidFile = new File(override);
|
||||
}
|
||||
}
|
||||
}
|
||||
new ApplicationPid().write(pidFile);
|
||||
pidFile.deleteOnExit();
|
||||
}
|
||||
|
||||
private Environment getEnvironment(SpringApplicationEvent event) {
|
||||
if (event instanceof ApplicationEnvironmentPreparedEvent) {
|
||||
return ((ApplicationEnvironmentPreparedEvent) event).getEnvironment();
|
||||
}
|
||||
if (event instanceof ApplicationPreparedEvent) {
|
||||
return ((ApplicationPreparedEvent) event).getApplicationContext()
|
||||
.getEnvironment();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,10 @@
|
|||
|
||||
package org.springframework.boot.actuate.system;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.springframework.boot.context.event.ApplicationStartedEvent;
|
||||
|
||||
/**
|
||||
* An {@link org.springframework.context.ApplicationListener} that saves application PID
|
||||
* into file. This application listener will be triggered exactly once per JVM, and the
|
||||
|
|
@ -31,4 +35,19 @@ package org.springframework.boot.actuate.system;
|
|||
@Deprecated
|
||||
public class ApplicationPidListener extends ApplicationPidFileWriter {
|
||||
|
||||
public ApplicationPidListener() {
|
||||
super();
|
||||
setTriggerEventType(ApplicationStartedEvent.class);
|
||||
}
|
||||
|
||||
public ApplicationPidListener(File file) {
|
||||
super(file);
|
||||
setTriggerEventType(ApplicationStartedEvent.class);
|
||||
}
|
||||
|
||||
public ApplicationPidListener(String filename) {
|
||||
super(filename);
|
||||
setTriggerEventType(ApplicationStartedEvent.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,23 +25,33 @@ import org.junit.Rule;
|
|||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
|
||||
import org.springframework.boot.context.event.ApplicationPreparedEvent;
|
||||
import org.springframework.boot.context.event.ApplicationStartedEvent;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.StandardEnvironment;
|
||||
import org.springframework.mock.env.MockPropertySource;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
import static org.hamcrest.Matchers.isEmptyString;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link ApplicationPidFileWriter}.
|
||||
*
|
||||
* @author Jakub Kubrynski
|
||||
* @author Dave Syer
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class ApplicationPidFileWriterTests {
|
||||
|
||||
private static final ApplicationStartedEvent EVENT = new ApplicationStartedEvent(
|
||||
new SpringApplication(), new String[] {});
|
||||
private static final ApplicationPreparedEvent EVENT = new ApplicationPreparedEvent(
|
||||
new SpringApplication(), new String[] {},
|
||||
mock(ConfigurableApplicationContext.class));
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||
|
|
@ -72,4 +82,47 @@ public class ApplicationPidFileWriterTests {
|
|||
not(isEmptyString()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void overridePidFileWithSpring() throws Exception {
|
||||
File file = this.temporaryFolder.newFile();
|
||||
ConfigurableEnvironment environment = new StandardEnvironment();
|
||||
MockPropertySource propertySource = new MockPropertySource();
|
||||
propertySource.setProperty("spring.application.pidfile", file.getAbsolutePath());
|
||||
environment.getPropertySources().addLast(propertySource);
|
||||
ConfigurableApplicationContext context = mock(ConfigurableApplicationContext.class);
|
||||
given(context.getEnvironment()).willReturn(environment);
|
||||
ApplicationPreparedEvent event = new ApplicationPreparedEvent(
|
||||
new SpringApplication(), new String[] {}, context);
|
||||
ApplicationPidFileWriter listener = new ApplicationPidFileWriter();
|
||||
listener.onApplicationEvent(event);
|
||||
assertThat(FileCopyUtils.copyToString(new FileReader(file)), not(isEmptyString()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void differentEventTypes() throws Exception {
|
||||
File file = this.temporaryFolder.newFile();
|
||||
ConfigurableEnvironment environment = new StandardEnvironment();
|
||||
MockPropertySource propertySource = new MockPropertySource();
|
||||
propertySource.setProperty("spring.application.pidfile", file.getAbsolutePath());
|
||||
environment.getPropertySources().addLast(propertySource);
|
||||
ApplicationEnvironmentPreparedEvent event = new ApplicationEnvironmentPreparedEvent(
|
||||
new SpringApplication(), new String[] {}, environment);
|
||||
ApplicationPidFileWriter listener = new ApplicationPidFileWriter();
|
||||
listener.onApplicationEvent(event);
|
||||
assertThat(FileCopyUtils.copyToString(new FileReader(file)), isEmptyString());
|
||||
listener.setTriggerEventType(ApplicationEnvironmentPreparedEvent.class);
|
||||
listener.onApplicationEvent(event);
|
||||
assertThat(FileCopyUtils.copyToString(new FileReader(file)), not(isEmptyString()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withNoEnvironment() throws Exception {
|
||||
File file = this.temporaryFolder.newFile();
|
||||
ApplicationPidFileWriter listener = new ApplicationPidFileWriter(file);
|
||||
listener.setTriggerEventType(ApplicationStartedEvent.class);
|
||||
listener.onApplicationEvent(new ApplicationStartedEvent(new SpringApplication(),
|
||||
new String[] {}));
|
||||
assertThat(FileCopyUtils.copyToString(new FileReader(file)), not(isEmptyString()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue