Skip to content
This repository was archived by the owner on Jun 29, 2018. It is now read-only.

Commit b7577fd

Browse files
Johannes StelzerJohannes Stelzer
authored andcommitted
fixup! Add optional automatic deregistration on shutdown - turned off by default; only periodically try to register when the context is active
1 parent d66e70f commit b7577fd

5 files changed

Lines changed: 256 additions & 60 deletions

File tree

spring-boot-admin-starter-client/src/main/java/de/codecentric/boot/admin/config/AdminClientProperties.java

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,19 @@
2323
import org.springframework.boot.actuate.autoconfigure.ManagementServerProperties;
2424
import org.springframework.boot.autoconfigure.web.ServerProperties;
2525
import org.springframework.boot.context.embedded.EmbeddedServletContainerInitializedEvent;
26+
import org.springframework.boot.context.embedded.EmbeddedWebApplicationContext;
2627
import org.springframework.boot.context.properties.ConfigurationProperties;
28+
import org.springframework.context.ApplicationEvent;
2729
import org.springframework.context.ApplicationListener;
30+
import org.springframework.context.event.ApplicationContextEvent;
31+
import org.springframework.context.event.ContextRefreshedEvent;
32+
import org.springframework.core.Ordered;
33+
import org.springframework.core.annotation.Order;
2834
import org.springframework.util.StringUtils;
2935

