Skip to content

Commit ebf129c

Browse files
author
Gong Yi
committed
Add new RESTART strategy
1 parent e22686f commit ebf129c

File tree

12 files changed

+146
-49
lines changed

12 files changed

+146
-49
lines changed

.mvn/wrapper/MavenWrapperDownloader.java

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,35 +19,37 @@
1919
public class MavenWrapperDownloader {
2020

2121
private static final String WRAPPER_VERSION = "0.5.6";
22+
2223
/**
23-
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
24+
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is
25+
* provided.
2426
*/
2527
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
2628
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
2729

2830
/**
29-
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
30-
* use instead of the default one.
31+
* Path to the maven-wrapper.properties file, which might contain a downloadUrl
32+
* property to use instead of the default one.
3133
*/
32-
private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
33-
".mvn/wrapper/maven-wrapper.properties";
34+
private static final String MAVEN_WRAPPER_PROPERTIES_PATH = ".mvn/wrapper/maven-wrapper.properties";
3435

3536
/**
3637
* Path where the maven-wrapper.jar will be saved to.
3738
*/
38-
private static final String MAVEN_WRAPPER_JAR_PATH =
39-
".mvn/wrapper/maven-wrapper.jar";
39+
private static final String MAVEN_WRAPPER_JAR_PATH = ".mvn/wrapper/maven-wrapper.jar";
4040

4141
/**
42-
* Name of the property which should be used to override the default download url for the wrapper.
42+
* Name of the property which should be used to override the default download url for
43+
* the wrapper.
4344
*/
4445
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
4546

4647
public static void main(String args[]) {
4748
System.out.println("- Downloader started");
4849
File baseDirectory = new File(args[0]);
4950
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
50-
// If the maven-wrapper.properties exists, read it and check if it contains a custom
51+
// If the maven-wrapper.properties exists, read it and check if it contains a
52+
// custom
5153
// wrapperUrl parameter.
5254
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
5355
String url = DEFAULT_DOWNLOAD_URL;
@@ -58,14 +60,17 @@ public static void main(String args[]) {
5860
Properties mavenWrapperProperties = new Properties();
5961
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
6062
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
61-
} catch (IOException e) {
63+
}
64+
catch (IOException e) {
6265
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
63-
} finally {
66+
}
67+
finally {
6468
try {
6569
if (mavenWrapperPropertyFileInputStream != null) {
6670
mavenWrapperPropertyFileInputStream.close();
6771
}
68-
} catch (IOException e) {
72+
}
73+
catch (IOException e) {
6974
// Ignore ...
7075
}
7176
}
@@ -83,7 +88,8 @@ public static void main(String args[]) {
8388
downloadFileFromURL(url, outputFile);
8489
System.out.println("Done");
8590
System.exit(0);
86-
} catch (Throwable e) {
91+
}
92+
catch (Throwable e) {
8793
System.out.println("- Error downloading");
8894
e.printStackTrace();
8995
System.exit(1);

pom.xml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
34
<modelVersion>4.0.0</modelVersion>
45
<parent>
56
<groupId>org.springframework.cloud</groupId>
@@ -122,6 +123,14 @@
122123
<groupId>com.github.spotbugs</groupId>
123124
<artifactId>spotbugs-maven-plugin</artifactId>
124125
<version>4.0.0</version>
126+
<dependencies>
127+
<!-- overwrite dependency on spotbugs if you want to specify the version of spotbugs -->
128+
<dependency>
129+
<groupId>com.github.spotbugs</groupId>
130+
<artifactId>spotbugs</artifactId>
131+
<version>4.0.4</version>
132+
</dependency>
133+
</dependencies>
125134
<executions>
126135
<execution>
127136
<goals>
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
http.name=hello
1+
http.name=hell23

propertysource-reload-example/pom.xml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
34
<modelVersion>4.0.0</modelVersion>
45
<parent>
56
<groupId>io.github.topikachu</groupId>
@@ -28,7 +29,10 @@
2829
<groupId>org.springframework.cloud</groupId>
2930
<artifactId>spring-cloud-starter</artifactId>
3031
</dependency>
31-
32+
<dependency>
33+
<groupId>org.springframework.boot</groupId>
34+
<artifactId>spring-boot-starter-actuator</artifactId>
35+
</dependency>
3236
<dependency>
3337
<groupId>org.projectlombok</groupId>
3438
<artifactId>lombok</artifactId>

propertysource-reload-example/src/main/java/io/github/topikachu/properties/reload/example/web/DemoController.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
import org.springframework.web.bind.annotation.GetMapping;
1111
import org.springframework.web.bind.annotation.RestController;
1212

13+
import javax.annotation.PostConstruct;
14+
1315
@RestController
1416
@RefreshScope
1517
public class DemoController {
@@ -36,4 +38,16 @@ public void onRefresh(PropertySourceReloadEvent event) {
3638
System.out.println(event.getFileEvent());
3739
}
3840

41+
@PostConstruct
42+
public void init() {
43+
new Thread(() -> {
44+
try {
45+
Thread.sleep(3600000);
46+
}
47+
catch (InterruptedException e) {
48+
e.printStackTrace();
49+
}
50+
}).start();
51+
}
52+
3953
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
propertysource.reload.properties-files=config/foo.properties,config/bar.properties,config/foo.yaml,config/a.properties
2-
2+
propertysource.reload.strategy=restart
3+
management.endpoint.restart.enabled=true

propertysource-reload-spring-boot-starter/pom.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
34
<modelVersion>4.0.0</modelVersion>
45
<parent>
56
<groupId>io.github.topikachu</groupId>

propertysource-reload-spring-boot-starter/src/main/java/io/github/topikachu/properties/reload/BootstrapConfiguration.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@
33
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
44
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
55
import org.springframework.boot.context.properties.EnableConfigurationProperties;
6-
import org.springframework.cloud.context.config.annotation.RefreshScope;
6+
import org.springframework.cloud.context.refresh.ContextRefresher;
7+
import org.springframework.cloud.context.restart.RestartEndpoint;
78
import org.springframework.context.annotation.Bean;
89
import org.springframework.context.annotation.Configuration;
910
import org.springframework.core.io.ResourceLoader;
1011

1112
@Configuration(proxyBeanMethods = false)
1213
@ConditionalOnProperty(value = "propertysource.reload.enabled", matchIfMissing = true)
13-
@ConditionalOnClass(RefreshScope.class)
14+
@ConditionalOnClass({ ContextRefresher.class, RestartEndpoint.class })
1415
public class BootstrapConfiguration {
1516

1617
@EnableConfigurationProperties(ReloadableProperties.class)

propertysource-reload-spring-boot-starter/src/main/java/io/github/topikachu/properties/reload/ConfigReloadAutoConfiguration.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
package io.github.topikachu.properties.reload;
22

3+
import org.springframework.beans.factory.annotation.Autowired;
34
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
45
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
56
import org.springframework.boot.context.properties.EnableConfigurationProperties;
6-
import org.springframework.cloud.context.config.annotation.RefreshScope;
77
import org.springframework.cloud.context.refresh.ContextRefresher;
8+
import org.springframework.cloud.context.restart.RestartEndpoint;
89
import org.springframework.context.ApplicationEventPublisher;
910
import org.springframework.context.ConfigurableApplicationContext;
1011
import org.springframework.context.annotation.Bean;
@@ -13,7 +14,7 @@
1314

1415
@Configuration(proxyBeanMethods = false)
1516
@ConditionalOnProperty(value = "propertysource.reload.enabled", matchIfMissing = true)
16-
@ConditionalOnClass(RefreshScope.class)
17+
@ConditionalOnClass({ ContextRefresher.class, RestartEndpoint.class })
1718
@EnableConfigurationProperties(ReloadableProperties.class)
1819
public class ConfigReloadAutoConfiguration {
1920

@@ -28,9 +29,11 @@ public ReloadableWatch fileAlterationObserver(ReloadableProperties reloadablePro
2829

2930
@Bean
3031
public ReloadExecutor reloadExecutor(ReloadableProperties reloadableProperties, ContextRefresher contextRefresher,
32+
@Autowired(required = false) RestartEndpoint restartEndpoint,
3133
ApplicationEventPublisher applicationEventPublisher, ConfigurableApplicationContext applicationContext) {
3234
return ReloadExecutor.builder().reloadableProperties(reloadableProperties).contextRefresher(contextRefresher)
33-
.applicationEventPublisher(applicationEventPublisher).applicationContext(applicationContext).build();
35+
.restartEndpoint(restartEndpoint).applicationEventPublisher(applicationEventPublisher)
36+
.applicationContext(applicationContext).build();
3437

3538
}
3639

propertysource-reload-spring-boot-starter/src/main/java/io/github/topikachu/properties/reload/ReloadExecutor.java

Lines changed: 63 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,29 @@
22

33
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
44
import lombok.Builder;
5-
import lombok.SneakyThrows;
5+
import org.apache.commons.logging.Log;
6+
import org.apache.commons.logging.LogFactory;
67
import org.springframework.boot.SpringApplication;
78
import org.springframework.cloud.context.refresh.ContextRefresher;
9+
import org.springframework.cloud.context.restart.RestartEndpoint;
810
import org.springframework.context.ApplicationEventPublisher;
911
import org.springframework.context.ConfigurableApplicationContext;
1012

1113
import java.io.File;
14+
import java.util.Optional;
1215
import java.util.Set;
1316
import java.util.concurrent.ThreadLocalRandom;
1417

1518
import static io.github.topikachu.properties.reload.ReloadableProperties.ReloadStrategy.*;
19+
import static io.github.topikachu.properties.reload.ReloadableProperties.StrategyType.REFRESH;
20+
import static io.github.topikachu.properties.reload.ReloadableProperties.StrategyType.RESTART_OR_SHUTDOWN;
1621

1722
@Builder
23+
@SuppressFBWarnings("DM_EXIT")
1824
public class ReloadExecutor {
1925

26+
private final Log logger = LogFactory.getLog(getClass());
27+
2028
private ReloadableProperties reloadableProperties;
2129

2230
private ContextRefresher contextRefresher;
@@ -25,42 +33,74 @@ public class ReloadExecutor {
2533

2634
private ConfigurableApplicationContext applicationContext;
2735

28-
@SuppressFBWarnings("DM_EXIT")
36+
private RestartEndpoint restartEndpoint;
37+
2938
public void executeReload(File file, PropertySourceReloadEvent.FileEvent event) {
30-
Set<String> keys;
31-
if (reloadableProperties.getStrategy() == REFRESH_ENVIRONMENT) {
32-
keys = contextRefresher.refreshEnvironment();
39+
if (reloadableProperties.getStrategy().getStrategyType() == REFRESH) {
40+
refresh(file, event);
3341
}
34-
else if (reloadableProperties.getStrategy() == REFRESH_SCOPE) {
35-
keys = contextRefresher.refresh();
42+
else if (reloadableProperties.getStrategy().getStrategyType() == RESTART_OR_SHUTDOWN) {
43+
restartOrShutdown();
44+
}
45+
else {
46+
throw new ReloadableException("Not a valid reload strategy " + reloadableProperties.getStrategy());
47+
}
48+
49+
}
50+
51+
private void restartOrShutdown() {
52+
long waitMillis = ThreadLocalRandom.current().nextLong(reloadableProperties.getMaxWaitForShutdown().toMillis());
53+
try {
54+
Thread.sleep(waitMillis);
55+
}
56+
catch (InterruptedException e) {
57+
}
58+
if (reloadableProperties.getStrategy() == RESTART) {
59+
Optional.ofNullable(restartEndpoint).ifPresent(RestartEndpoint::restart);
3660
}
3761
else if (reloadableProperties.getStrategy() == EXIT_APPLICATION) {
38-
waitForShutdown();
3962
SpringApplication.exit(applicationContext);
40-
return;
4163
}
4264
else if (reloadableProperties.getStrategy() == EXIT_APPLICATION_FORCE) {
43-
waitForShutdown();
44-
int status = SpringApplication.exit(applicationContext);
45-
System.exit(status);
46-
return;
65+
try {
66+
SpringApplication.exit(applicationContext);
67+
}
68+
finally {
69+
Thread shutdownThread = new Thread(() -> {
70+
long waitForSystemExitMillis = reloadableProperties.getMaxWaitForSystemExit().toMillis();
71+
try {
72+
Thread.sleep(waitForSystemExitMillis);
73+
}
74+
catch (InterruptedException e) {
75+
}
76+
logger.warn("Not a graceful shutdown. Execute System#exit");
77+
System.exit(0);
78+
return;
79+
});
80+
shutdownThread.setName("shutdown");
81+
shutdownThread.setDaemon(true);
82+
shutdownThread.start();
83+
}
4784
}
4885
else {
4986
throw new ReloadableException("Not a valid reload strategy " + reloadableProperties.getStrategy());
5087
}
51-
if (reloadableProperties.getStrategy() == REFRESH_ENVIRONMENT
52-
|| reloadableProperties.getStrategy() == REFRESH_SCOPE) {
53-
applicationEventPublisher.publishEvent(
54-
PropertySourceReloadEvent.builder().file(file).keys(keys).fileEvent(event).source(this).build());
55-
}
5688

5789
}
5890

59-
@SneakyThrows
60-
private void waitForShutdown() {
61-
final long waitMillis = ThreadLocalRandom.current()
62-
.nextLong(reloadableProperties.getMaxWaitForShutdown().toMillis());
63-
Thread.sleep(waitMillis);
91+
private void refresh(File file, PropertySourceReloadEvent.FileEvent event) {
92+
Set<String> keys;
93+
if (reloadableProperties.getStrategy() == REFRESH_ENVIRONMENT) {
94+
keys = contextRefresher.refreshEnvironment();
95+
}
96+
else if (reloadableProperties.getStrategy() == REFRESH_SCOPE) {
97+
keys = contextRefresher.refresh();
98+
}
99+
else {
100+
throw new ReloadableException("Not a valid reload strategy " + reloadableProperties.getStrategy());
101+
}
102+
applicationEventPublisher.publishEvent(
103+
PropertySourceReloadEvent.builder().file(file).keys(keys).fileEvent(event).source(this).build());
64104
}
65105

66106
}

0 commit comments

Comments
 (0)