diff --git a/docs/src/main/asciidoc/spring-cloud-netflix.adoc b/docs/src/main/asciidoc/spring-cloud-netflix.adoc index 64c9c7fc..ab48c463 100644 --- a/docs/src/main/asciidoc/spring-cloud-netflix.adoc +++ b/docs/src/main/asciidoc/spring-cloud-netflix.adoc @@ -1107,7 +1107,7 @@ favor for an opt-in approach. [[spring-cloud-feign-hystrix-fallback]] === Feign Hystrix Fallbacks -Hystrix supports the notion of a fallback: a default code path that is executed when they circuit is open or there is an error. To enable fallbacks for a given `@FeignClient` set the `fallback` attribute to the class name that implements the fallback. +Hystrix supports the notion of a fallback: a default code path that is executed when they circuit is open or there is an error. To enable fallbacks for a given `@FeignClient` set the `fallback` attribute to the class name that implements the fallback. You also need to declare your implementation as a Spring bean. [source,java,indent=0] ---- diff --git a/mvnw.cmd b/mvnw.cmd index fc830243..b0dc0e7e 100644 --- a/mvnw.cmd +++ b/mvnw.cmd @@ -1,145 +1,145 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Maven2 Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" -if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -set MAVEN_CMD_LINE_ARGS=%* - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven2 Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +set MAVEN_CMD_LINE_ARGS=%* + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" set WRAPPER_JAR="".\.mvn\wrapper\maven-wrapper.jar"" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS% -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" -if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%" == "on" pause - -if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% - -exit /B %ERROR_CODE% +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS% +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClient.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClient.java index 131b08ff..0a40573c 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClient.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClient.java @@ -107,7 +107,7 @@ public @interface FeignClient { String path() default ""; /** - * Whether to mark the feign proxy as a primary bean. Defaults to false. + * Whether to mark the feign proxy as a primary bean. Defaults to true. */ boolean primary() default true; diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/support/SpringDecoder.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/support/SpringDecoder.java index 3fbd26c6..798ef5bd 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/support/SpringDecoder.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/support/SpringDecoder.java @@ -23,6 +23,7 @@ import java.io.IOException; import java.io.InputStream; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import java.lang.reflect.WildcardType; import org.springframework.beans.factory.ObjectFactory; import org.springframework.boot.autoconfigure.http.HttpMessageConverters; @@ -48,9 +49,10 @@ public class SpringDecoder implements Decoder { } @Override - public Object decode(final Response response, Type type) throws IOException, - FeignException { - if (type instanceof Class || type instanceof ParameterizedType) { + public Object decode(final Response response, Type type) + throws IOException, FeignException { + if (type instanceof Class || type instanceof ParameterizedType + || type instanceof WildcardType) { @SuppressWarnings({ "unchecked", "rawtypes" }) HttpMessageConverterExtractor extractor = new HttpMessageConverterExtractor( type, this.messageConverters.getObject().getConverters()); diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/hystrix/security/HystrixSecurityAutoConfiguration.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/hystrix/security/HystrixSecurityAutoConfiguration.java index 37cc3620..272f234e 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/hystrix/security/HystrixSecurityAutoConfiguration.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/hystrix/security/HystrixSecurityAutoConfiguration.java @@ -74,11 +74,6 @@ public class HystrixSecurityAutoConfiguration { super(ConfigurationPhase.REGISTER_BEAN); } - @ConditionalOnProperty(name = "feign.hystrix.enabled", matchIfMissing = false) - static class HystrixEnabled { - - } - @ConditionalOnProperty(name = "hystrix.shareSecurityContext") static class ShareSecurityContext { diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/SimpleRouteLocator.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/SimpleRouteLocator.java index 483599f2..28ccdf85 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/SimpleRouteLocator.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/SimpleRouteLocator.java @@ -83,6 +83,11 @@ public class SimpleRouteLocator implements RouteLocator, Ordered { @Override public Route getMatchingRoute(final String path) { + return getSimpleMatchingRoute(path); + + } + + protected Route getSimpleMatchingRoute(final String path) { if (log.isDebugEnabled()) { log.debug("Finding route for path: " + path); } @@ -102,29 +107,31 @@ public class SimpleRouteLocator implements RouteLocator, Ordered { String adjustedPath = adjustPath(path); - ZuulRoute route = null; + ZuulRoute route = getZuulRoute(adjustedPath); + + return getRoute(route, adjustedPath); + } + + protected ZuulRoute getZuulRoute(String adjustedPath) { if (!matchesIgnoredPatterns(adjustedPath)) { for (Entry entry : this.routes.get().entrySet()) { String pattern = entry.getKey(); log.debug("Matching pattern:" + pattern); if (this.pathMatcher.match(pattern, adjustedPath)) { - route = entry.getValue(); - break; + return entry.getValue(); } } } - if (log.isDebugEnabled()) { - log.debug("route matched=" + route); - } - - return getRoute(route, adjustedPath); - + return null; } - private Route getRoute(ZuulRoute route, String path) { + protected Route getRoute(ZuulRoute route, String path) { if (route == null) { return null; } + if (log.isDebugEnabled()) { + log.debug("route matched=" + route); + } String targetPath = path; String prefix = this.properties.getPrefix(); if (path.startsWith(prefix) && this.properties.isStripPrefix()) { 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 f411fad2..3b808528 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 @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,6 +33,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.concurrent.TimeUnit; import static com.netflix.hystrix.HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE; @@ -40,6 +41,7 @@ import static com.netflix.hystrix.HystrixCommandProperties.ExecutionIsolationStr * @author Spencer Gibb * @author Dave Syer * @author Mathias Düsterhöft + * @author Bilal Alp */ @Data @ConfigurationProperties("zuul") @@ -326,6 +328,14 @@ public class ZuulProperties { * The maximum number of connections that can be used by a single route. */ private int maxPerRouteConnections = 20; + /** + * The lifetime for the connection pool. + */ + private long timeToLive = -1; + /** + * The time unit for timeToLive. + */ + private TimeUnit timeUnit = TimeUnit.MILLISECONDS; } @Data diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/post/SendResponseFilter.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/post/SendResponseFilter.java index 6ac172bb..d0338860 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/post/SendResponseFilter.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/post/SendResponseFilter.java @@ -71,7 +71,7 @@ public class SendResponseFilter extends ZuulFilter { public SendResponseFilter() { super(); - // To support Servlet API 3.0.1 we need to check if setcontentLengthLong exists + // To support Servlet API 3.1 we need to check if setContentLengthLong exists try { HttpServletResponse.class.getMethod("setContentLengthLong"); } catch(NoSuchMethodException e) { diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/RibbonRoutingFilter.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/RibbonRoutingFilter.java index f28d82c5..6832abe7 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/RibbonRoutingFilter.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/RibbonRoutingFilter.java @@ -68,7 +68,7 @@ public class RibbonRoutingFilter extends ZuulFilter { this.helper = helper; this.ribbonCommandFactory = ribbonCommandFactory; this.requestCustomizers = requestCustomizers; - // To support Servlet API 3.0.1 we need to check if getcontentLengthLong exists + // To support Servlet API 3.1 we need to check if getContentLengthLong exists try { HttpServletRequest.class.getMethod("getContentLengthLong"); } catch(NoSuchMethodException e) { 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 9fec0b08..07d8b947 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 @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -92,6 +92,7 @@ import static org.springframework.cloud.netflix.zuul.filters.support.FilterConst * * @author Spencer Gibb * @author Dave Syer + * @author Bilal Alp */ public class SimpleHostRoutingFilter extends ZuulFilter { @@ -235,7 +236,8 @@ public class SimpleHostRoutingFilter extends ZuulFilter { } final Registry registry = registryBuilder.build(); - this.connectionManager = new PoolingHttpClientConnectionManager(registry); + this.connectionManager = new PoolingHttpClientConnectionManager(registry, null, null, null, + hostProperties.getTimeToLive(), hostProperties.getTimeUnit()); this.connectionManager .setMaxTotal(this.hostProperties.getMaxTotalConnections()); this.connectionManager.setDefaultMaxPerRoute( diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/SpringDecoderTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/SpringDecoderTests.java index 949864da..c01cebf9 100644 --- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/SpringDecoderTests.java +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/SpringDecoderTests.java @@ -19,9 +19,11 @@ package org.springframework.cloud.netflix.feign; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.List; +import java.util.Map; import org.junit.Test; import org.junit.runner.RunWith; @@ -36,6 +38,7 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; @@ -108,6 +111,19 @@ public class SpringDecoderTests extends FeignClientFactoryBean { assertEquals("first hello didn't match", "hello world 1", hellos.get(0)); } + @Test + @SuppressWarnings("unchecked") + public void testWildcardTypeDecode() { + ResponseEntity wildcard = testClient().getWildcard(); + assertNotNull("wildcard was null", wildcard); + assertEquals("wrong status code", HttpStatus.OK, wildcard.getStatusCode()); + Object wildcardBody = wildcard.getBody(); + assertNotNull("wildcardBody was null", wildcardBody); + assertTrue("wildcard not an instance of Map", wildcardBody instanceof Map); + Map hello = (Map) wildcardBody; + assertEquals("first hello didn't match", "wildcard", hello.get("message")); + } + @Test public void testResponseEntityVoid() { ResponseEntity response = testClient().getHelloVoid(); @@ -156,6 +172,9 @@ public class SpringDecoderTests extends FeignClientFactoryBean { @RequestMapping(method = RequestMethod.GET, value = "/hellonotfound") ResponseEntity getNotFound(); + + @GetMapping("/helloWildcard") + ResponseEntity getWildcard(); } @Configuration @@ -199,6 +218,11 @@ public class SpringDecoderTests extends FeignClientFactoryBean { return ResponseEntity.status(HttpStatus.NOT_FOUND).body((String) null); } + @Override + public ResponseEntity getWildcard() { + return ResponseEntity.ok(new Hello("wildcard")); + } + public static void main(String[] args) { new SpringApplicationBuilder(Application.class) .properties("spring.application.name=springdecodertest", diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/hystrix/security/HystrixSecurityNoFeignTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/hystrix/security/HystrixSecurityNoFeignTests.java new file mode 100644 index 00000000..e9a36fd3 --- /dev/null +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/hystrix/security/HystrixSecurityNoFeignTests.java @@ -0,0 +1,42 @@ +/* + * Copyright 2013-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.springframework.cloud.netflix.hystrix.security; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit4.SpringRunner; + +import com.netflix.hystrix.strategy.HystrixPlugins; +import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy; + +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(SpringRunner.class) +@DirtiesContext +@SpringBootTest(classes = HystrixSecurityApplication.class) +public class HystrixSecurityNoFeignTests { + + @Test + public void testSecurityConcurrencyStrategyInstalled() { + HystrixConcurrencyStrategy concurrencyStrategy = HystrixPlugins.getInstance().getConcurrencyStrategy(); + assertThat(concurrencyStrategy).isInstanceOf(SecurityContextConcurrencyStrategy.class); + } + +} diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/hystrix/security/HystrixSecurityTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/hystrix/security/HystrixSecurityTests.java index 5f22f975..3ed019e3 100644 --- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/hystrix/security/HystrixSecurityTests.java +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/hystrix/security/HystrixSecurityTests.java @@ -18,6 +18,8 @@ package org.springframework.cloud.netflix.hystrix.security; import java.util.Base64; +import com.netflix.hystrix.strategy.HystrixPlugins; +import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -33,6 +35,8 @@ import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.web.client.RestTemplate; +import static org.assertj.core.api.Assertions.assertThat; + /** * Tests that a secured web service returning values using a feign client properly access * the security context from a hystrix command. @@ -40,7 +44,9 @@ import org.springframework.web.client.RestTemplate; */ @RunWith(SpringJUnit4ClassRunner.class) @DirtiesContext -@SpringBootTest(classes = HystrixSecurityApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT, properties = {"username.ribbon.listOfServers=localhost:${local.server.port}","feign.hystrix.enabled=true"}) +@SpringBootTest(classes = HystrixSecurityApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT, + properties = { "username.ribbon.listOfServers=localhost:${local.server.port}", + "feign.hystrix.enabled=true"}) public class HystrixSecurityTests { @Autowired private CustomConcurrenyStrategy customConcurrenyStrategy; @@ -54,6 +60,12 @@ public class HystrixSecurityTests { @Value("${security.user.password}") private String password; + @Test + public void testSecurityConcurrencyStrategyInstalled() { + HystrixConcurrencyStrategy concurrencyStrategy = HystrixPlugins.getInstance().getConcurrencyStrategy(); + assertThat(concurrencyStrategy).isInstanceOf(SecurityContextConcurrencyStrategy.class); + } + @Test public void testFeignHystrixSecurity() { HttpHeaders headers = HystrixSecurityTests.createBasicAuthHeader(username, diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/RibbonClientPreprocessorOverridesRetryTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/RibbonClientPreprocessorOverridesRetryTests.java index 2b093f95..f6e698f3 100644 --- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/RibbonClientPreprocessorOverridesRetryTests.java +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/RibbonClientPreprocessorOverridesRetryTests.java @@ -1,121 +1,121 @@ -/* - * Copyright 2013-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package org.springframework.cloud.netflix.ribbon; - -import java.net.ConnectException; -import java.net.SocketException; -import java.net.SocketTimeoutException; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.List; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.netflix.archaius.ArchaiusAutoConfiguration; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.util.Assert; - -import com.netflix.client.DefaultLoadBalancerRetryHandler; -import com.netflix.client.RetryHandler; -import com.netflix.client.config.IClientConfig; - -/** - * @author Tyler Van Gorder - */ -@RunWith(SpringJUnit4ClassRunner.class) -@SpringBootTest(classes = RibbonClientPreprocessorOverridesRetryTests.TestConfiguration.class, value = { - "customRetry.ribbon.MaxAutoRetries=0", - "customRetry.ribbon.MaxAutoRetriesNextServer=1", - "customRetry.ribbon.OkToRetryOnAllOperations=true" }) -@DirtiesContext -public class RibbonClientPreprocessorOverridesRetryTests { - - @Autowired - private SpringClientFactory factory; - - @Test - public void customRetryIsConfigured() throws Exception { - RibbonLoadBalancerContext context = (RibbonLoadBalancerContext) this.factory - .getLoadBalancerContext("customRetry"); - Assert.isInstanceOf(RetryRibbonConfiguration.CustomRetryHandler.class, - context.getRetryHandler()); - Assert.isTrue(context.getRetryHandler().getMaxRetriesOnSameServer() == 0); - Assert.isTrue(context.getRetryHandler().getMaxRetriesOnNextServer() == 1); - Assert.isTrue(context.getRetryHandler() - .isCircuitTrippingException(new UnknownHostException("Unknown Host"))); - } - - @Configuration - @RibbonClient(name = "customRetry", configuration = RetryRibbonConfiguration.class) - @Import({ PropertyPlaceholderAutoConfiguration.class, ArchaiusAutoConfiguration.class, - RibbonAutoConfiguration.class }) - protected static class TestConfiguration { - } - -} - -@Configuration -class RetryRibbonConfiguration { - @Bean - public RetryHandler retryHandler(IClientConfig config) { - return new CustomRetryHandler(config); - } - - class CustomRetryHandler extends DefaultLoadBalancerRetryHandler { - - @SuppressWarnings("unchecked") - private List> retriable = new ArrayList() { - { - add(UnknownHostException.class); - add(ConnectException.class); - add(SocketTimeoutException.class); - } - }; - - @SuppressWarnings("unchecked") - private List> circuitRelated = new ArrayList() { - { - add(UnknownHostException.class); - add(SocketException.class); - add(SocketTimeoutException.class); - } - }; - - CustomRetryHandler(IClientConfig config) { - super(config); - } - - @Override - protected List> getRetriableExceptions() { - return retriable; - } - - @Override - protected List> getCircuitRelatedExceptions() { - return circuitRelated; - } - - } -} +/* + * Copyright 2013-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.springframework.cloud.netflix.ribbon; + +import java.net.ConnectException; +import java.net.SocketException; +import java.net.SocketTimeoutException; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.netflix.archaius.ArchaiusAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.util.Assert; + +import com.netflix.client.DefaultLoadBalancerRetryHandler; +import com.netflix.client.RetryHandler; +import com.netflix.client.config.IClientConfig; + +/** + * @author Tyler Van Gorder + */ +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest(classes = RibbonClientPreprocessorOverridesRetryTests.TestConfiguration.class, value = { + "customRetry.ribbon.MaxAutoRetries=0", + "customRetry.ribbon.MaxAutoRetriesNextServer=1", + "customRetry.ribbon.OkToRetryOnAllOperations=true" }) +@DirtiesContext +public class RibbonClientPreprocessorOverridesRetryTests { + + @Autowired + private SpringClientFactory factory; + + @Test + public void customRetryIsConfigured() throws Exception { + RibbonLoadBalancerContext context = (RibbonLoadBalancerContext) this.factory + .getLoadBalancerContext("customRetry"); + Assert.isInstanceOf(RetryRibbonConfiguration.CustomRetryHandler.class, + context.getRetryHandler()); + Assert.isTrue(context.getRetryHandler().getMaxRetriesOnSameServer() == 0); + Assert.isTrue(context.getRetryHandler().getMaxRetriesOnNextServer() == 1); + Assert.isTrue(context.getRetryHandler() + .isCircuitTrippingException(new UnknownHostException("Unknown Host"))); + } + + @Configuration + @RibbonClient(name = "customRetry", configuration = RetryRibbonConfiguration.class) + @Import({ PropertyPlaceholderAutoConfiguration.class, ArchaiusAutoConfiguration.class, + RibbonAutoConfiguration.class }) + protected static class TestConfiguration { + } + +} + +@Configuration +class RetryRibbonConfiguration { + @Bean + public RetryHandler retryHandler(IClientConfig config) { + return new CustomRetryHandler(config); + } + + class CustomRetryHandler extends DefaultLoadBalancerRetryHandler { + + @SuppressWarnings("unchecked") + private List> retriable = new ArrayList() { + { + add(UnknownHostException.class); + add(ConnectException.class); + add(SocketTimeoutException.class); + } + }; + + @SuppressWarnings("unchecked") + private List> circuitRelated = new ArrayList() { + { + add(UnknownHostException.class); + add(SocketException.class); + add(SocketTimeoutException.class); + } + }; + + CustomRetryHandler(IClientConfig config) { + super(config); + } + + @Override + protected List> getRetriableExceptions() { + return retriable; + } + + @Override + protected List> getCircuitRelatedExceptions() { + return circuitRelated; + } + + } +} 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 078967c1..c4966889 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 @@ -20,8 +20,10 @@ package org.springframework.cloud.netflix.zuul.filters.route; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.lang.reflect.Field; import java.nio.charset.Charset; import java.util.Arrays; +import java.util.concurrent.TimeUnit; import java.util.zip.GZIPOutputStream; import javax.servlet.http.HttpServletResponse; @@ -29,9 +31,13 @@ import javax.servlet.http.HttpServletResponse; import org.apache.http.HttpEntityEnclosingRequest; import org.apache.http.HttpHost; import org.apache.http.HttpRequest; +import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.Configurable; import org.apache.http.entity.InputStreamEntity; +import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.assertj.core.api.Assertions; import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; @@ -50,6 +56,7 @@ import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.ReflectionUtils; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @@ -70,7 +77,8 @@ import static org.springframework.util.StreamUtils.copyToString; @RunWith(SpringRunner.class) @SpringBootTest(classes = SampleApplication.class, webEnvironment = RANDOM_PORT, - properties = "server.servlet.contextPath: /app") + properties = {"server.servlet.contextPath: /app", "zuul.host.socket-timeout-millis=11000", + "zuul.host.connect-timeout-millis=2100"}) @DirtiesContext public class SimpleHostRoutingFilterTests { @@ -86,13 +94,37 @@ public class SimpleHostRoutingFilterTests { } } + @Test + public void timeoutPropertiesAreApplied() { + setupContext(); + CloseableHttpClient httpClient = getFilter().newClient(); + Assertions.assertThat(httpClient).isInstanceOf(Configurable.class); + RequestConfig config = ((Configurable) httpClient).getConfig(); + assertEquals(11000, config.getSocketTimeout()); + assertEquals(2100, config.getConnectTimeout()); + } + @Test public void connectionPropertiesAreApplied() { - addEnvironment(this.context, "zuul.host.maxTotalConnections=100", "zuul.host.maxPerRouteConnections=10"); + addEnvironment(this.context, "zuul.host.maxTotalConnections=100", + "zuul.host.maxPerRouteConnections=10", "zuul.host.timeToLive=5", + "zuul.host.timeUnit=SECONDS"); setupContext(); PoolingHttpClientConnectionManager connMgr = getFilter().newConnectionManager(); assertEquals(100, connMgr.getMaxTotal()); assertEquals(10, connMgr.getDefaultMaxPerRoute()); + Object pool = getField(connMgr, "pool"); + Long timeToLive = getField(pool, "timeToLive"); + TimeUnit timeUnit = getField(pool, "tunit"); + assertEquals(new Long(5), timeToLive); + assertEquals(TimeUnit.SECONDS, timeUnit); + } + + protected T getField(Object target, String name) { + Field field = ReflectionUtils.findField(target.getClass(), name); + ReflectionUtils.makeAccessible(field); + Object value = ReflectionUtils.getField(field, target); + return (T)value; } @Test diff --git a/spring-cloud-netflix-dependencies/pom.xml b/spring-cloud-netflix-dependencies/pom.xml index a2ea0b41..805349be 100644 --- a/spring-cloud-netflix-dependencies/pom.xml +++ b/spring-cloud-netflix-dependencies/pom.xml @@ -16,8 +16,8 @@ 0.7.4 1.6.2 - 9.4.0 - 1.5.11 + 9.5.0 + 1.5.12 2.2.2 0.10.1 1.3.0 @@ -238,11 +238,6 @@ - - javax-inject - javax-inject - 1 - com.netflix.eureka eureka-core diff --git a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaClientAutoConfiguration.java b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaClientAutoConfiguration.java index 4835555a..0fca4dd9 100644 --- a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaClientAutoConfiguration.java +++ b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaClientAutoConfiguration.java @@ -22,9 +22,11 @@ import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import java.net.MalformedURLException; +import java.net.URL; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.actuate.endpoint.Endpoint; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.AnyNestedCondition; @@ -53,6 +55,7 @@ import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Lazy; import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.PropertyResolver; import org.springframework.util.StringUtils; import com.netflix.appinfo.ApplicationInfoManager; @@ -62,7 +65,6 @@ import com.netflix.appinfo.InstanceInfo; import com.netflix.discovery.DiscoveryClient.DiscoveryClientOptionalArgs; import com.netflix.discovery.EurekaClient; import com.netflix.discovery.EurekaClientConfig; - import static org.springframework.cloud.commons.util.IdUtils.getDefaultInstanceId; /** @@ -82,18 +84,14 @@ import static org.springframework.cloud.commons.util.IdUtils.getDefaultInstanceI @AutoConfigureAfter(name = "org.springframework.cloud.autoconfigure.RefreshAutoConfiguration") public class EurekaClientAutoConfiguration { - @Value("${server.port:${SERVER_PORT:${PORT:8080}}}") - private int nonSecurePort; - - @Value("${management.port:${MANAGEMENT_PORT:${server.port:${SERVER_PORT:${PORT:8080}}}}}") - private int managementPort; - - @Autowired private ConfigurableEnvironment env; - @Autowired(required = false) private HealthCheckHandler healthCheckHandler; + public EurekaClientAutoConfiguration(ConfigurableEnvironment env) { + this.env = env; + } + @Bean public HasFeatures eurekaFeature() { return HasFeatures.namedFeature("Eureka Client", EurekaClient.class); @@ -120,17 +118,22 @@ public class EurekaClientAutoConfiguration { public EurekaInstanceConfigBean eurekaInstanceConfigBean(InetUtils inetUtils) { String hostname = getProperty("eureka.instance.hostname"); boolean preferIpAddress = Boolean.parseBoolean(getProperty("eureka.instance.prefer-ip-address")); + int nonSecurePort = Integer.valueOf(env.getProperty("server.port", env.getProperty("port", "8080"))); + int managementPort = Integer.valueOf(env.getProperty("management.port", String.valueOf(nonSecurePort))); + String managementContextPath = env.getProperty("management.context-path", env.getProperty("server.servlet.context-path", "/")); EurekaInstanceConfigBean instance = new EurekaInstanceConfigBean(inetUtils); - instance.setNonSecurePort(this.nonSecurePort); - instance.setInstanceId(getDefaultInstanceId(this.env)); + instance.setNonSecurePort(nonSecurePort); + instance.setInstanceId(getDefaultInstanceId(propertyResolver)); instance.setPreferIpAddress(preferIpAddress); - - if (this.managementPort != this.nonSecurePort && this.managementPort != 0) { + if (managementPort != nonSecurePort && managementPort != 0) { if (StringUtils.hasText(hostname)) { instance.setHostname(hostname); } String statusPageUrlPath = getProperty("eureka.instance.status-page-url-path"); String healthCheckUrlPath = getProperty("eureka.instance.health-check-url-path"); + if (!managementContextPath.endsWith("/")) { + managementContextPath = managementContextPath + "/"; + } if (StringUtils.hasText(statusPageUrlPath)) { instance.setStatusPageUrlPath(statusPageUrlPath); } @@ -138,17 +141,15 @@ public class EurekaClientAutoConfiguration { instance.setHealthCheckUrlPath(healthCheckUrlPath); } String scheme = instance.getSecurePortEnabled() ? "https" : "http"; - instance.setStatusPageUrl(scheme + "://" + instance.getHostname() + ":" - + this.managementPort + instance.getStatusPageUrlPath()); - instance.setHealthCheckUrl(scheme + "://" + instance.getHostname() + ":" - + this.managementPort + instance.getHealthCheckUrlPath()); + URL base = new URL(scheme, instance.getHostname(), managementPort, managementContextPath); + instance.setStatusPageUrl(new URL(base, StringUtils.trimLeadingCharacter(instance.getStatusPageUrlPath(), '/')).toString()); + instance.setHealthCheckUrl(new URL(base, StringUtils.trimLeadingCharacter(instance.getHealthCheckUrlPath(), '/')).toString()); } return instance; } @Bean - public DiscoveryClient discoveryClient(EurekaInstanceConfig config, - EurekaClient client) { + public DiscoveryClient discoveryClient(EurekaInstanceConfig config, EurekaClient client) { return new EurekaDiscoveryClient(config, client); } @@ -193,8 +194,7 @@ public class EurekaClientAutoConfiguration { @Bean(destroyMethod = "shutdown") @ConditionalOnMissingBean(value = EurekaClient.class, search = SearchStrategy.CURRENT) - public EurekaClient eurekaClient(ApplicationInfoManager manager, - EurekaClientConfig config) { + public EurekaClient eurekaClient(ApplicationInfoManager manager, EurekaClientConfig config) { return new CloudEurekaClient(manager, config, this.optionalArgs, this.context); } @@ -222,8 +222,7 @@ public class EurekaClientAutoConfiguration { @ConditionalOnMissingBean(value = EurekaClient.class, search = SearchStrategy.CURRENT) @org.springframework.cloud.context.config.annotation.RefreshScope @Lazy - public EurekaClient eurekaClient(ApplicationInfoManager manager, - EurekaClientConfig config, EurekaInstanceConfig instance) { + public EurekaClient eurekaClient(ApplicationInfoManager manager, EurekaClientConfig config, EurekaInstanceConfig instance) { manager.getInfo(); // force initialization return new CloudEurekaClient(manager, config, this.optionalArgs, this.context); @@ -233,8 +232,7 @@ public class EurekaClientAutoConfiguration { @ConditionalOnMissingBean(value = ApplicationInfoManager.class, search = SearchStrategy.CURRENT) @org.springframework.cloud.context.config.annotation.RefreshScope @Lazy - public ApplicationInfoManager eurekaApplicationInfoManager( - EurekaInstanceConfig config) { + public ApplicationInfoManager eurekaApplicationInfoManager(EurekaInstanceConfig config) { InstanceInfo instanceInfo = new InstanceInfoFactory().create(config); return new ApplicationInfoManager(config, instanceInfo); } @@ -274,4 +272,14 @@ public class EurekaClientAutoConfiguration { } + @Configuration + @ConditionalOnClass(Endpoint.class) + protected static class EurekaHealthIndicatorConfiguration { + @Bean + @ConditionalOnMissingBean + public EurekaHealthIndicator eurekaHealthIndicator(EurekaClient eurekaClient, + EurekaInstanceConfig instanceConfig, EurekaClientConfig clientConfig) { + return new EurekaHealthIndicator(eurekaClient, instanceConfig, clientConfig); + } + } } diff --git a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaDiscoveryClientConfiguration.java b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaDiscoveryClientConfiguration.java index 8f068518..42b7b303 100644 --- a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaDiscoveryClientConfiguration.java +++ b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaDiscoveryClientConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2014 the original author or authors. + * Copyright 2013-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,12 +12,12 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. + * */ package org.springframework.cloud.netflix.eureka; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.actuate.endpoint.Endpoint; import org.springframework.boot.actuate.health.HealthAggregator; import org.springframework.boot.actuate.health.OrderedHealthAggregator; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -30,7 +30,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.event.EventListener; -import com.netflix.appinfo.EurekaInstanceConfig; import com.netflix.appinfo.HealthCheckHandler; import com.netflix.discovery.EurekaClient; import com.netflix.discovery.EurekaClientConfig; @@ -82,16 +81,6 @@ public class EurekaDiscoveryClientConfiguration { } } - @Configuration - @ConditionalOnClass(Endpoint.class) - protected static class EurekaHealthIndicatorConfiguration { - @Bean - @ConditionalOnMissingBean - public EurekaHealthIndicator eurekaHealthIndicator(EurekaClient eurekaClient, - EurekaInstanceConfig instanceConfig, EurekaClientConfig clientConfig) { - return new EurekaHealthIndicator(eurekaClient, instanceConfig, clientConfig); - } - } @Configuration @ConditionalOnProperty(value = "eureka.client.healthcheck.enabled", matchIfMissing = false) diff --git a/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/EurekaClientAutoConfigurationTests.java b/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/EurekaClientAutoConfigurationTests.java index 10637daf..8f4c09f8 100644 --- a/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/EurekaClientAutoConfigurationTests.java +++ b/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/EurekaClientAutoConfigurationTests.java @@ -121,6 +121,54 @@ public class EurekaClientAutoConfigurationTests { instance.getHealthCheckUrl().contains("/myHealthCheck")); } + @Test + public void statusPageUrlPathAndManagementPortAndContextPath() { + EnvironmentTestUtils.addEnvironment(this.context, "server.port=8989", + "management.port=9999", "management.contextPath=/manage", + "eureka.instance.statusPageUrlPath=/myStatusPage"); + setupContext(RefreshAutoConfiguration.class); + EurekaInstanceConfigBean instance = this.context + .getBean(EurekaInstanceConfigBean.class); + assertTrue("Wrong status page: " + instance.getStatusPageUrl(), + instance.getStatusPageUrl().endsWith(":9999/manage/myStatusPage")); + } + + @Test + public void healthCheckUrlPathAndManagementPortAndContextPath() { + EnvironmentTestUtils.addEnvironment(this.context, "server.port=8989", + "management.port=9999", "management.contextPath=/manage", + "eureka.instance.healthCheckUrlPath=/myHealthCheck"); + setupContext(RefreshAutoConfiguration.class); + EurekaInstanceConfigBean instance = this.context + .getBean(EurekaInstanceConfigBean.class); + assertTrue("Wrong health check: " + instance.getHealthCheckUrl(), + instance.getHealthCheckUrl().endsWith(":9999/manage/myHealthCheck")); + } + + @Test + public void statusPageUrlPathAndManagementPortAndContextPathKebobCase() { + EnvironmentTestUtils.addEnvironment(this.context, "server.port=8989", + "management.port=9999", "management.context-path=/manage", + "eureka.instance.statusPageUrlPath=/myStatusPage"); + setupContext(RefreshAutoConfiguration.class); + EurekaInstanceConfigBean instance = this.context + .getBean(EurekaInstanceConfigBean.class); + assertTrue("Wrong status page: " + instance.getStatusPageUrl(), + instance.getStatusPageUrl().endsWith(":9999/manage/myStatusPage")); + } + + @Test + public void healthCheckUrlPathAndManagementPortAndContextPathKebobCase() { + EnvironmentTestUtils.addEnvironment(this.context, "server.port=8989", + "management.port=9999", "management.context-path=/manage", + "eureka.instance.healthCheckUrlPath=/myHealthCheck"); + setupContext(RefreshAutoConfiguration.class); + EurekaInstanceConfigBean instance = this.context + .getBean(EurekaInstanceConfigBean.class); + assertTrue("Wrong health check: " + instance.getHealthCheckUrl(), + instance.getHealthCheckUrl().endsWith(":9999/manage/myHealthCheck")); + } + @Test public void statusPageUrlPathAndManagementPortKabobCase() { EnvironmentTestUtils.addEnvironment(this.context, "server.port=8989", @@ -280,6 +328,12 @@ public class EurekaClientAutoConfigurationTests { assertEquals("mytesteurekaappname", getInstanceConfig().getAppname()); } + @Test + public void eurekaHealthIndicatorCreated() { + setupContext(); + this.context.getBean(EurekaHealthIndicator.class); + } + private void testNonSecurePort(String propName) { addEnvironment(this.context, propName + ":8888"); setupContext(); diff --git a/spring-cloud-netflix-hystrix-stream/src/test/java/org/springframework/cloud/netflix/hystrix/stream/HystrixStreamTests.java b/spring-cloud-netflix-hystrix-stream/src/test/java/org/springframework/cloud/netflix/hystrix/stream/HystrixStreamTests.java index f71b7cff..8e6f16d9 100644 --- a/spring-cloud-netflix-hystrix-stream/src/test/java/org/springframework/cloud/netflix/hystrix/stream/HystrixStreamTests.java +++ b/spring-cloud-netflix-hystrix-stream/src/test/java/org/springframework/cloud/netflix/hystrix/stream/HystrixStreamTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,11 +19,13 @@ package org.springframework.cloud.netflix.hystrix.stream; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; +import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.context.annotation.Configuration; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.web.bind.annotation.RequestMapping; @@ -31,12 +33,14 @@ import org.springframework.web.bind.annotation.RestController; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; +import static org.assertj.core.api.Assertions.assertThat; + /** * @author Spencer Gibb */ @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = HystrixStreamTests.Application.class, webEnvironment = WebEnvironment.RANDOM_PORT, - properties = { "spring.jmx.enabled=true" }) + properties = { "spring.jmx.enabled=true", "spring.application.name=mytestapp" }) @DirtiesContext public class HystrixStreamTests { @@ -46,9 +50,13 @@ public class HystrixStreamTests { @Autowired private Application application; + @Autowired + private DiscoveryClient discoveryClient; + @EnableAutoConfiguration @EnableCircuitBreaker @RestController + @Configuration public static class Application { @HystrixCommand @@ -56,16 +64,16 @@ public class HystrixStreamTests { public String hello() { return "Hello World"; } - - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } - } @Test public void contextLoads() { this.application.hello(); + //It is important that local service instance resolves for metrics + //origin details to be populated + ServiceInstance localServiceInstance = discoveryClient.getLocalServiceInstance(); + assertThat(localServiceInstance).isNotNull(); + assertThat(localServiceInstance.getServiceId()).isEqualTo("mytestapp"); this.task.gatherMetrics(); }