-
Notifications
You must be signed in to change notification settings - Fork 8.1k
feat: add Jakarta EE Servlet 6.0 adapter module (#2998) #3627
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 1.8
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
| <modelVersion>4.0.0</modelVersion> | ||
|
|
||
| <parent> | ||
| <groupId>com.alibaba.csp</groupId> | ||
| <artifactId>sentinel-adapter</artifactId> | ||
| <version>2.0.0-alpha2-SNAPSHOT</version> | ||
| </parent> | ||
|
|
||
| <artifactId>sentinel-web-servlet-jakarta</artifactId> | ||
| <packaging>jar</packaging> | ||
| <description>Sentinel adapter for Jakarta EE Servlet 6.0 (Spring Boot 3.x)</description> | ||
|
|
||
| <properties> | ||
| <jakarta.servlet-api.version>6.0.0</jakarta.servlet-api.version> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Warning] |
||
| <skip.spring.v6x.test>false</skip.spring.v6x.test> | ||
| <maven.compiler.source>17</maven.compiler.source> | ||
| <maven.compiler.target>17</maven.compiler.target> | ||
| </properties> | ||
|
|
||
| <dependencies> | ||
| <dependency> | ||
| <groupId>com.alibaba.csp</groupId> | ||
| <artifactId>sentinel-core</artifactId> | ||
| </dependency> | ||
|
|
||
| <dependency> | ||
| <groupId>jakarta.servlet</groupId> | ||
| <artifactId>jakarta.servlet-api</artifactId> | ||
| <version>${jakarta.servlet-api.version}</version> | ||
| <scope>provided</scope> | ||
| </dependency> | ||
|
|
||
| <dependency> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Warning] Test dependencies (junit, spring-boot-starter-test) are declared, but the module adds no tests, while the javax sibling |
||
| <groupId>junit</groupId> | ||
| <artifactId>junit</artifactId> | ||
| <scope>test</scope> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.springframework.boot</groupId> | ||
| <artifactId>spring-boot-starter-web</artifactId> | ||
| <version>3.2.0</version> | ||
| <scope>test</scope> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.springframework.boot</groupId> | ||
| <artifactId>spring-boot-starter-test</artifactId> | ||
| <version>3.2.0</version> | ||
| <scope>test</scope> | ||
| </dependency> | ||
| </dependencies> | ||
|
|
||
| <build> | ||
| <plugins> | ||
| <plugin> | ||
| <groupId>org.apache.maven.plugins</groupId> | ||
| <artifactId>maven-surefire-plugin</artifactId> | ||
| <version>${maven.surefire.version}</version> | ||
| <configuration> | ||
| <skipTests>${skip.spring.v6x.test}</skipTests> | ||
| </configuration> | ||
| </plugin> | ||
| </plugins> | ||
| </build> | ||
|
|
||
| </project> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,144 @@ | ||
| /* | ||
| * Copyright 1999-2018 Alibaba Group Holding Ltd. | ||
| * | ||
| * 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 com.alibaba.csp.sentinel.adapter.servlet; | ||
|
|
||
| import java.io.IOException; | ||
|
|
||
| import jakarta.servlet.Filter; | ||
| import jakarta.servlet.FilterChain; | ||
| import jakarta.servlet.FilterConfig; | ||
| import jakarta.servlet.ServletException; | ||
| import jakarta.servlet.ServletRequest; | ||
| import jakarta.servlet.ServletResponse; | ||
| import jakarta.servlet.http.HttpServletRequest; | ||
| import jakarta.servlet.http.HttpServletResponse; | ||
|
|
||
| import com.alibaba.csp.sentinel.Entry; | ||
| import com.alibaba.csp.sentinel.EntryType; | ||
| import com.alibaba.csp.sentinel.ResourceTypeConstants; | ||
| import com.alibaba.csp.sentinel.SphU; | ||
| import com.alibaba.csp.sentinel.Tracer; | ||
| import com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser; | ||
| import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlCleaner; | ||
| import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager; | ||
| import com.alibaba.csp.sentinel.adapter.servlet.config.WebServletConfig; | ||
| import com.alibaba.csp.sentinel.adapter.servlet.util.FilterUtil; | ||
| import com.alibaba.csp.sentinel.context.ContextUtil; | ||
| import com.alibaba.csp.sentinel.slots.block.BlockException; | ||
| import com.alibaba.csp.sentinel.util.StringUtil; | ||
|
|
||
| /** | ||
| * Servlet filter that integrates with Sentinel. | ||
| * | ||
| * @author youji.zj | ||
| * @author Eric Zhao | ||
| * @author zhaoyuguang | ||
| */ | ||
| public class CommonFilter implements Filter { | ||
|
|
||
| /** | ||
| * Specify whether the URL resource name should contain the HTTP method prefix (e.g. {@code POST:}). | ||
| */ | ||
| public static final String HTTP_METHOD_SPECIFY = "HTTP_METHOD_SPECIFY"; | ||
| /** | ||
| * 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. | ||
| * | ||
| * @since 1.7.0 | ||
| */ | ||
| public static final String WEB_CONTEXT_UNIFY = "WEB_CONTEXT_UNIFY"; | ||
|
|
||
| private final static String COLON = ":"; | ||
|
|
||
| private boolean httpMethodSpecify = false; | ||
| private boolean webContextUnify = true; | ||
|
|
||
| @Override | ||
| public void init(FilterConfig filterConfig) { | ||
| httpMethodSpecify = Boolean.parseBoolean(filterConfig.getInitParameter(HTTP_METHOD_SPECIFY)); | ||
| if (filterConfig.getInitParameter(WEB_CONTEXT_UNIFY) != null) { | ||
| webContextUnify = Boolean.parseBoolean(filterConfig.getInitParameter(WEB_CONTEXT_UNIFY)); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) | ||
| throws IOException, ServletException { | ||
| HttpServletRequest sRequest = (HttpServletRequest) request; | ||
| Entry urlEntry = null; | ||
|
|
||
| try { | ||
| String target = FilterUtil.filterTarget(sRequest); | ||
| // Clean and unify the URL. | ||
| // For REST APIs, you have to clean the URL (e.g. `/foo/1` and `/foo/2` -> `/foo/:id`), or | ||
| // the amount of context and resources will exceed the threshold. | ||
| UrlCleaner urlCleaner = WebCallbackManager.getUrlCleaner(); | ||
| if (urlCleaner != null) { | ||
| target = urlCleaner.clean(target); | ||
| } | ||
|
|
||
| // If you intend to exclude some URLs, you can convert the URLs to the empty string "" | ||
| // in the UrlCleaner implementation. | ||
| if (!StringUtil.isEmpty(target)) { | ||
| // Parse the request origin using registered origin parser. | ||
| String origin = parseOrigin(sRequest); | ||
| String contextName = webContextUnify ? WebServletConfig.WEB_SERVLET_CONTEXT_NAME : target; | ||
| ContextUtil.enter(contextName, origin); | ||
|
|
||
| if (httpMethodSpecify) { | ||
| // Add HTTP method prefix if necessary. | ||
| String pathWithHttpMethod = sRequest.getMethod().toUpperCase() + COLON + target; | ||
| urlEntry = SphU.entry(pathWithHttpMethod, ResourceTypeConstants.COMMON_WEB, EntryType.IN); | ||
| } else { | ||
| urlEntry = SphU.entry(target, ResourceTypeConstants.COMMON_WEB, EntryType.IN); | ||
| } | ||
| } | ||
| chain.doFilter(request, response); | ||
| } catch (BlockException e) { | ||
| HttpServletResponse sResponse = (HttpServletResponse) response; | ||
| // Return the block page, or redirect to another URL. | ||
| WebCallbackManager.getUrlBlockHandler().blocked(sRequest, sResponse, e); | ||
| } catch (IOException | ServletException | RuntimeException e2) { | ||
| Tracer.traceEntry(e2, urlEntry); | ||
| throw e2; | ||
| } finally { | ||
| if (urlEntry != null) { | ||
| urlEntry.exit(); | ||
| } | ||
| ContextUtil.exit(); | ||
| } | ||
| } | ||
|
|
||
| private String parseOrigin(HttpServletRequest request) { | ||
| RequestOriginParser originParser = WebCallbackManager.getRequestOriginParser(); | ||
| String origin = EMPTY_ORIGIN; | ||
| if (originParser != null) { | ||
| origin = originParser.parseOrigin(request); | ||
| if (StringUtil.isEmpty(origin)) { | ||
| return EMPTY_ORIGIN; | ||
| } | ||
| } | ||
| return origin; | ||
| } | ||
|
|
||
| @Override | ||
| public void destroy() { | ||
|
|
||
| } | ||
|
|
||
| private static final String EMPTY_ORIGIN = ""; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| /* | ||
| * Copyright 1999-2018 Alibaba Group Holding Ltd. | ||
| * | ||
| * 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 com.alibaba.csp.sentinel.adapter.servlet; | ||
|
|
||
| import java.io.IOException; | ||
|
|
||
| import jakarta.servlet.Filter; | ||
| import jakarta.servlet.FilterChain; | ||
| import jakarta.servlet.FilterConfig; | ||
| import jakarta.servlet.ServletException; | ||
| import jakarta.servlet.ServletRequest; | ||
| import jakarta.servlet.ServletResponse; | ||
| import jakarta.servlet.http.HttpServletRequest; | ||
| import jakarta.servlet.http.HttpServletResponse; | ||
|
|
||
| import com.alibaba.csp.sentinel.Entry; | ||
| import com.alibaba.csp.sentinel.ResourceTypeConstants; | ||
| import com.alibaba.csp.sentinel.SphU; | ||
| import com.alibaba.csp.sentinel.Tracer; | ||
| import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager; | ||
| import com.alibaba.csp.sentinel.adapter.servlet.config.WebServletConfig; | ||
| import com.alibaba.csp.sentinel.context.ContextUtil; | ||
| import com.alibaba.csp.sentinel.slots.block.BlockException; | ||
|
|
||
| /*** | ||
| * Servlet filter for all requests. | ||
| * | ||
| * @author youji.zj | ||
| */ | ||
| public class CommonTotalFilter implements Filter { | ||
|
|
||
| public static final String TOTAL_URL_REQUEST = "total-url-request"; | ||
|
|
||
| @Override | ||
| public void init(FilterConfig filterConfig) { | ||
|
|
||
| } | ||
|
|
||
| @Override | ||
| public void doFilter(ServletRequest request, ServletResponse response, | ||
| FilterChain chain) throws IOException, ServletException { | ||
| HttpServletRequest sRequest = (HttpServletRequest)request; | ||
|
|
||
| Entry entry = null; | ||
| try { | ||
| ContextUtil.enter(WebServletConfig.WEB_SERVLET_CONTEXT_NAME); | ||
| entry = SphU.entry(TOTAL_URL_REQUEST, ResourceTypeConstants.COMMON_WEB); | ||
| chain.doFilter(request, response); | ||
| } catch (BlockException e) { | ||
| HttpServletResponse sResponse = (HttpServletResponse)response; | ||
| WebCallbackManager.getUrlBlockHandler().blocked(sRequest, sResponse, e); | ||
| } catch (IOException | ServletException | RuntimeException e2) { | ||
| Tracer.trace(e2); | ||
| throw e2; | ||
| } finally { | ||
| if (entry != null) { | ||
| entry.exit(); | ||
| } | ||
| ContextUtil.exit(); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public void destroy() { | ||
|
|
||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| /* | ||
| * Copyright 1999-2018 Alibaba Group Holding Ltd. | ||
| * | ||
| * 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 com.alibaba.csp.sentinel.adapter.servlet.callback; | ||
|
|
||
| import java.io.IOException; | ||
|
|
||
| import jakarta.servlet.http.HttpServletRequest; | ||
| import jakarta.servlet.http.HttpServletResponse; | ||
|
|
||
| import com.alibaba.csp.sentinel.adapter.servlet.util.FilterUtil; | ||
| import com.alibaba.csp.sentinel.slots.block.BlockException; | ||
|
|
||
| /*** | ||
| * The default {@link UrlBlockHandler}. | ||
| * | ||
| * @author youji.zj | ||
| */ | ||
| public class DefaultUrlBlockHandler implements UrlBlockHandler { | ||
|
|
||
| @Override | ||
| public void blocked(HttpServletRequest request, HttpServletResponse response, BlockException ex) | ||
| throws IOException { | ||
| // Directly redirect to the default flow control (blocked) page or customized block page. | ||
| FilterUtil.blockRequest(request, response); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| /* | ||
| * Copyright 1999-2018 Alibaba Group Holding Ltd. | ||
| * | ||
| * 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 com.alibaba.csp.sentinel.adapter.servlet.callback; | ||
|
|
||
| /*** | ||
| * @author youji.zj | ||
| */ | ||
| public class DefaultUrlCleaner implements UrlCleaner { | ||
|
|
||
| @Override | ||
| public String clean(String originUrl) { | ||
| return originUrl; | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Critical] The parent version
2.0.0-alpha2-SNAPSHOTdoes not match this branch's reactor version (1.8.11-SNAPSHOT, managed via${revision}). Maven cannot resolvecom.alibaba.csp:sentinel-adapter:2.0.0-alpha2-SNAPSHOTfrom remote repositories, so thejdk17-plusbuild fails before compilation. Please use${revision}here (all sibling modules do, e.g.sentinel-web-servlet/pom.xml).