diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/ZuulFilterInitializer.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/ZuulFilterInitializer.java index 19ae0de0..2d347331 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/ZuulFilterInitializer.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/ZuulFilterInitializer.java @@ -19,8 +19,8 @@ package org.springframework.cloud.netflix.zuul; import java.lang.reflect.Field; import java.util.Map; -import javax.servlet.ServletContextEvent; -import javax.servlet.ServletContextListener; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; import org.springframework.util.ReflectionUtils; @@ -39,7 +39,7 @@ import lombok.extern.apachecommons.CommonsLog; * */ @CommonsLog -public class ZuulFilterInitializer implements ServletContextListener { +public class ZuulFilterInitializer { private final Map filters; private final CounterFactory counterFactory; @@ -59,10 +59,9 @@ public class ZuulFilterInitializer implements ServletContextListener { this.filterRegistry = filterRegistry; } - @Override - public void contextInitialized(ServletContextEvent sce) { - - log.info("Starting filter initializer context listener"); + @PostConstruct + public void contextInitialized() { + log.info("Starting filter initializer"); TracerFactory.initialize(tracerFactory); CounterFactory.initialize(counterFactory); @@ -72,9 +71,9 @@ public class ZuulFilterInitializer implements ServletContextListener { } } - @Override - public void contextDestroyed(ServletContextEvent sce) { - log.info("Stopping filter initializer context listener"); + @PreDestroy + public void contextDestroyed() { + log.info("Stopping filter initializer"); for (Map.Entry entry : this.filters.entrySet()) { filterRegistry.remove(entry.getKey()); } diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/ZuulProperties.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/ZuulProperties.java index 3b808528..8c2d40ad 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/ZuulProperties.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/ZuulProperties.java @@ -328,6 +328,14 @@ public class ZuulProperties { * The maximum number of connections that can be used by a single route. */ private int maxPerRouteConnections = 20; + /** + * The socket timeout in millis. Defaults to 10000. + */ + private int socketTimeoutMillis = 10000; + /** + * The connection timeout in millis. Defaults to 2000. + */ + private int connectTimeoutMillis = 2000; /** * The lifetime for the connection pool. */ diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/SimpleHostRoutingFilter.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/SimpleHostRoutingFilter.java index 07d8b947..f6b9909c 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/SimpleHostRoutingFilter.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/SimpleHostRoutingFilter.java @@ -67,18 +67,17 @@ import org.apache.http.message.BasicHeader; import org.apache.http.message.BasicHttpEntityEnclosingRequest; import org.apache.http.message.BasicHttpRequest; import org.apache.http.protocol.HttpContext; +import org.springframework.cloud.context.environment.EnvironmentChangeEvent; import org.springframework.cloud.netflix.zuul.filters.ProxyRequestHelper; import org.springframework.cloud.netflix.zuul.filters.ZuulProperties; import org.springframework.cloud.netflix.zuul.filters.ZuulProperties.Host; import org.springframework.cloud.netflix.zuul.util.ZuulRuntimeException; +import org.springframework.context.event.EventListener; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.util.StringUtils; -import com.netflix.config.DynamicIntProperty; -import com.netflix.config.DynamicPropertyFactory; import com.netflix.zuul.ZuulFilter; -import com.netflix.zuul.constants.ZuulConstants; import com.netflix.zuul.context.RequestContext; import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.HTTPS_SCHEME; @@ -98,14 +97,6 @@ public class SimpleHostRoutingFilter extends ZuulFilter { private static final Log log = LogFactory.getLog(SimpleHostRoutingFilter.class); - private static final DynamicIntProperty SOCKET_TIMEOUT = DynamicPropertyFactory - .getInstance() - .getIntProperty(ZuulConstants.ZUUL_HOST_SOCKET_TIMEOUT_MILLIS, 10000); - - private static final DynamicIntProperty CONNECTION_TIMEOUT = DynamicPropertyFactory - .getInstance() - .getIntProperty(ZuulConstants.ZUUL_HOST_CONNECT_TIMEOUT_MILLIS, 2000); - private final Timer connectionManagerTimer = new Timer( "SimpleHostRoutingFilter.connectionManagerTimer", true); @@ -117,9 +108,18 @@ public class SimpleHostRoutingFilter extends ZuulFilter { private PoolingHttpClientConnectionManager connectionManager; private CloseableHttpClient httpClient; - private final Runnable clientloader = new Runnable() { - @Override - public void run() { + @EventListener + public void onPropertyChange(EnvironmentChangeEvent event) { + boolean createNewClient = false; + + for (String key : event.getKeys()) { + if (key.startsWith("zuul.host.")) { + createNewClient = true; + break; + } + } + + if (createNewClient) { try { SimpleHostRoutingFilter.this.httpClient.close(); } @@ -128,7 +128,7 @@ public class SimpleHostRoutingFilter extends ZuulFilter { } SimpleHostRoutingFilter.this.httpClient = newClient(); } - }; + } public SimpleHostRoutingFilter(ProxyRequestHelper helper, ZuulProperties properties) { this.helper = helper; @@ -141,8 +141,6 @@ public class SimpleHostRoutingFilter extends ZuulFilter { @PostConstruct private void initialize() { this.httpClient = newClient(); - SOCKET_TIMEOUT.addCallback(this.clientloader); - CONNECTION_TIMEOUT.addCallback(this.clientloader); this.connectionManagerTimer.schedule(new TimerTask() { @Override public void run() { @@ -251,8 +249,8 @@ public class SimpleHostRoutingFilter extends ZuulFilter { protected CloseableHttpClient newClient() { final RequestConfig requestConfig = RequestConfig.custom() - .setSocketTimeout(SOCKET_TIMEOUT.get()) - .setConnectTimeout(CONNECTION_TIMEOUT.get()) + .setSocketTimeout(this.hostProperties.getSocketTimeoutMillis()) + .setConnectTimeout(this.hostProperties.getConnectTimeoutMillis()) .setCookieSpec(CookieSpecs.IGNORE_COOKIES).build(); HttpClientBuilder httpClientBuilder = HttpClients.custom(); diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/ZuulFilterInitializerTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/ZuulFilterInitializerTests.java index 0abb2458..64e1ab71 100644 --- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/ZuulFilterInitializerTests.java +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/ZuulFilterInitializerTests.java @@ -16,12 +16,12 @@ package org.springframework.cloud.netflix.zuul; +import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; -import javax.servlet.ServletContextEvent; - +import org.junit.Test; import org.springframework.test.util.ReflectionTestUtils; import org.springframework.util.ReflectionUtils; @@ -31,10 +31,6 @@ import com.netflix.zuul.filters.FilterRegistry; import com.netflix.zuul.monitoring.CounterFactory; import com.netflix.zuul.monitoring.TracerFactory; -import org.junit.Test; - -import java.lang.reflect.Constructor; - import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -42,9 +38,6 @@ import static org.mockito.Mockito.mock; public class ZuulFilterInitializerTests { - private static final ServletContextEvent DUMMY_SERVLET_CONTEXT_EVENT = mock( - ServletContextEvent.class); - private Map filters = getFilters(); private CounterFactory counterFactory = mock(CounterFactory.class); private TracerFactory tracerFactory = mock(TracerFactory.class); @@ -56,7 +49,7 @@ public class ZuulFilterInitializerTests { @Test public void shouldSetupOnContextInitializedEvent() throws Exception { - initializer.contextInitialized(DUMMY_SERVLET_CONTEXT_EVENT); + initializer.contextInitialized(); assertEquals(tracerFactory, TracerFactory.instance()); assertEquals(counterFactory, CounterFactory.instance()); @@ -66,7 +59,7 @@ public class ZuulFilterInitializerTests { @Test public void shouldCleanupOnContextDestroyed() throws Exception { - initializer.contextDestroyed(DUMMY_SERVLET_CONTEXT_EVENT); + initializer.contextDestroyed(); assertEquals(null, ReflectionTestUtils.getField(TracerFactory.class, "INSTANCE")); assertEquals(null, diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/route/SimpleHostRoutingFilterTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/route/SimpleHostRoutingFilterTests.java index 6d813b87..f7cd9c53 100644 --- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/route/SimpleHostRoutingFilterTests.java +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/route/SimpleHostRoutingFilterTests.java @@ -22,6 +22,7 @@ import java.io.IOException; import java.lang.reflect.Field; import java.nio.charset.Charset; import java.util.Arrays; +import java.util.Collections; import java.util.concurrent.TimeUnit; import java.util.zip.GZIPOutputStream; @@ -46,6 +47,7 @@ import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoCon import org.springframework.boot.context.embedded.LocalServerPort; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.context.environment.EnvironmentChangeEvent; import org.springframework.cloud.netflix.zuul.filters.ProxyRequestHelper; import org.springframework.cloud.netflix.zuul.filters.ZuulProperties; import org.springframework.context.annotation.AnnotationConfigApplicationContext; @@ -54,6 +56,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.util.ReflectionTestUtils; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.ReflectionUtils; import org.springframework.web.bind.annotation.PathVariable; @@ -76,8 +79,7 @@ import static org.springframework.util.StreamUtils.copyToString; @RunWith(SpringRunner.class) @SpringBootTest(classes = SampleApplication.class, webEnvironment = RANDOM_PORT, - properties = {"server.contextPath: /app", "zuul.host.socket-timeout-millis=11000", - "zuul.host.connect-timeout-millis=2100"}) + properties = {"server.contextPath: /app"}) @DirtiesContext public class SimpleHostRoutingFilterTests { @@ -95,6 +97,8 @@ public class SimpleHostRoutingFilterTests { @Test public void timeoutPropertiesAreApplied() { + addEnvironment(this.context, "zuul.host.socket-timeout-millis=11000", + "zuul.host.connect-timeout-millis=2100"); setupContext(); CloseableHttpClient httpClient = getFilter().newClient(); Assertions.assertThat(httpClient).isInstanceOf(Configurable.class); @@ -188,6 +192,17 @@ public class SimpleHostRoutingFilterTests { assertTrue("Get 1".equals(responseString)); } + @Test + public void zuulHostKeysUpdateHttpClient() { + setupContext(); + SimpleHostRoutingFilter filter = getFilter(); + CloseableHttpClient httpClient = (CloseableHttpClient) ReflectionTestUtils.getField(filter, "httpClient"); + EnvironmentChangeEvent event = new EnvironmentChangeEvent(Collections.singleton("zuul.host.mykey")); + filter.onPropertyChange(event); + CloseableHttpClient newhttpClient = (CloseableHttpClient) ReflectionTestUtils.getField(filter, "httpClient"); + Assertions.assertThat(httpClient).isNotEqualTo(newhttpClient); + } + private void setupContext() { this.context.register(PropertyPlaceholderAutoConfiguration.class, TestConfiguration.class); @@ -199,8 +214,13 @@ public class SimpleHostRoutingFilterTests { } @Configuration - @EnableConfigurationProperties(ZuulProperties.class) + @EnableConfigurationProperties protected static class TestConfiguration { + @Bean + ZuulProperties zuulProperties() { + return new ZuulProperties(); + } + @Bean SimpleHostRoutingFilter simpleHostRoutingFilter(ZuulProperties zuulProperties) { return new SimpleHostRoutingFilter(new ProxyRequestHelper(), zuulProperties);