From e8b297839cf7ed58515ee590a33488ba0e6a5a47 Mon Sep 17 00:00:00 2001 From: cdfive Date: Tue, 10 Mar 2020 00:10:25 +0800 Subject: [PATCH 1/3] Add "web-context-unify" configuration to support "chain" relation flow strategy in Spring webmvc adapter. --- .../sentinel-spring-webmvc-adapter/README.md | 1 + .../webmvc/AbstractSentinelInterceptor.java | 13 ++++++++++++- .../spring/webmvc/SentinelWebInterceptor.java | 8 ++++++++ .../webmvc/config/SentinelWebMvcConfig.java | 15 +++++++++++++++ .../spring/webmvc/config/InterceptorConfig.java | 1 + .../sentinel/adapter/servlet/CommonFilter.java | 2 +- .../spring/webmvc/config/InterceptorConfig.java | 3 +++ 7 files changed, 41 insertions(+), 2 deletions(-) diff --git a/sentinel-adapter/sentinel-spring-webmvc-adapter/README.md b/sentinel-adapter/sentinel-spring-webmvc-adapter/README.md index 941daed42e..cfbeb2da95 100755 --- a/sentinel-adapter/sentinel-spring-webmvc-adapter/README.md +++ b/sentinel-adapter/sentinel-spring-webmvc-adapter/README.md @@ -97,6 +97,7 @@ config.setBlockExceptionHandler((request, response, e) -> { | urlCleaner | The `UrlCleaner` interface is designed for clean and unify the URL resource. | `UrlCleaner` | - | | requestAttributeName | Attribute key in request used by Sentinel (internal) | `String` | `$$sentinel_spring_web_entry_attr` | | httpMethodSpecify | Specify whether the URL resource name should contain the HTTP method prefix (e.g. `POST:`). | `boolean` | `false` | +| webContextUnify | Specify whether unify web context(i.e. use the default context name). | `boolean` | `true` | - `SentinelWebMvcTotalConfig` configuration: diff --git a/sentinel-adapter/sentinel-spring-webmvc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc/AbstractSentinelInterceptor.java b/sentinel-adapter/sentinel-spring-webmvc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc/AbstractSentinelInterceptor.java index e9f0a39ee6..d5c44d9090 100644 --- a/sentinel-adapter/sentinel-spring-webmvc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc/AbstractSentinelInterceptor.java +++ b/sentinel-adapter/sentinel-spring-webmvc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc/AbstractSentinelInterceptor.java @@ -59,7 +59,8 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons if (StringUtil.isNotEmpty(resourceName)) { // Parse the request origin using registered origin parser. String origin = parseOrigin(request); - ContextUtil.enter(SENTINEL_SPRING_WEB_CONTEXT_NAME, origin); + String contextName = getContextName(request); + ContextUtil.enter(contextName, origin); Entry entry = SphU.entry(resourceName, ResourceTypeConstants.COMMON_WEB, EntryType.IN); setEntryInRequest(request, baseWebMvcConfig.getRequestAttributeName(), entry); @@ -79,6 +80,16 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons */ protected abstract String getResourceName(HttpServletRequest request); + /** + * Return the context name of the target web resource. + * + * @param request web request + * @return the context name of the target web resource. + */ + protected String getContextName(HttpServletRequest request) { + return SENTINEL_SPRING_WEB_CONTEXT_NAME; + } + @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { diff --git a/sentinel-adapter/sentinel-spring-webmvc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc/SentinelWebInterceptor.java b/sentinel-adapter/sentinel-spring-webmvc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc/SentinelWebInterceptor.java index b01b2c358a..0c244d680a 100644 --- a/sentinel-adapter/sentinel-spring-webmvc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc/SentinelWebInterceptor.java +++ b/sentinel-adapter/sentinel-spring-webmvc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc/SentinelWebInterceptor.java @@ -66,4 +66,12 @@ protected String getResourceName(HttpServletRequest request) { return resourceName; } + @Override + protected String getContextName(HttpServletRequest request) { + if (config.isWebContextUnify()) { + return super.getContextName(request); + } + + return getResourceName(request); + } } diff --git a/sentinel-adapter/sentinel-spring-webmvc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc/config/SentinelWebMvcConfig.java b/sentinel-adapter/sentinel-spring-webmvc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc/config/SentinelWebMvcConfig.java index 29a2891ca6..33b8a29e19 100755 --- a/sentinel-adapter/sentinel-spring-webmvc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc/config/SentinelWebMvcConfig.java +++ b/sentinel-adapter/sentinel-spring-webmvc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc/config/SentinelWebMvcConfig.java @@ -34,6 +34,11 @@ public class SentinelWebMvcConfig extends BaseWebMvcConfig { */ private boolean httpMethodSpecify; + /** + * Specify whether unify web context(i.e. use the default context name), and is true by default. + */ + private boolean webContextUnify = true; + public SentinelWebMvcConfig() { super(); setRequestAttributeName(DEFAULT_REQUEST_ATTRIBUTE_NAME); @@ -57,11 +62,21 @@ public SentinelWebMvcConfig setHttpMethodSpecify(boolean httpMethodSpecify) { return this; } + public boolean isWebContextUnify() { + return webContextUnify; + } + + public SentinelWebMvcConfig setWebContextUnify(boolean webContextUnify) { + this.webContextUnify = webContextUnify; + return this; + } + @Override public String toString() { return "SentinelWebMvcConfig{" + "urlCleaner=" + urlCleaner + ", httpMethodSpecify=" + httpMethodSpecify + + ", webContextUnify=" + webContextUnify + ", requestAttributeName='" + requestAttributeName + '\'' + ", blockExceptionHandler=" + blockExceptionHandler + ", originParser=" + originParser + diff --git a/sentinel-adapter/sentinel-spring-webmvc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/spring/webmvc/config/InterceptorConfig.java b/sentinel-adapter/sentinel-spring-webmvc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/spring/webmvc/config/InterceptorConfig.java index 1ff24fd2cf..5b167a0c1d 100644 --- a/sentinel-adapter/sentinel-spring-webmvc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/spring/webmvc/config/InterceptorConfig.java +++ b/sentinel-adapter/sentinel-spring-webmvc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/spring/webmvc/config/InterceptorConfig.java @@ -66,6 +66,7 @@ public void handle(HttpServletRequest request, HttpServletResponse response, Blo //Custom configuration if necessary config.setHttpMethodSpecify(false); + config.setWebContextUnify(true); config.setOriginParser(new RequestOriginParser() { @Override public String parseOrigin(HttpServletRequest request) { diff --git a/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/CommonFilter.java b/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/CommonFilter.java index e246e06c65..f7bf3d6148 100755 --- a/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/CommonFilter.java +++ b/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/CommonFilter.java @@ -54,7 +54,7 @@ public class CommonFilter implements Filter { */ public static final String HTTP_METHOD_SPECIFY = "HTTP_METHOD_SPECIFY"; /** - * If enabled, use the URL path as the context name, or else use the default + * If enabled, use the default context name, or else use the URL path as the context name, * {@link WebServletConfig#WEB_SERVLET_CONTEXT_NAME}. Please pay attention to the number of context (EntranceNode), * which may affect the memory footprint. * diff --git a/sentinel-demo/sentinel-demo-spring-webmvc/src/main/java/com/alibaba/csp/sentinel/demo/spring/webmvc/config/InterceptorConfig.java b/sentinel-demo/sentinel-demo-spring-webmvc/src/main/java/com/alibaba/csp/sentinel/demo/spring/webmvc/config/InterceptorConfig.java index 58509df273..ed2a1bf992 100644 --- a/sentinel-demo/sentinel-demo-spring-webmvc/src/main/java/com/alibaba/csp/sentinel/demo/spring/webmvc/config/InterceptorConfig.java +++ b/sentinel-demo/sentinel-demo-spring-webmvc/src/main/java/com/alibaba/csp/sentinel/demo/spring/webmvc/config/InterceptorConfig.java @@ -53,6 +53,9 @@ private void addSpringMvcInterceptor(InterceptorRegistry registry) { // Custom configuration if necessary config.setHttpMethodSpecify(true); + // If set false, entrance contexts will be separated by different URLs, + // which is useful to support "chain" relation flow strategy. + config.setWebContextUnify(true); config.setOriginParser(request -> request.getHeader("S-user")); // Add sentinel interceptor From 65ff6761162a6473a8cede311c1a2216f469be66 Mon Sep 17 00:00:00 2001 From: cdfive Date: Sun, 22 Mar 2020 11:20:45 +0800 Subject: [PATCH 2/3] Exit context if request is blocked and improve test case. --- .../spring/webmvc/AbstractSentinelInterceptor.java | 1 + .../spring/webmvc/SentinelSpringMvcIntegrationTest.java | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/sentinel-adapter/sentinel-spring-webmvc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc/AbstractSentinelInterceptor.java b/sentinel-adapter/sentinel-spring-webmvc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc/AbstractSentinelInterceptor.java index eab24e1461..ef710842a2 100644 --- a/sentinel-adapter/sentinel-spring-webmvc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc/AbstractSentinelInterceptor.java +++ b/sentinel-adapter/sentinel-spring-webmvc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc/AbstractSentinelInterceptor.java @@ -67,6 +67,7 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons } return true; } catch (BlockException e) { + ContextUtil.exit(); handleBlockException(request, response, e); return false; } diff --git a/sentinel-adapter/sentinel-spring-webmvc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/spring/webmvc/SentinelSpringMvcIntegrationTest.java b/sentinel-adapter/sentinel-spring-webmvc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/spring/webmvc/SentinelSpringMvcIntegrationTest.java index f6a4b30fba..f1ddb937ce 100644 --- a/sentinel-adapter/sentinel-spring-webmvc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/spring/webmvc/SentinelSpringMvcIntegrationTest.java +++ b/sentinel-adapter/sentinel-spring-webmvc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/spring/webmvc/SentinelSpringMvcIntegrationTest.java @@ -71,18 +71,21 @@ public void testOriginParser() throws Exception { final String headerName = "S-User"; configureRulesFor(springMvcPathVariableUrl, 0, limitOrigin); + // This will be passed since the caller is different: userB this.mvc.perform(get("/foo/1").accept(MediaType.TEXT_PLAIN).header(headerName, "userB")) .andExpect(status().isOk()) .andExpect(content().string("foo 1")); - // This will be blocked and reponse json. + // This will be blocked since the caller is same: userA this.mvc.perform( get("/foo/2").accept(MediaType.APPLICATION_JSON).header(headerName, limitOrigin)) .andExpect(status().isOk()) .andExpect(content().json(ResultWrapper.blocked().toJsonString())); + + // This will be passed since the caller is different: "" this.mvc.perform(get("/foo/3").accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) - .andExpect(content().string(ResultWrapper.blocked().toJsonString())); + .andExpect(content().string("foo 3")); FlowRuleManager.loadRules(null); } @@ -115,7 +118,7 @@ public void testRuntimeException() throws Exception { assertEquals(i + 1, cn.passQps(), 0.01); } - // This will be blocked and reponse json. + // This will be blocked and response json. this.mvc.perform(get(url)) .andExpect(status().isOk()) .andExpect(content().string(ResultWrapper.blocked().toJsonString())); From 84dfe5e72f2c07af85787825b041d66b7b4a433c Mon Sep 17 00:00:00 2001 From: cdfive Date: Mon, 23 Mar 2020 15:08:28 +0800 Subject: [PATCH 3/3] Using try finally block, since user may need the context in the block handler --- .../adapter/spring/webmvc/AbstractSentinelInterceptor.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sentinel-adapter/sentinel-spring-webmvc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc/AbstractSentinelInterceptor.java b/sentinel-adapter/sentinel-spring-webmvc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc/AbstractSentinelInterceptor.java index ef710842a2..b065c54cb1 100644 --- a/sentinel-adapter/sentinel-spring-webmvc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc/AbstractSentinelInterceptor.java +++ b/sentinel-adapter/sentinel-spring-webmvc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/spring/webmvc/AbstractSentinelInterceptor.java @@ -67,8 +67,11 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons } return true; } catch (BlockException e) { - ContextUtil.exit(); - handleBlockException(request, response, e); + try { + handleBlockException(request, response, e); + } finally { + ContextUtil.exit(); + } return false; } }