3036
@ConfigurationProperties(prefix = "spring.boot.admin.client", ignoreUnknownFields = false)
31-
public class AdminClientProperties implements ApplicationListener<EmbeddedServletContainerInitializedEvent>{
37+
@Order(Ordered.LOWEST_PRECEDENCE - 100)
38+
public class AdminClientProperties implements ApplicationListener<ApplicationEvent> {
3239

3340
private String url;
3441

@@ -45,30 +52,53 @@ public class AdminClientProperties implements ApplicationListener<EmbeddedServle
4552

4653
private int managementPort = -1;
4754

55+
private boolean serverInitialized = false;
4856

4957
@Override
50-
public void onApplicationEvent(
51-
EmbeddedServletContainerInitializedEvent event) {
52-
if ("management".equals(event.getApplicationContext().getNamespace())) {
53-
managementPort = event.getEmbeddedServletContainer().getPort();
54-
} else {
55-
serverPort = event.getEmbeddedServletContainer().getPort();
58+
public void onApplicationEvent(ApplicationEvent event) {
59+
if (event instanceof EmbeddedServletContainerInitializedEvent) {
60+
EmbeddedServletContainerInitializedEvent initEvent = (EmbeddedServletContainerInitializedEvent) event;
61+
serverInitialized = true;
62+
if ("management".equals(initEvent.getApplicationContext().getNamespace())) {
63+
managementPort = initEvent.getEmbeddedServletContainer().getPort();
64+
} else {
65+
serverPort = initEvent.getEmbeddedServletContainer().getPort();
66+
}
67+
} else if (startedDeployedWar(event)) {
68+
serverInitialized = true;
69+
if (!StringUtils.hasText(url)) {
70+
throw new RuntimeException(
71+
"spring.boot.admin.client.url must be set for deployed war files!");
72+
}
73+
}
74+
}
75+
76+
private boolean startedDeployedWar(ApplicationEvent event) {
77+
if (event instanceof ContextRefreshedEvent) {
78+
ApplicationContextEvent contextEvent = (ApplicationContextEvent) event;
79+
if (contextEvent.getApplicationContext() instanceof EmbeddedWebApplicationContext) {
80+
EmbeddedWebApplicationContext context = (EmbeddedWebApplicationContext) contextEvent
81+
.getApplicationContext();
82+
return context.getEmbeddedServletContainer() == null;
83+
}
5684
}
85+
return false;
5786
}
5887

88+
5989
/**
6090
* @return Client-management-URL to register with. Can be overriden in case the
6191
* reachable URL is different (e.g. Docker). Must be unique in registry.
6292
*/
6393
public String getUrl() {
6494
if (url == null) {
6595
if (managementPort != -1) {
66-
url = "http://"
96+
return "http://"
6797
+ (getHostname() + ':' + managementPort + toPathFragment(management
6898
.getContextPath()))
6999
.replaceAll("//+", "/");
70100
} else if (serverPort != -1){
71-
url = "http://"
101+
return "http://"
72102
+ (getHostname()
73103
+ ':'
74104
+ serverPort
@@ -87,6 +117,10 @@ public void setUrl(String url) {
87117
this.url = url;
88118
}
89119

120+
public boolean isServerInitialized() {
121+
return serverInitialized;
122+
}
123+
90124
/**
91125
* @return Name to register with.
92126
*/

spring-boot-admin-starter-client/src/main/java/de/codecentric/boot/admin/config/SpringBootAdminClientAutoConfiguration.java

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,16 @@
2121
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
2222
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
2323
import org.springframework.boot.context.properties.EnableConfigurationProperties;
24-
import org.springframework.context.ApplicationListener;
25-
import org.springframework.context.ConfigurableApplicationContext;
2624
import org.springframework.context.annotation.Bean;
2725
import org.springframework.context.annotation.Configuration;
28-
import org.springframework.context.event.ApplicationContextEvent;
29-
import org.springframework.context.event.ContextClosedEvent;
30-
import org.springframework.context.event.ContextRefreshedEvent;
31-
import org.springframework.context.event.ContextStartedEvent;
32-
import org.springframework.context.event.ContextStoppedEvent;
3326
import org.springframework.http.client.ClientHttpRequestInterceptor;
3427
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
3528
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
3629
import org.springframework.web.client.RestTemplate;
3730

3831
import de.codecentric.boot.admin.actuate.LogfileMvcEndpoint;
3932
import de.codecentric.boot.admin.services.ApplicationRegistrator;
33+
import de.codecentric.boot.admin.services.RegistrationApplicationListener;
4034
import de.codecentric.boot.admin.web.BasicAuthHttpRequestInterceptor;
4135

4236
/**
@@ -75,14 +69,13 @@ protected RestTemplate createRestTemplate(AdminProperties admin) {
7569
*/
7670
@Bean
7771
public ScheduledTaskRegistrar taskRegistrar(final ApplicationRegistrator registrator,
78-
final ConfigurableApplicationContext context,
79-
AdminProperties admin) {
72+
AdminProperties admin, final AdminClientProperties client) {
8073
ScheduledTaskRegistrar registrar = new ScheduledTaskRegistrar();
8174

8275
Runnable registratorTask = new Runnable() {
8376
@Override
8477
public void run() {
85-
if (context.isActive()) {
78+
if (client.isServerInitialized()) {
8679
registrator.register();
8780
}
8881
}
@@ -93,26 +86,14 @@ public void run() {
9386
}
9487

9588
/**
96-
* ApplicationListener triggering rigestration after refresh/shutdown
89+
* ApplicationListener triggering registration after refresh/shutdown
9790
*/
9891
@Bean
99-
public ApplicationListener<ApplicationContextEvent> RegistrationListener(
92+
public RegistrationApplicationListener registrationListener(
10093
final ApplicationRegistrator registrator, final AdminProperties admin) {
101-
return new ApplicationListener<ApplicationContextEvent>() {
102-
public void onApplicationEvent(ApplicationContextEvent event) {
103-
if (event instanceof ContextRefreshedEvent
104-
|| event instanceof ContextStartedEvent) {
105-
registrator.register();
106-
}
107-
else if (admin.isAutoDeregistration()
108-
&& (event instanceof ContextClosedEvent || event instanceof ContextStoppedEvent)) {
109-
registrator.deregister();
110-
}
111-
}
112-
};
94+
return new RegistrationApplicationListener(admin, registrator);
11395
}
11496

115-
11697
@Configuration
11798
@ConditionalOnExpression("${endpoints.logfile.enabled:true}")
11899
@ConditionalOnProperty("logging.file")
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package de.codecentric.boot.admin.services;
2+
3+
import org.springframework.boot.context.embedded.EmbeddedServletContainerInitializedEvent;
4+
import org.springframework.boot.context.embedded.EmbeddedWebApplicationContext;
5+
import org.springframework.context.ApplicationEvent;
6+
import org.springframework.context.ApplicationListener;
7+
import org.springframework.context.event.ApplicationContextEvent;
8+
import org.springframework.context.event.ContextClosedEvent;
9+
import org.springframework.context.event.ContextRefreshedEvent;
10+
import org.springframework.core.Ordered;
11+
import org.springframework.core.annotation.Order;
12+
13+
import de.codecentric.boot.admin.config.AdminProperties;
14+
15+
@Order(Ordered.LOWEST_PRECEDENCE)
16+
public class RegistrationApplicationListener implements
17+
ApplicationListener<ApplicationEvent> {
18+
private final AdminProperties admin;
19+
private final ApplicationRegistrator registrator;
20+
21+
public RegistrationApplicationListener(AdminProperties admin,
22+
ApplicationRegistrator registrator) {
23+
this.admin = admin;
24+
this.registrator = registrator;
25+
}
26+
27+
public void onApplicationEvent(ApplicationEvent event) {
28+
if (startedDeployedWar(event) || startedEmbeddedServer(event)) {
29+
registrator.register();
30+
}
31+
else if (admin.isAutoDeregistration()
32+
&& event instanceof ContextClosedEvent) {
33+
registrator.deregister();
34+
}
35+
}
36+
37+
private boolean startedEmbeddedServer(ApplicationEvent event) {
38+
return event instanceof EmbeddedServletContainerInitializedEvent;
39+
}
40+
41+
private boolean startedDeployedWar(ApplicationEvent event) {
42+
if (event instanceof ContextRefreshedEvent) {
43+
ApplicationContextEvent contextEvent = (ApplicationContextEvent) event;
44+
if (contextEvent.getApplicationContext() instanceof EmbeddedWebApplicationContext) {
45+
EmbeddedWebApplicationContext context = (EmbeddedWebApplicationContext) contextEvent
46+
.getApplicationContext();
47+
return context.getEmbeddedServletContainer() == null;
48+
}
49+
}
50+
return false;
51+
}
52+
}
53+

spring-boot-admin-starter-client/src/test/java/de/codecentric/boot/admin/config/AdminClientPropertiesTest.java

Lines changed: 62 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package de.codecentric.boot.admin.config;
22

33
import static org.hamcrest.Matchers.is;
4+
import static org.junit.Assert.assertFalse;
45
import static org.junit.Assert.assertThat;
6+
import static org.junit.Assert.assertTrue;
57
import static org.mockito.Mockito.mock;
68
import static org.mockito.Mockito.when;
79

@@ -16,6 +18,7 @@
1618
import org.springframework.boot.context.embedded.EmbeddedServletContainerInitializedEvent;
1719
import org.springframework.boot.context.embedded.EmbeddedWebApplicationContext;
1820
import org.springframework.boot.test.EnvironmentTestUtils;
21+
import org.springframework.context.event.ContextRefreshedEvent;
1922
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
2023

2124
public class AdminClientPropertiesTest {
@@ -29,40 +32,66 @@ public void close() {
2932
}
3033
}
3134

35+
@Test
36+
public void test_isServerStarted_false() {
37+
assertFalse(new AdminClientProperties().isServerInitialized());
38+
}
39+
40+
@Test
41+
public void test_isServerStarted_true_embedded() {
42+
AdminClientProperties clientProperties = new AdminClientProperties();
43+
clientProperties.setUrl("http://localhost");
44+
publishServletContainerInitializedEvent(clientProperties, 8080, null);
45+
assertTrue(clientProperties.isServerInitialized());
46+
}
47+
48+
@Test
49+
public void test_isServerStarted_true_war() {
50+
AdminClientProperties clientProperties = new AdminClientProperties();
51+
clientProperties.setUrl("http://localhost");
52+
publishContextRefreshedEvent(clientProperties);
53+
assertTrue(clientProperties.isServerInitialized());
54+
}
55+
56+
@Test(expected = RuntimeException.class)
57+
public void test_isServerStarted_exception_war() {
58+
AdminClientProperties clientProperties = new AdminClientProperties();
59+
publishContextRefreshedEvent(clientProperties);
60+
}
61+
3262
@Test
3363
public void test_mgmtPortPath() {
34-
load("spring.boot.admin.url:http://localhost:8081",
35-
"management.contextPath=/admin");
36-
AdminClientProperties clientProperties = context
37-
.getBean(AdminClientProperties.class);
64+
load("management.contextPath=/admin");
65+
AdminClientProperties clientProperties = new AdminClientProperties();
66+
context.getAutowireCapableBeanFactory().autowireBean(clientProperties);
3867

39-
publishEvent(8080, null);
40-
publishEvent(8081, "management");
68+
publishServletContainerInitializedEvent(clientProperties, 8080, null);
69+
publishServletContainerInitializedEvent(clientProperties, 8081, "management");
4170

4271
assertThat(clientProperties.getUrl(), is("http://" + getHostname()
4372
+ ":8081/admin"));
4473
}
4574

4675
@Test
4776
public void test_mgmtPort() {
48-
load("spring.boot.admin.url:http://localhost:8081");
49-
AdminClientProperties clientProperties = context
50-
.getBean(AdminClientProperties.class);
77+
load();
78+
AdminClientProperties clientProperties = new AdminClientProperties();
79+
context.getAutowireCapableBeanFactory().autowireBean(clientProperties);
5180

52-
publishEvent(8080, null);
53-
publishEvent(8081, "management");
81+
publishServletContainerInitializedEvent(clientProperties, 8080, null);
82+
publishServletContainerInitializedEvent(clientProperties, 8081, "management");
5483

5584
assertThat(clientProperties.getUrl(), is("http://" + getHostname() + ":8081"));
5685
}
5786

5887
@Test
5988
public void test_contextPath_mgmtPath() {
60-
load("spring.boot.admin.url:http://localhost:8081", "server.context-path=app",
89+
load("server.context-path=app",
6190
"management.context-path=/admin");
62-
AdminClientProperties clientProperties = context
63-
.getBean(AdminClientProperties.class);
91+
AdminClientProperties clientProperties = new AdminClientProperties();
92+
context.getAutowireCapableBeanFactory().autowireBean(clientProperties);
6493

65-
publishEvent(8080, null);
94+
publishServletContainerInitializedEvent(clientProperties, 8080, null);
6695

6796
assertThat(clientProperties.getUrl(), is("http://" + getHostname()
6897
+ ":8080/app/admin"));
@@ -71,23 +100,23 @@ public void test_contextPath_mgmtPath() {
71100

72101
@Test
73102
public void test_contextPath() {
74-
load("spring.boot.admin.url:http://localhost:8081", "server.context-path=app");
75-
AdminClientProperties clientProperties = context
76-
.getBean(AdminClientProperties.class);
103+
load("server.context-path=app");
104+
AdminClientProperties clientProperties = new AdminClientProperties();
105+
context.getAutowireCapableBeanFactory().autowireBean(clientProperties);
77106

78-
publishEvent(8080, null);
107+
publishServletContainerInitializedEvent(clientProperties, 8080, null);
79108

80109
assertThat(clientProperties.getUrl(), is("http://" + getHostname() + ":8080/app"));
81110
}
82111

83112

84113
@Test
85114
public void test_default() {
86-
load("spring.boot.admin.url:http://localhost:8081");
87-
AdminClientProperties clientProperties = context
88-
.getBean(AdminClientProperties.class);
115+
load();
116+
AdminClientProperties clientProperties = new AdminClientProperties();
117+
context.getAutowireCapableBeanFactory().autowireBean(clientProperties);
89118

90-
publishEvent(8080, null);
119+
publishServletContainerInitializedEvent(clientProperties, 8080, null);
91120

92121
assertThat(clientProperties.getUrl(), is("http://" + getHostname() + ":8080"));
93122
}
@@ -101,20 +130,27 @@ private String getHostname() {
101130
}
102131
}
103132

104-
private void publishEvent(int port, String namespace) {
133+
private void publishServletContainerInitializedEvent(AdminClientProperties client,
134+
int port, String namespace) {
105135
EmbeddedServletContainer eventSource = mock(EmbeddedServletContainer.class);
106136
when(eventSource.getPort()).thenReturn(port);
107137
EmbeddedWebApplicationContext eventContext = mock(EmbeddedWebApplicationContext.class);
108138
when(eventContext.getNamespace()).thenReturn(namespace);
109-
context.publishEvent(new EmbeddedServletContainerInitializedEvent(eventContext,
139+
when(eventContext.getEmbeddedServletContainer()).thenReturn(eventSource);
140+
client.onApplicationEvent(new EmbeddedServletContainerInitializedEvent(
141+
eventContext,
110142
eventSource));
111143
}
112144

145+
private void publishContextRefreshedEvent(AdminClientProperties client) {
146+
client.onApplicationEvent(new ContextRefreshedEvent(
147+
mock(EmbeddedWebApplicationContext.class)));
148+
}
149+
113150
private void load(String... environment) {
114151
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
115152
applicationContext.register(ServerPropertiesAutoConfiguration.class);
116153
applicationContext.register(ManagementServerPropertiesAutoConfiguration.class);
117-
applicationContext.register(SpringBootAdminClientAutoConfiguration.class);
118154
EnvironmentTestUtils.addEnvironment(applicationContext, environment);
119155
applicationContext.refresh();
120156
this.context = applicationContext;

0 commit comments

Comments
 (0)