This is an automated email from the ASF dual-hosted git repository.

albumenj pushed a commit to branch 3.3
in repository https://gitbox.apache.org/repos/asf/dubbo.git


The following commit(s) were added to refs/heads/3.3 by this push:
     new 2486674828 Triple Unary Call Support On Servlet (#14314)
2486674828 is described below

commit 2486674828c1a2a7111b63a60a97fb70b0a02e30
Author: Sean Yang <[email protected]>
AuthorDate: Sun Jun 16 17:55:19 2024 +0800

    Triple Unary Call Support On Servlet (#14314)
    
    * servlet
    
    * fix(servlet): Some bugfix
    
    * fix(servlet): Some protocol config read bugfix
---
 .artifacts                                         |   3 +-
 .../org/apache/dubbo/common/io/StreamUtils.java    |   2 +-
 .../apache/dubbo/config/nested/TripleConfig.java   |  58 +++++--
 .../dubbo-demo-spring-boot-provider/pom.xml        |   5 +
 .../src/main/resources/application.yml             |  14 +-
 dubbo-demo/dubbo-demo-spring-boot/pom.xml          |  10 ++
 dubbo-dependencies-bom/pom.xml                     |  14 +-
 .../dubbo-dependencies-zookeeper-curator5/pom.xml  |   6 +
 dubbo-distribution/dubbo-all-shaded/pom.xml        |   9 +-
 dubbo-distribution/dubbo-all/pom.xml               |   8 +
 dubbo-distribution/dubbo-bom/pom.xml               |  10 ++
 dubbo-distribution/pom.xml                         |   6 +
 .../support/servlet/ServletHttpRequestAdaptee.java |   3 +-
 dubbo-plugin/dubbo-triple-servlet/pom.xml          | 107 ++++++++++++
 .../protocol/tri/servlet/HttpMetadataAdapter.java  |  83 ++++++++++
 .../protocol/tri/servlet/ServletStreamChannel.java | 157 ++++++++++++++++++
 .../rpc/protocol/tri/servlet/TripleFilter.java     | 182 +++++++++++++++++++++
 dubbo-plugin/pom.xml                               |   1 +
 .../apache/dubbo/remoting/http12/HttpVersion.java  |  29 ++--
 .../main/java/org/apache/dubbo/rpc/Constants.java  |   1 +
 .../dubbo/rpc/protocol/tri/ServletExchanger.java   |  46 ++++++
 .../rpc/protocol/tri/TripleHttp2Protocol.java      |   5 +-
 .../dubbo/rpc/protocol/tri/TripleProtocol.java     |  26 ++-
 .../protocol/tri/h12/TripleProtocolDetector.java   |  16 +-
 .../mapping/DefaultRequestMappingRegistry.java     |  17 ++
 .../protocol/tri/rest/mapping/RequestMapping.java  |   4 +
 .../tri/rest/mapping/RequestMappingRegistry.java   |   2 +
 .../rest/mapping/condition/MethodsCondition.java   |   4 +
 .../pom.xml                                        |  35 +++-
 .../DubboTriple3AutoConfiguration.java             |  58 +++++++
 .../boot/autoconfigure/SpringBoot3Condition.java   |  25 ++-
 .../src/main/resources/META-INF/spring.factories   |   2 +
 ...rk.boot.autoconfigure.AutoConfiguration.imports |   1 +
 .../dubbo-spring-boot-autoconfigure/pom.xml        |   6 +
 .../DubboTripleAutoConfiguration.java              |  59 +++++++
 .../boot/autoconfigure/SpringBoot12Condition.java  |  25 ++-
 .../src/main/resources/META-INF/spring.factories   |   3 +-
 ...rk.boot.autoconfigure.AutoConfiguration.imports |   1 +
 .../dubbo-spring-boot-starter/pom.xml              |   5 +
 dubbo-spring-boot/pom.xml                          |   1 +
 dubbo-test/dubbo-dependencies-all/pom.xml          |  10 ++
 pom.xml                                            |   6 +
 42 files changed, 975 insertions(+), 90 deletions(-)

diff --git a/.artifacts b/.artifacts
index ff64e78918..41748ff3bf 100644
--- a/.artifacts
+++ b/.artifacts
@@ -94,6 +94,7 @@ dubbo-spring-boot
 dubbo-spring-boot-actuator
 dubbo-spring-boot-actuator-compatible
 dubbo-spring-boot-autoconfigure
+dubbo-spring-boot-3-autoconfigure
 dubbo-spring-boot-autoconfigure-compatible
 dubbo-spring-boot-compatible
 dubbo-observability-spring-boot-starters
@@ -117,4 +118,4 @@ dubbo-plugin-loom
 dubbo-rest-jaxrs
 dubbo-rest-servlet
 dubbo-rest-spring
-
+dubbo-triple-servlet
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/common/io/StreamUtils.java 
b/dubbo-common/src/main/java/org/apache/dubbo/common/io/StreamUtils.java
index 6b72eed44d..b86237639d 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/io/StreamUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/io/StreamUtils.java
@@ -261,7 +261,7 @@ public final class StreamUtils {
         if (in.getClass() == ByteArrayInputStream.class) {
             return readBytes((ByteArrayInputStream) in);
         }
-        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
         byte[] buffer = new byte[4096];
         int bytesRead;
         while ((bytesRead = in.read(buffer)) != -1) {
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/TripleConfig.java 
b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/TripleConfig.java
index 1524671ed6..96b2141b62 100644
--- 
a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/TripleConfig.java
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/TripleConfig.java
@@ -193,6 +193,25 @@ public class TripleConfig implements Serializable {
      */
     private String http3CcAlgorithm;
 
+    /**
+     * Enable servlet support, requests are transport through the servlet 
container,
+     * which only supports unary calls due to protocol limitations
+     * <p>The default value is false.
+     */
+    private Boolean enableServlet;
+
+    /**
+     * The URL patterns that the servlet filter will be registered for.
+     * <p>The default value is '/*'.
+     */
+    private String[] servletFilterUrlPatterns;
+
+    /**
+     * The order of the servlet filter.
+     * <p>The default value is -1000000.
+     */
+    private Integer servletFilterOrder;
+
     public Integer getMaxBodySize() {
         return maxBodySize;
     }
@@ -401,6 +420,30 @@ public class TripleConfig implements Serializable {
         this.http3CcAlgorithm = http3CcAlgorithm;
     }
 
+    public Boolean getEnableServlet() {
+        return enableServlet;
+    }
+
+    public void setEnableServlet(Boolean enableServlet) {
+        this.enableServlet = enableServlet;
+    }
+
+    public String[] getServletFilterUrlPatterns() {
+        return servletFilterUrlPatterns;
+    }
+
+    public void setServletFilterUrlPatterns(String[] servletFilterUrlPatterns) 
{
+        this.servletFilterUrlPatterns = servletFilterUrlPatterns;
+    }
+
+    public Integer getServletFilterOrder() {
+        return servletFilterOrder;
+    }
+
+    public void setServletFilterOrder(Integer servletFilterOrder) {
+        this.servletFilterOrder = servletFilterOrder;
+    }
+
     public void checkDefault() {
         if (maxBodySize == null) {
             maxBodySize = 1 << 23;
@@ -438,20 +481,5 @@ public class TripleConfig implements Serializable {
         if (maxHeaderListSize == null) {
             maxHeaderListSize = 1 << 15;
         }
-        if (http3InitialMaxData == null) {
-            http3InitialMaxData = 1 << 23;
-        }
-        if (http3InitialMaxStreamDataBidiLocal == null) {
-            http3InitialMaxStreamDataBidiLocal = 1 << 20;
-        }
-        if (http3InitialMaxStreamDataBidiRemote == null) {
-            http3InitialMaxStreamDataBidiRemote = 1 << 20;
-        }
-        if (http3InitialMaxStreamsBidi == null) {
-            http3InitialMaxStreamsBidi = (long) 1 << 30;
-        }
-        if (http3InitialMaxStreamsUni == null) {
-            http3InitialMaxStreamsUni = (long) 1 << 30;
-        }
     }
 }
diff --git 
a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-provider/pom.xml 
b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-provider/pom.xml
index 2c0d523449..88b6160ba4 100644
--- a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-provider/pom.xml
+++ b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-provider/pom.xml
@@ -92,6 +92,11 @@
       <version>${project.version}</version>
     </dependency>
 
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-web</artifactId>
+    </dependency>
+
     <dependency>
       <groupId>org.apache.dubbo</groupId>
       <artifactId>dubbo-spring-boot-starter</artifactId>
diff --git 
a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-provider/src/main/resources/application.yml
 
b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-provider/src/main/resources/application.yml
index b1789be60f..b75b8578e9 100644
--- 
a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-provider/src/main/resources/application.yml
+++ 
b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-provider/src/main/resources/application.yml
@@ -21,9 +21,12 @@ spring:
 dubbo:
   application:
     name: ${spring.application.name}
+    qos-enable: false
   protocol:
-    name: dubbo
-    port: -1
+    name: tri
+    port: ${server.port}
+    triple:
+      enable-servlet: true
   registry:
     id: zk-registry
     address: zookeeper://127.0.0.1:2181
@@ -41,3 +44,10 @@ dubbo:
       exporter:
         enabled: true
     enable-metadata: true
+
+server:
+  port: 8081
+  http2:
+    enabled: true
+  tomcat:
+    keep-alive-timeout: 180000
diff --git a/dubbo-demo/dubbo-demo-spring-boot/pom.xml 
b/dubbo-demo/dubbo-demo-spring-boot/pom.xml
index 5466f619f8..2d63b81e5e 100644
--- a/dubbo-demo/dubbo-demo-spring-boot/pom.xml
+++ b/dubbo-demo/dubbo-demo-spring-boot/pom.xml
@@ -65,4 +65,14 @@
       </dependency>
     </dependencies>
   </dependencyManagement>
+
+  <profiles>
+    <profile>
+      <id>spring-boot-3</id>
+      <properties>
+        <spring-boot.version>3.2.1</spring-boot.version>
+        
<spring-boot-maven-plugin.version>3.2.1</spring-boot-maven-plugin.version>
+      </properties>
+    </profile>
+  </profiles>
 </project>
diff --git a/dubbo-dependencies-bom/pom.xml b/dubbo-dependencies-bom/pom.xml
index b8d0eb5499..f9a5420ff5 100644
--- a/dubbo-dependencies-bom/pom.xml
+++ b/dubbo-dependencies-bom/pom.xml
@@ -109,6 +109,7 @@
     <protobuf-java_version>3.25.3</protobuf-java_version>
     <javax_annotation-api_version>1.3.2</javax_annotation-api_version>
     <servlet_version>3.1.0</servlet_version>
+    <servlet6_version>6.1.0</servlet6_version>
     <jetty_version>9.4.54.v20240208</jetty_version>
     <validation_new_version>3.1.0</validation_new_version>
     <validation_version>1.1.0.Final</validation_version>
@@ -412,7 +413,12 @@
         <artifactId>javax.servlet-api</artifactId>
         <version>${servlet_version}</version>
       </dependency>
-
+      <dependency>
+        <groupId>jakarta.servlet</groupId>
+        <artifactId>jakarta.servlet-api</artifactId>
+        <version>${servlet6_version}</version>
+        <scope>provided</scope>
+      </dependency>
       <dependency>
         <groupId>com.squareup.okhttp3</groupId>
         <artifactId>okhttp</artifactId>
@@ -1036,6 +1042,12 @@
         </plugins>
       </build>
     </profile>
+    <profile>
+      <id>skip-spotless</id>
+      <properties>
+        <spotless.skip>true</spotless.skip>
+      </properties>
+    </profile>
   </profiles>
 
 </project>
diff --git a/dubbo-dependencies/dubbo-dependencies-zookeeper-curator5/pom.xml 
b/dubbo-dependencies/dubbo-dependencies-zookeeper-curator5/pom.xml
index a850d77231..0577d9d0ae 100644
--- a/dubbo-dependencies/dubbo-dependencies-zookeeper-curator5/pom.xml
+++ b/dubbo-dependencies/dubbo-dependencies-zookeeper-curator5/pom.xml
@@ -204,5 +204,11 @@
         </plugins>
       </build>
     </profile>
+    <profile>
+      <id>skip-spotless</id>
+      <properties>
+        <spotless.skip>true</spotless.skip>
+      </properties>
+    </profile>
   </profiles>
 </project>
diff --git a/dubbo-distribution/dubbo-all-shaded/pom.xml 
b/dubbo-distribution/dubbo-all-shaded/pom.xml
index bbd07fdbfb..ba8b8e4584 100644
--- a/dubbo-distribution/dubbo-all-shaded/pom.xml
+++ b/dubbo-distribution/dubbo-all-shaded/pom.xml
@@ -133,7 +133,13 @@
       <scope>compile</scope>
       <optional>true</optional>
     </dependency>
-
+    <dependency>
+      <groupId>org.apache.dubbo</groupId>
+      <artifactId>dubbo-triple-servlet</artifactId>
+      <version>${project.version}</version>
+      <scope>compile</scope>
+      <optional>true</optional>
+    </dependency>
     <!-- metadata -->
     <dependency>
       <groupId>org.apache.dubbo</groupId>
@@ -488,6 +494,7 @@
                   <include>org.apache.dubbo:dubbo-rest-jaxrs</include>
                   <include>org.apache.dubbo:dubbo-rest-servlet</include>
                   <include>org.apache.dubbo:dubbo-rest-spring</include>
+                  <include>org.apache.dubbo:dubbo-triple-servlet</include>
                   <include>org.apache.dubbo:dubbo-serialization-api</include>
                   
<include>org.apache.dubbo:dubbo-serialization-hessian2</include>
                   
<include>org.apache.dubbo:dubbo-serialization-fastjson2</include>
diff --git a/dubbo-distribution/dubbo-all/pom.xml 
b/dubbo-distribution/dubbo-all/pom.xml
index 366b4ac7de..ba8316e135 100644
--- a/dubbo-distribution/dubbo-all/pom.xml
+++ b/dubbo-distribution/dubbo-all/pom.xml
@@ -290,6 +290,13 @@
       <scope>compile</scope>
       <optional>true</optional>
     </dependency>
+    <dependency>
+      <groupId>org.apache.dubbo</groupId>
+      <artifactId>dubbo-triple-servlet</artifactId>
+      <version>${project.version}</version>
+      <scope>compile</scope>
+      <optional>true</optional>
+    </dependency>
 
     <!-- registry -->
     <dependency>
@@ -536,6 +543,7 @@
                   <include>org.apache.dubbo:dubbo-rest-jaxrs</include>
                   <include>org.apache.dubbo:dubbo-rest-servlet</include>
                   <include>org.apache.dubbo:dubbo-rest-spring</include>
+                  <include>org.apache.dubbo:dubbo-triple-servlet</include>
                   <include>org.apache.dubbo:dubbo-serialization-api</include>
                   
<include>org.apache.dubbo:dubbo-serialization-hessian2</include>
                   
<include>org.apache.dubbo:dubbo-serialization-fastjson2</include>
diff --git a/dubbo-distribution/dubbo-bom/pom.xml 
b/dubbo-distribution/dubbo-bom/pom.xml
index a9df0e8c35..11c897b9b8 100644
--- a/dubbo-distribution/dubbo-bom/pom.xml
+++ b/dubbo-distribution/dubbo-bom/pom.xml
@@ -344,6 +344,11 @@
         <artifactId>dubbo-rest-spring</artifactId>
         <version>${project.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.apache.dubbo</groupId>
+        <artifactId>dubbo-triple-servlet</artifactId>
+        <version>${project.version}</version>
+      </dependency>
 
       <!-- registry -->
       <dependency>
@@ -490,6 +495,11 @@
         <artifactId>dubbo-spring-boot-autoconfigure</artifactId>
         <version>${project.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.apache.dubbo</groupId>
+        <artifactId>dubbo-spring-boot-3-autoconfigure</artifactId>
+        <version>${project.version}</version>
+      </dependency>
       <dependency>
         <groupId>org.apache.dubbo</groupId>
         <artifactId>dubbo-spring-boot-compatible</artifactId>
diff --git a/dubbo-distribution/pom.xml b/dubbo-distribution/pom.xml
index e3d4ca1a88..a61e230e9b 100644
--- a/dubbo-distribution/pom.xml
+++ b/dubbo-distribution/pom.xml
@@ -115,5 +115,11 @@
         </plugins>
       </build>
     </profile>
+    <profile>
+      <id>skip-spotless</id>
+      <properties>
+        <spotless.skip>true</spotless.skip>
+      </properties>
+    </profile>
   </profiles>
 </project>
diff --git 
a/dubbo-plugin/dubbo-rest-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/servlet/ServletHttpRequestAdaptee.java
 
b/dubbo-plugin/dubbo-rest-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/servlet/ServletHttpRequestAdaptee.java
index 102ae8402b..6099a6c8d3 100644
--- 
a/dubbo-plugin/dubbo-rest-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/servlet/ServletHttpRequestAdaptee.java
+++ 
b/dubbo-plugin/dubbo-rest-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/servlet/ServletHttpRequestAdaptee.java
@@ -19,6 +19,7 @@ package 
org.apache.dubbo.rpc.protocol.tri.rest.support.servlet;
 import org.apache.dubbo.common.utils.CollectionUtils;
 import org.apache.dubbo.remoting.http12.HttpChannel;
 import org.apache.dubbo.remoting.http12.HttpMetadata;
+import org.apache.dubbo.remoting.http12.HttpVersion;
 import org.apache.dubbo.remoting.http12.message.DefaultHttpRequest;
 
 import javax.servlet.AsyncContext;
@@ -319,7 +320,7 @@ public class ServletHttpRequestAdaptee extends 
DefaultHttpRequest implements Htt
 
     @Override
     public String getProtocol() {
-        return isHttp2() ? "HTTP/2.0" : "HTTP/1.1";
+        return isHttp2() ? HttpVersion.HTTP2.getProtocol() : 
HttpVersion.HTTP1.getProtocol();
     }
 
     @Override
diff --git a/dubbo-plugin/dubbo-triple-servlet/pom.xml 
b/dubbo-plugin/dubbo-triple-servlet/pom.xml
new file mode 100644
index 0000000000..ee6d22318a
--- /dev/null
+++ b/dubbo-plugin/dubbo-triple-servlet/pom.xml
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You 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.
+  -->
+<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>org.apache.dubbo</groupId>
+    <artifactId>dubbo-plugin</artifactId>
+    <version>${revision}</version>
+    <relativePath>../pom.xml</relativePath>
+  </parent>
+
+  <artifactId>dubbo-triple-servlet</artifactId>
+
+  <properties>
+    <servlet4_version>4.0.1</servlet4_version>
+    
<sources_directory>${project.build.directory}/generated-sources/java/org/apache/dubbo/rpc/protocol/tri/servlet/jakarta</sources_directory>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.dubbo</groupId>
+      <artifactId>dubbo-rpc-triple</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>javax.servlet</groupId>
+      <artifactId>javax.servlet-api</artifactId>
+      <version>${servlet4_version}</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>jakarta.servlet</groupId>
+      <artifactId>jakarta.servlet-api</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.dubbo</groupId>
+      <artifactId>dubbo-remoting-netty4</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-antrun-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>copy-sources</id>
+            <goals>
+              <goal>run</goal>
+            </goals>
+            <phase>generate-sources</phase>
+            <configuration>
+              <target>
+                <copy overwrite="true" todir="${sources_directory}">
+                  <fileset 
dir="src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet" />
+                </copy>
+                <replace token="tri.servlet;" value="tri.servlet.jakarta;">
+                  <fileset dir="${sources_directory}" />
+                </replace>
+                <replace token="javax.servlet" value="jakarta.servlet">
+                  <fileset dir="${sources_directory}" />
+                </replace>
+              </target>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>build-helper-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>add-sources</id>
+            <goals>
+              <goal>add-source</goal>
+            </goals>
+            <phase>generate-sources</phase>
+            <configuration>
+              <sources>
+                
<source>${project.build.directory}/generated-sources/java</source>
+              </sources>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git 
a/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/HttpMetadataAdapter.java
 
b/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/HttpMetadataAdapter.java
new file mode 100644
index 0000000000..15af2654c7
--- /dev/null
+++ 
b/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/HttpMetadataAdapter.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.dubbo.rpc.protocol.tri.servlet;
+
+import org.apache.dubbo.remoting.http12.HttpHeaders;
+import org.apache.dubbo.remoting.http12.h2.Http2Header;
+
+import javax.servlet.http.HttpServletRequest;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+
+final class HttpMetadataAdapter implements Http2Header {
+
+    private final HttpServletRequest request;
+
+    private HttpHeaders headers;
+
+    HttpMetadataAdapter(HttpServletRequest request) {
+        this.request = request;
+    }
+
+    @Override
+    public HttpHeaders headers() {
+        HttpHeaders headers = this.headers;
+        if (headers == null) {
+            headers = new HttpHeaders();
+            Enumeration<String> en = request.getHeaderNames();
+            while (en.hasMoreElements()) {
+                String key = en.nextElement();
+                List<String> values = new ArrayList<>(1);
+                Enumeration<String> ven = request.getHeaders(key);
+                while (ven.hasMoreElements()) {
+                    values.add(ven.nextElement());
+                }
+                headers.put(key, values);
+            }
+            this.headers = headers;
+        }
+        return headers;
+    }
+
+    @Override
+    public String method() {
+        return request.getMethod();
+    }
+
+    @Override
+    public String path() {
+        String query = request.getQueryString();
+        return query == null ? request.getRequestURI() : 
request.getRequestURI() + '?' + query;
+    }
+
+    @Override
+    public String status() {
+        return null;
+    }
+
+    @Override
+    public long id() {
+        return -1L;
+    }
+
+    @Override
+    public boolean isEndStream() {
+        return false;
+    }
+}
diff --git 
a/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/ServletStreamChannel.java
 
b/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/ServletStreamChannel.java
new file mode 100644
index 0000000000..d5f0c7d39f
--- /dev/null
+++ 
b/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/ServletStreamChannel.java
@@ -0,0 +1,157 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.dubbo.rpc.protocol.tri.servlet;
+
+import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.remoting.http12.HttpHeaderNames;
+import org.apache.dubbo.remoting.http12.HttpHeaders;
+import org.apache.dubbo.remoting.http12.HttpMetadata;
+import org.apache.dubbo.remoting.http12.HttpOutputMessage;
+import org.apache.dubbo.remoting.http12.HttpVersion;
+import org.apache.dubbo.remoting.http12.h2.H2StreamChannel;
+import org.apache.dubbo.remoting.http12.h2.Http2Header;
+import org.apache.dubbo.remoting.http12.h2.Http2OutputMessage;
+import org.apache.dubbo.remoting.http12.h2.Http2OutputMessageFrame;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import java.io.ByteArrayOutputStream;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.CompletableFuture;
+
+import static 
org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_IO_EXCEPTION;
+
+final class ServletStreamChannel implements H2StreamChannel {
+
+    private static final ErrorTypeAwareLogger LOG = 
LoggerFactory.getErrorTypeAwareLogger(ServletStreamChannel.class);
+
+    private final HttpServletRequest request;
+    private final HttpServletResponse response;
+    private final AsyncContext context;
+
+    ServletStreamChannel(HttpServletRequest request, HttpServletResponse 
response, AsyncContext context) {
+        this.request = request;
+        this.response = response;
+        this.context = context;
+    }
+
+    @Override
+    public CompletableFuture<Void> writeResetFrame(long errorCode) {
+        try {
+            if (errorCode == 0L) {
+                response.getOutputStream().close();
+            } else if (errorCode >= 300 && errorCode < 600) {
+                response.sendError((int) errorCode);
+            } else {
+                
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+            }
+        } catch (Throwable t) {
+            LOG.error(COMMON_IO_EXCEPTION, "", "", "Failed to close response", 
t);
+        } finally {
+            context.complete();
+        }
+        return CompletableFuture.completedFuture(null);
+    }
+
+    @Override
+    public Http2OutputMessage newOutputMessage(boolean endStream) {
+        return new Http2OutputMessageFrame(new ByteArrayOutputStream(256), 
endStream);
+    }
+
+    @Override
+    public CompletableFuture<Void> writeHeader(HttpMetadata httpMetadata) {
+        boolean endStream = ((Http2Header) httpMetadata).isEndStream();
+        try {
+            HttpHeaders headers = httpMetadata.headers();
+            if (endStream) {
+                response.setTrailerFields(() -> {
+                    Map<String, String> map = new HashMap<>();
+                    for (Entry<String, List<String>> entry : 
headers.entrySet()) {
+                        map.put(entry.getKey(), entry.getValue().get(0));
+                    }
+                    return map;
+                });
+            } else {
+                for (Entry<String, List<String>> entry : headers.entrySet()) {
+                    String key = entry.getKey();
+                    List<String> values = entry.getValue();
+                    if (HttpHeaderNames.STATUS.getName().equals(key)) {
+                        response.setStatus(Integer.parseInt(values.get(0)));
+                        continue;
+                    }
+                    if (values.size() == 1) {
+                        response.setHeader(key, values.get(0));
+                    } else {
+                        for (int i = 0, size = values.size(); i < size; i++) {
+                            response.addHeader(key, values.get(i));
+                        }
+                    }
+                }
+            }
+        } catch (Throwable t) {
+            LOG.error(COMMON_IO_EXCEPTION, "", "", "Failed to write header", 
t);
+        } finally {
+            if (endStream) {
+                context.complete();
+            }
+        }
+        return CompletableFuture.completedFuture(null);
+    }
+
+    @Override
+    public CompletableFuture<Void> writeMessage(HttpOutputMessage 
httpOutputMessage) {
+        boolean endStream = ((Http2OutputMessage) 
httpOutputMessage).isEndStream();
+        try {
+            ByteArrayOutputStream bos = (ByteArrayOutputStream) 
httpOutputMessage.getBody();
+            ServletOutputStream out = response.getOutputStream();
+            if 
(!HttpVersion.HTTP2.getProtocol().equals(request.getProtocol())) {
+                response.setContentLength(bos.size());
+            }
+            bos.writeTo(out);
+            out.flush();
+        } catch (Throwable t) {
+            LOG.error(COMMON_IO_EXCEPTION, "", "", "Failed to write message", 
t);
+        } finally {
+            if (endStream) {
+                context.complete();
+            }
+        }
+        return CompletableFuture.completedFuture(null);
+    }
+
+    @Override
+    public SocketAddress remoteAddress() {
+        return InetSocketAddress.createUnresolved(request.getRemoteAddr(), 
request.getRemotePort());
+    }
+
+    @Override
+    public SocketAddress localAddress() {
+        return InetSocketAddress.createUnresolved(request.getLocalAddr(), 
request.getLocalPort());
+    }
+
+    @Override
+    public void flush() {}
+}
diff --git 
a/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/TripleFilter.java
 
b/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/TripleFilter.java
new file mode 100644
index 0000000000..17f1d107a6
--- /dev/null
+++ 
b/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/TripleFilter.java
@@ -0,0 +1,182 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.dubbo.rpc.protocol.tri.servlet;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.io.StreamUtils;
+import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.remoting.http12.h2.H2StreamChannel;
+import org.apache.dubbo.remoting.http12.h2.Http2InputMessageFrame;
+import org.apache.dubbo.remoting.http12.h2.Http2ServerTransportListenerFactory;
+import org.apache.dubbo.remoting.http12.h2.Http2TransportListener;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.PathResolver;
+import org.apache.dubbo.rpc.model.FrameworkModel;
+import org.apache.dubbo.rpc.protocol.tri.ServletExchanger;
+import org.apache.dubbo.rpc.protocol.tri.TripleConstant;
+import org.apache.dubbo.rpc.protocol.tri.TripleHeaderEnum;
+import org.apache.dubbo.rpc.protocol.tri.TripleProtocol;
+import org.apache.dubbo.rpc.protocol.tri.h12.grpc.GrpcHeaderNames;
+import 
org.apache.dubbo.rpc.protocol.tri.h12.grpc.GrpcHttp2ServerTransportListener;
+import org.apache.dubbo.rpc.protocol.tri.h12.grpc.GrpcUtils;
+import 
org.apache.dubbo.rpc.protocol.tri.h12.http2.GenericHttp2ServerTransportListenerFactory;
+import 
org.apache.dubbo.rpc.protocol.tri.rest.mapping.DefaultRequestMappingRegistry;
+import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingRegistry;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Set;
+
+import static 
org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_IO_EXCEPTION;
+import static 
org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;
+
+public class TripleFilter implements Filter {
+
+    private static final ErrorTypeAwareLogger LOG = 
LoggerFactory.getErrorTypeAwareLogger(TripleFilter.class);
+
+    private PathResolver pathResolver;
+    private RequestMappingRegistry mappingRegistry;
+    private int defaultTimeout;
+
+    @Override
+    public void init(FilterConfig config) {
+        FrameworkModel frameworkModel = FrameworkModel.defaultModel();
+        pathResolver = frameworkModel.getDefaultExtension(PathResolver.class);
+        mappingRegistry = 
frameworkModel.getBeanFactory().getOrRegisterBean(DefaultRequestMappingRegistry.class);
+        String timeoutString = config.getInitParameter("timeout");
+        defaultTimeout = timeoutString == null ? 180_000 : 
Integer.parseInt(timeoutString);
+    }
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, 
FilterChain chain)
+            throws ServletException, IOException {
+        HttpServletRequest hRequest = (HttpServletRequest) request;
+        HttpServletResponse hResponse = (HttpServletResponse) response;
+
+        if (!hasServiceMapping(hRequest) && 
!mappingRegistry.exists(hRequest.getRequestURI(), hRequest.getMethod())) {
+            chain.doFilter(request, response);
+            return;
+        }
+
+        AsyncContext context = request.startAsync();
+        try {
+            H2StreamChannel streamChannel = new ServletStreamChannel(hRequest, 
hResponse, context);
+            Http2TransportListener listener = 
determineHttp2ServerTransportListenerFactory(request.getContentType())
+                    .newInstance(streamChannel, ServletExchanger.getUrl(), 
FrameworkModel.defaultModel());
+
+            context.setTimeout(resolveTimeout(hRequest, listener instanceof 
GrpcHttp2ServerTransportListener));
+
+            listener.onMetadata(new HttpMetadataAdapter(hRequest));
+
+            ByteArrayOutputStream os;
+            try {
+                os = new ByteArrayOutputStream(1024);
+                StreamUtils.copy(request.getInputStream(), os);
+            } catch (Throwable t) {
+                LOG.error(COMMON_IO_EXCEPTION, "", "", "Failed to read input", 
t);
+                try {
+                    hResponse.sendError(HttpServletResponse.SC_BAD_REQUEST);
+                } finally {
+                    context.complete();
+                }
+                return;
+            }
+            listener.onData(new Http2InputMessageFrame(new 
ByteArrayInputStream(os.toByteArray()), true));
+        } catch (Throwable t) {
+            LOG.error(INTERNAL_ERROR, "", "", "Failed to process request", t);
+            try {
+                
hResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+            } finally {
+                context.complete();
+            }
+        }
+    }
+
+    @Override
+    public void destroy() {}
+
+    private boolean hasServiceMapping(HttpServletRequest request) {
+        String uri = request.getRequestURI();
+
+        int index = uri.indexOf('/', 1);
+        if (index == -1) {
+            return false;
+        }
+        if (uri.indexOf('/', index + 1) != -1) {
+            return false;
+        }
+
+        String serviceName = uri.substring(1, index);
+        String version = 
request.getHeader(TripleHeaderEnum.SERVICE_VERSION.getHeader());
+        String group = 
request.getHeader(TripleHeaderEnum.SERVICE_GROUP.getHeader());
+        String key = URL.buildKey(serviceName, group, version);
+        Invoker<?> invoker = pathResolver.resolve(key);
+        if (invoker == null && TripleProtocol.RESOLVE_FALLBACK_TO_DEFAULT) {
+            invoker = pathResolver.resolve(URL.buildKey(serviceName, group, 
TripleConstant.DEFAULT_VERSION));
+            if (invoker == null) {
+                return pathResolver.resolve(serviceName) != null;
+            }
+        }
+
+        return true;
+    }
+
+    private Http2ServerTransportListenerFactory 
determineHttp2ServerTransportListenerFactory(String contentType) {
+        Set<Http2ServerTransportListenerFactory> 
http2ServerTransportListenerFactories = FrameworkModel.defaultModel()
+                .getExtensionLoader(Http2ServerTransportListenerFactory.class)
+                .getSupportedExtensionInstances();
+        for (Http2ServerTransportListenerFactory factory : 
http2ServerTransportListenerFactories) {
+            if (factory.supportContentType(contentType)) {
+                return factory;
+            }
+        }
+        return GenericHttp2ServerTransportListenerFactory.INSTANCE;
+    }
+
+    private int resolveTimeout(HttpServletRequest request, boolean isGrpc) {
+        try {
+            if (isGrpc) {
+                String timeoutString = 
request.getHeader(GrpcHeaderNames.GRPC_TIMEOUT.getName());
+                if (timeoutString != null) {
+                    Long timeout = 
GrpcUtils.parseTimeoutToMills(timeoutString);
+                    if (timeout != null) {
+                        return timeout.intValue() + 2000;
+                    }
+                }
+            } else {
+                String timeoutString = 
request.getHeader(TripleHeaderEnum.SERVICE_TIMEOUT.getHeader());
+                if (timeoutString != null) {
+                    return Integer.parseInt(timeoutString) + 2000;
+                }
+            }
+        } catch (Throwable ignored) {
+        }
+        return defaultTimeout;
+    }
+}
diff --git a/dubbo-plugin/pom.xml b/dubbo-plugin/pom.xml
index fa1466ef0a..df9b5dccde 100644
--- a/dubbo-plugin/pom.xml
+++ b/dubbo-plugin/pom.xml
@@ -43,6 +43,7 @@
     <module>dubbo-rest-jaxrs</module>
     <module>dubbo-rest-servlet</module>
     <module>dubbo-rest-spring</module>
+    <module>dubbo-triple-servlet</module>
   </modules>
   <properties>
     <skip_maven_deploy>false</skip_maven_deploy>
diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMappingRegistry.java
 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpVersion.java
similarity index 61%
copy from 
dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMappingRegistry.java
copy to 
dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpVersion.java
index b7dfb55994..f7fa9f2375 100644
--- 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMappingRegistry.java
+++ 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpVersion.java
@@ -14,22 +14,25 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.rpc.protocol.tri.rest.mapping;
+package org.apache.dubbo.remoting.http12;
 
-import org.apache.dubbo.remoting.http12.HttpRequest;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.HandlerMeta;
+public enum HttpVersion {
+    HTTP1("http1", "HTTP/1.1"),
+    HTTP2("http2", "HTTP/2.0");
 
-/**
- * RequestMappingRegistry used for registering and unregistering rest request 
mappings.
- */
-public interface RequestMappingRegistry {
-
-    void register(Invoker<?> invoker);
+    private final String version;
+    private final String protocol;
 
-    void unregister(Invoker<?> invoker);
+    HttpVersion(String version, String protocol) {
+        this.version = version;
+        this.protocol = protocol;
+    }
 
-    HandlerMeta lookup(HttpRequest request);
+    public String getVersion() {
+        return version;
+    }
 
-    void destroy();
+    public String getProtocol() {
+        return protocol;
+    }
 }
diff --git 
a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Constants.java 
b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Constants.java
index 0e81a1433b..0e6100827d 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Constants.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Constants.java
@@ -106,6 +106,7 @@ public interface Constants {
     String H2_SETTINGS_PASS_THROUGH_STANDARD_HTTP_HEADERS = 
"dubbo.rpc.tri.pass-through-standard-http-headers";
 
     String H3_SETTINGS_HTTP3_ENABLE = "dubbo.protocol.triple.enable-http3";
+    String H3_SETTINGS_SERVLET_ENABLE = "dubbo.protocol.triple.enable-servlet";
 
     String ADAPTIVE_LOADBALANCE_ATTACHMENT_KEY = "lb_adaptive";
     String ADAPTIVE_LOADBALANCE_START_TIME = "adaptive_startTime";
diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/ServletExchanger.java
 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/ServletExchanger.java
new file mode 100644
index 0000000000..9e899b66d8
--- /dev/null
+++ 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/ServletExchanger.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.dubbo.rpc.protocol.tri;
+
+import org.apache.dubbo.common.URL;
+
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicReference;
+
+public final class ServletExchanger {
+
+    private static final AtomicReference<URL> url = new AtomicReference<>();
+    private static final AtomicReference<Integer> serverPort = new 
AtomicReference<>();
+
+    private ServletExchanger() {}
+
+    public static void bind(URL url) {
+        ServletExchanger.url.compareAndSet(null, url);
+    }
+
+    public static void bindServerPort(int serverPort) {
+        ServletExchanger.serverPort.compareAndSet(null, serverPort);
+    }
+
+    public static URL getUrl() {
+        return Objects.requireNonNull(url.get(), "ServletExchanger not bound 
to triple protocol");
+    }
+
+    public static Integer getServerPort() {
+        return serverPort.get();
+    }
+}
diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleHttp2Protocol.java
 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleHttp2Protocol.java
index 7566851c8d..011881ddc9 100644
--- 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleHttp2Protocol.java
+++ 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleHttp2Protocol.java
@@ -25,6 +25,7 @@ import org.apache.dubbo.remoting.api.AbstractWireProtocol;
 import org.apache.dubbo.remoting.api.pu.ChannelHandlerPretender;
 import org.apache.dubbo.remoting.api.pu.ChannelOperator;
 import org.apache.dubbo.remoting.api.ssl.ContextOperator;
+import org.apache.dubbo.remoting.http12.HttpVersion;
 import org.apache.dubbo.remoting.http12.netty4.HttpWriteQueueHandler;
 import org.apache.dubbo.remoting.http12.netty4.h1.NettyHttp1Codec;
 import org.apache.dubbo.remoting.http12.netty4.h1.NettyHttp1ConnectionHandler;
@@ -116,13 +117,13 @@ public class TripleHttp2Protocol extends 
AbstractWireProtocol implements ScopeMo
         List<ChannelHandler> channelHandlerPretenders = new ArrayList<>();
         try {
             // h1
-            if 
(TripleProtocolDetector.HttpVersion.HTTP1.getVersion().equals(httpVersion)) {
+            if (HttpVersion.HTTP1.getVersion().equals(httpVersion)) {
                 configurerHttp1Handlers(url, channelHandlerPretenders);
                 return;
             }
 
             // h2
-            if 
(TripleProtocolDetector.HttpVersion.HTTP2.getVersion().equals(httpVersion)) {
+            if (HttpVersion.HTTP2.getVersion().equals(httpVersion)) {
                 configurerHttp2Handlers(url, channelHandlerPretenders);
             }
         } finally {
diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleProtocol.java
 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleProtocol.java
index 6286dd7f46..9e5088a25d 100644
--- 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleProtocol.java
+++ 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleProtocol.java
@@ -23,11 +23,11 @@ import org.apache.dubbo.common.logger.Logger;
 import org.apache.dubbo.common.logger.LoggerFactory;
 import org.apache.dubbo.common.threadpool.manager.ExecutorRepository;
 import org.apache.dubbo.common.utils.ExecutorUtil;
+import org.apache.dubbo.common.utils.NetUtils;
 import org.apache.dubbo.remoting.api.connection.AbstractConnectionClient;
 import org.apache.dubbo.remoting.api.pu.DefaultPuHandler;
 import org.apache.dubbo.remoting.exchange.Http3Exchanger;
 import org.apache.dubbo.remoting.exchange.PortUnificationExchanger;
-import org.apache.dubbo.rpc.Constants;
 import org.apache.dubbo.rpc.Exporter;
 import org.apache.dubbo.rpc.Invoker;
 import org.apache.dubbo.rpc.PathResolver;
@@ -53,11 +53,14 @@ import static 
org.apache.dubbo.common.constants.CommonConstants.THREADPOOL_KEY;
 import static 
org.apache.dubbo.common.constants.CommonConstants.THREAD_NAME_KEY;
 import static org.apache.dubbo.config.Constants.CLIENT_THREAD_POOL_NAME;
 import static org.apache.dubbo.config.Constants.SERVER_THREAD_POOL_NAME;
+import static org.apache.dubbo.remoting.Constants.BIND_PORT_KEY;
 import static org.apache.dubbo.rpc.Constants.H2_SETTINGS_IGNORE_1_0_0_KEY;
 import static 
org.apache.dubbo.rpc.Constants.H2_SETTINGS_PASS_THROUGH_STANDARD_HTTP_HEADERS;
 import static 
org.apache.dubbo.rpc.Constants.H2_SETTINGS_RESOLVE_FALLBACK_TO_DEFAULT_KEY;
 import static 
org.apache.dubbo.rpc.Constants.H2_SETTINGS_SUPPORT_NO_LOWER_HEADER_KEY;
 import static org.apache.dubbo.rpc.Constants.H3_SETTINGS_HTTP3_ENABLE;
+import static org.apache.dubbo.rpc.Constants.H3_SETTINGS_SERVLET_ENABLE;
+import static org.apache.dubbo.rpc.Constants.HTTP3_KEY;
 
 public class TripleProtocol extends AbstractProtocol {
 
@@ -73,6 +76,7 @@ public class TripleProtocol extends AbstractProtocol {
     public static boolean RESOLVE_FALLBACK_TO_DEFAULT = true;
     public static boolean PASS_THROUGH_STANDARD_HTTP_HEADERS = false;
     public static boolean HTTP3_ENABLED = false;
+    public static boolean SERVLET_ENABLED = false;
 
     public TripleProtocol(FrameworkModel frameworkModel) {
         this.frameworkModel = frameworkModel;
@@ -90,6 +94,7 @@ public class TripleProtocol extends AbstractProtocol {
 
         Configuration globalConf = 
ConfigurationUtils.getGlobalConfiguration(frameworkModel.defaultApplication());
         HTTP3_ENABLED = globalConf.getBoolean(H3_SETTINGS_HTTP3_ENABLE, false);
+        SERVLET_ENABLED = globalConf.getBoolean(H3_SETTINGS_SERVLET_ENABLE, 
false);
     }
 
     @Override
@@ -166,7 +171,22 @@ public class TripleProtocol extends AbstractProtocol {
         ExecutorRepository.getInstance(url.getOrDefaultApplicationModel())
                 .createExecutorIfAbsent(ExecutorUtil.setThreadName(url, 
SERVER_THREAD_POOL_NAME));
 
-        PortUnificationExchanger.bind(url, new DefaultPuHandler());
+        boolean bindPort = true;
+        if (SERVLET_ENABLED) {
+            int port = url.getParameter(BIND_PORT_KEY, url.getPort());
+            Integer serverPort = ServletExchanger.getServerPort();
+            if (serverPort == null) {
+                if (NetUtils.isPortInUsed(port)) {
+                    bindPort = false;
+                }
+            } else if (serverPort == port) {
+                bindPort = false;
+            }
+            ServletExchanger.bind(url);
+        }
+        if (bindPort) {
+            PortUnificationExchanger.bind(url, new DefaultPuHandler());
+        }
 
         if (isHttp3Enabled(url)) {
             Http3Exchanger.bind(url);
@@ -216,6 +236,6 @@ public class TripleProtocol extends AbstractProtocol {
     }
 
     public static boolean isHttp3Enabled(URL url) {
-        return HTTP3_ENABLED || url.getParameter(Constants.HTTP3_KEY, false);
+        return HTTP3_ENABLED || url.getParameter(HTTP3_KEY, false);
     }
 }
diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/TripleProtocolDetector.java
 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/TripleProtocolDetector.java
index 5fa91a97f7..213d97624a 100644
--- 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/TripleProtocolDetector.java
+++ 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/TripleProtocolDetector.java
@@ -21,6 +21,7 @@ import 
org.apache.dubbo.remoting.buffer.ByteBufferBackedChannelBuffer;
 import org.apache.dubbo.remoting.buffer.ChannelBuffer;
 import org.apache.dubbo.remoting.buffer.ChannelBuffers;
 import org.apache.dubbo.remoting.http12.HttpMethods;
+import org.apache.dubbo.remoting.http12.HttpVersion;
 
 import io.netty.handler.codec.http2.Http2CodecUtil;
 
@@ -74,19 +75,4 @@ public class TripleProtocolDetector implements 
ProtocolDetector {
         }
         return false;
     }
-
-    public enum HttpVersion {
-        HTTP1("http1"),
-        HTTP2("http2");
-
-        private final String version;
-
-        HttpVersion(String version) {
-            this.version = version;
-        }
-
-        public String getVersion() {
-            return version;
-        }
-    }
 }
diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java
 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java
index 81680ac4f2..ffb3502778 100644
--- 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java
+++ 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java
@@ -206,6 +206,23 @@ public final class DefaultRequestMappingRegistry 
implements RequestMappingRegist
         return handler;
     }
 
+    @Override
+    public boolean exists(String path, String method) {
+        List<Match<Registration>> matches = new ArrayList<>();
+        lock.readLock().lock();
+        try {
+            tree.match(path, matches);
+        } finally {
+            lock.readLock().unlock();
+        }
+        for (int i = 0, size = matches.size(); i < size; i++) {
+            if (matches.get(i).getValue().mapping.matchMethod(method)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     private static final class Registration {
         RequestMapping mapping;
         HandlerMeta meta;
diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMapping.java
 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMapping.java
index 5d00ad8eac..3dd19f4f2b 100644
--- 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMapping.java
+++ 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMapping.java
@@ -106,6 +106,10 @@ public final class RequestMapping implements 
Condition<RequestMapping, HttpReque
         return doMatch(request, new PathCondition(path));
     }
 
+    public boolean matchMethod(String method) {
+        return methodsCondition == null || 
methodsCondition.getMethods().contains(method);
+    }
+
     @Override
     public RequestMapping match(HttpRequest request) {
         return doMatch(request, null);
diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMappingRegistry.java
 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMappingRegistry.java
index b7dfb55994..444854c5e7 100644
--- 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMappingRegistry.java
+++ 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMappingRegistry.java
@@ -31,5 +31,7 @@ public interface RequestMappingRegistry {
 
     HandlerMeta lookup(HttpRequest request);
 
+    boolean exists(String path, String method);
+
     void destroy();
 }
diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/MethodsCondition.java
 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/MethodsCondition.java
index fa01f67194..96b8eec3c4 100644
--- 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/MethodsCondition.java
+++ 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/MethodsCondition.java
@@ -38,6 +38,10 @@ public final class MethodsCondition implements 
Condition<MethodsCondition, HttpR
         this.methods = methods;
     }
 
+    public Set<String> getMethods() {
+        return methods;
+    }
+
     @Override
     public MethodsCondition combine(MethodsCondition other) {
         Set<String> set = new HashSet<>(methods);
diff --git a/dubbo-spring-boot/dubbo-spring-boot-starter/pom.xml 
b/dubbo-spring-boot/dubbo-spring-boot-3-autoconfigure/pom.xml
similarity index 61%
copy from dubbo-spring-boot/dubbo-spring-boot-starter/pom.xml
copy to dubbo-spring-boot/dubbo-spring-boot-3-autoconfigure/pom.xml
index 7abb4ce74f..bfaf876099 100644
--- a/dubbo-spring-boot/dubbo-spring-boot-starter/pom.xml
+++ b/dubbo-spring-boot/dubbo-spring-boot-3-autoconfigure/pom.xml
@@ -19,28 +19,51 @@
   <modelVersion>4.0.0</modelVersion>
   <parent>
     <groupId>org.apache.dubbo</groupId>
-    <artifactId>dubbo-spring-boot</artifactId>
+    <artifactId>dubbo-parent</artifactId>
     <version>${revision}</version>
-    <relativePath>../pom.xml</relativePath>
+    <relativePath>../../pom.xml</relativePath>
   </parent>
 
-  <artifactId>dubbo-spring-boot-starter</artifactId>
+  <artifactId>dubbo-spring-boot-3-autoconfigure</artifactId>
   <packaging>jar</packaging>
-  <description>Apache Dubbo Spring Boot Starter</description>
+  <description>Apache Dubbo Spring Boot 3 Auto-Configure</description>
+
+  <properties>
+    <spring-boot.version>3.2.1</spring-boot.version>
+  </properties>
+
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-dependencies</artifactId>
+        <version>${spring-boot.version}</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
 
   <dependencies>
     <!-- Spring Boot dependencies -->
     <dependency>
       <groupId>org.springframework.boot</groupId>
-      <artifactId>spring-boot-starter</artifactId>
+      <artifactId>spring-boot-autoconfigure</artifactId>
       <optional>true</optional>
     </dependency>
 
+    <!-- Dubbo -->
     <dependency>
       <groupId>org.apache.dubbo</groupId>
-      <artifactId>dubbo-spring-boot-autoconfigure</artifactId>
+      <artifactId>dubbo</artifactId>
       <version>${project.version}</version>
+      <optional>true</optional>
     </dependency>
 
+    <dependency>
+      <groupId>jakarta.servlet</groupId>
+      <artifactId>jakarta.servlet-api</artifactId>
+      <optional>true</optional>
+    </dependency>
   </dependencies>
 </project>
diff --git 
a/dubbo-spring-boot/dubbo-spring-boot-3-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboTriple3AutoConfiguration.java
 
b/dubbo-spring-boot/dubbo-spring-boot-3-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboTriple3AutoConfiguration.java
new file mode 100644
index 0000000000..80fd90ef39
--- /dev/null
+++ 
b/dubbo-spring-boot/dubbo-spring-boot-3-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboTriple3AutoConfiguration.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.dubbo.spring.boot.autoconfigure;
+
+import org.apache.dubbo.rpc.protocol.tri.ServletExchanger;
+import org.apache.dubbo.rpc.protocol.tri.servlet.jakarta.TripleFilter;
+
+import jakarta.servlet.Filter;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import 
org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
+import 
org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Conditional;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration(proxyBeanMethods = false)
+@Conditional(SpringBoot3Condition.class)
+public class DubboTriple3AutoConfiguration {
+
+    public static final String PREFIX = "dubbo.protocol.triple";
+
+    @Configuration(proxyBeanMethods = false)
+    @ConditionalOnClass(Filter.class)
+    @ConditionalOnWebApplication(type = Type.SERVLET)
+    @ConditionalOnProperty(prefix = PREFIX, name = "enable-servlet")
+    public static class TripleServletConfiguration {
+
+        @Bean
+        public FilterRegistrationBean<TripleFilter> tripleProtocolFilter(
+                @Value("${" + PREFIX + ".servlet-filter-url-patterns:/*}") 
String[] urlPatterns,
+                @Value("${" + PREFIX + ".servlet-filter-order:-1000000}") int 
order,
+                @Value("${server.port:8080}") int serverPort) {
+            ServletExchanger.bindServerPort(serverPort);
+            FilterRegistrationBean<TripleFilter> registrationBean = new 
FilterRegistrationBean<>();
+            registrationBean.setFilter(new TripleFilter());
+            registrationBean.addUrlPatterns(urlPatterns);
+            registrationBean.setOrder(order);
+            return registrationBean;
+        }
+    }
+}
diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMappingRegistry.java
 
b/dubbo-spring-boot/dubbo-spring-boot-3-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/SpringBoot3Condition.java
similarity index 58%
copy from 
dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMappingRegistry.java
copy to 
dubbo-spring-boot/dubbo-spring-boot-3-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/SpringBoot3Condition.java
index b7dfb55994..489446f1d7 100644
--- 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMappingRegistry.java
+++ 
b/dubbo-spring-boot/dubbo-spring-boot-3-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/SpringBoot3Condition.java
@@ -14,22 +14,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.rpc.protocol.tri.rest.mapping;
+package org.apache.dubbo.spring.boot.autoconfigure;
 
-import org.apache.dubbo.remoting.http12.HttpRequest;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.HandlerMeta;
+import org.springframework.boot.SpringBootVersion;
+import org.springframework.context.annotation.Condition;
+import org.springframework.context.annotation.ConditionContext;
+import org.springframework.core.type.AnnotatedTypeMetadata;
 
-/**
- * RequestMappingRegistry used for registering and unregistering rest request 
mappings.
- */
-public interface RequestMappingRegistry {
-
-    void register(Invoker<?> invoker);
-
-    void unregister(Invoker<?> invoker);
+public class SpringBoot3Condition implements Condition {
 
-    HandlerMeta lookup(HttpRequest request);
+    public static boolean IS_SPRING_BOOT_3 = 
SpringBootVersion.getVersion().charAt(0) >= '3';
 
-    void destroy();
+    @Override
+    public boolean matches(ConditionContext context, AnnotatedTypeMetadata 
metadata) {
+        return IS_SPRING_BOOT_3;
+    }
 }
diff --git 
a/dubbo-spring-boot/dubbo-spring-boot-3-autoconfigure/src/main/resources/META-INF/spring.factories
 
b/dubbo-spring-boot/dubbo-spring-boot-3-autoconfigure/src/main/resources/META-INF/spring.factories
new file mode 100644
index 0000000000..3ee254abc6
--- /dev/null
+++ 
b/dubbo-spring-boot/dubbo-spring-boot-3-autoconfigure/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,2 @@
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+org.apache.dubbo.spring.boot.autoconfigure.DubboTriple3AutoConfiguration
diff --git 
a/dubbo-spring-boot/dubbo-spring-boot-3-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
 
b/dubbo-spring-boot/dubbo-spring-boot-3-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 0000000000..03e1ef54ec
--- /dev/null
+++ 
b/dubbo-spring-boot/dubbo-spring-boot-3-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+org.apache.dubbo.spring.boot.autoconfigure.DubboTriple3AutoConfiguration
diff --git a/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/pom.xml 
b/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/pom.xml
index ddc4a74127..af3d04948d 100644
--- a/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/pom.xml
+++ b/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/pom.xml
@@ -71,6 +71,12 @@
       <optional>true</optional>
     </dependency>
 
+    <dependency>
+      <groupId>javax.servlet</groupId>
+      <artifactId>javax.servlet-api</artifactId>
+      <scope>provided</scope>
+    </dependency>
+
     <!-- Test Dependencies -->
     <dependency>
       <groupId>org.springframework.boot</groupId>
diff --git 
a/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboTripleAutoConfiguration.java
 
b/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboTripleAutoConfiguration.java
new file mode 100644
index 0000000000..114ab7cadf
--- /dev/null
+++ 
b/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboTripleAutoConfiguration.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.dubbo.spring.boot.autoconfigure;
+
+import org.apache.dubbo.rpc.protocol.tri.ServletExchanger;
+import org.apache.dubbo.rpc.protocol.tri.servlet.TripleFilter;
+
+import javax.servlet.Filter;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import 
org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
+import 
org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Conditional;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration(proxyBeanMethods = false)
+@Conditional(SpringBoot12Condition.class)
+public class DubboTripleAutoConfiguration {
+
+    public static final String PREFIX = "dubbo.protocol.triple";
+
+    @Configuration(proxyBeanMethods = false)
+    @ConditionalOnClass(Filter.class)
+    @ConditionalOnWebApplication(type = Type.SERVLET)
+    @ConditionalOnProperty(prefix = PREFIX, name = "enable-servlet")
+    public static class TripleServletConfiguration {
+
+        @Bean
+        public FilterRegistrationBean<TripleFilter> tripleProtocolFilter(
+                @Value("${" + PREFIX + ".servlet-filter-url-patterns:/*}") 
String[] urlPatterns,
+                @Value("${" + PREFIX + ".servlet-filter-order:-1000000}") int 
order,
+                @Value("${server.port:8080}") int serverPort) {
+            ServletExchanger.bindServerPort(serverPort);
+            FilterRegistrationBean<TripleFilter> registrationBean = new 
FilterRegistrationBean<>();
+            registrationBean.setFilter(new TripleFilter());
+            registrationBean.addUrlPatterns(urlPatterns);
+            registrationBean.setOrder(order);
+            return registrationBean;
+        }
+    }
+}
diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMappingRegistry.java
 
b/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/SpringBoot12Condition.java
similarity index 58%
copy from 
dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMappingRegistry.java
copy to 
dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/SpringBoot12Condition.java
index b7dfb55994..9bf7fdf760 100644
--- 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMappingRegistry.java
+++ 
b/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/SpringBoot12Condition.java
@@ -14,22 +14,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.rpc.protocol.tri.rest.mapping;
+package org.apache.dubbo.spring.boot.autoconfigure;
 
-import org.apache.dubbo.remoting.http12.HttpRequest;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.HandlerMeta;
+import org.springframework.boot.SpringBootVersion;
+import org.springframework.context.annotation.Condition;
+import org.springframework.context.annotation.ConditionContext;
+import org.springframework.core.type.AnnotatedTypeMetadata;
 
-/**
- * RequestMappingRegistry used for registering and unregistering rest request 
mappings.
- */
-public interface RequestMappingRegistry {
-
-    void register(Invoker<?> invoker);
-
-    void unregister(Invoker<?> invoker);
+public class SpringBoot12Condition implements Condition {
 
-    HandlerMeta lookup(HttpRequest request);
+    public static boolean IS_SPRING_BOOT_12 = 
SpringBootVersion.getVersion().charAt(0) < '3';
 
-    void destroy();
+    @Override
+    public boolean matches(ConditionContext context, AnnotatedTypeMetadata 
metadata) {
+        return IS_SPRING_BOOT_12;
+    }
 }
diff --git 
a/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories
 
b/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories
index c88a29b244..38eb67828f 100644
--- 
a/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories
+++ 
b/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories
@@ -1,2 +1,3 @@
 org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
-org.apache.dubbo.spring.boot.autoconfigure.DubboRelaxedBinding2AutoConfiguration
\ No newline at end of file
+org.apache.dubbo.spring.boot.autoconfigure.DubboRelaxedBinding2AutoConfiguration,\
+org.apache.dubbo.spring.boot.autoconfigure.DubboTripleAutoConfiguration
diff --git 
a/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
 
b/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
index be0f66976d..dd87d13a98 100644
--- 
a/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
+++ 
b/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -1 +1,2 @@
 
org.apache.dubbo.spring.boot.autoconfigure.DubboRelaxedBinding2AutoConfiguration
+org.apache.dubbo.spring.boot.autoconfigure.DubboTripleAutoConfiguration
diff --git a/dubbo-spring-boot/dubbo-spring-boot-starter/pom.xml 
b/dubbo-spring-boot/dubbo-spring-boot-starter/pom.xml
index 7abb4ce74f..b21cb786f8 100644
--- a/dubbo-spring-boot/dubbo-spring-boot-starter/pom.xml
+++ b/dubbo-spring-boot/dubbo-spring-boot-starter/pom.xml
@@ -41,6 +41,11 @@
       <artifactId>dubbo-spring-boot-autoconfigure</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.apache.dubbo</groupId>
+      <artifactId>dubbo-spring-boot-3-autoconfigure</artifactId>
+      <version>${project.version}</version>
+    </dependency>
 
   </dependencies>
 </project>
diff --git a/dubbo-spring-boot/pom.xml b/dubbo-spring-boot/pom.xml
index d198c79489..f6ce540332 100644
--- a/dubbo-spring-boot/pom.xml
+++ b/dubbo-spring-boot/pom.xml
@@ -32,6 +32,7 @@
   <modules>
     <module>dubbo-spring-boot-actuator</module>
     <module>dubbo-spring-boot-autoconfigure</module>
+    <module>dubbo-spring-boot-3-autoconfigure</module>
     <module>dubbo-spring-boot-compatible</module>
     <module>dubbo-spring-boot-starter</module>
     <module>dubbo-spring-boot-starters</module>
diff --git a/dubbo-test/dubbo-dependencies-all/pom.xml 
b/dubbo-test/dubbo-dependencies-all/pom.xml
index 790e3e2c18..529a5233bf 100644
--- a/dubbo-test/dubbo-dependencies-all/pom.xml
+++ b/dubbo-test/dubbo-dependencies-all/pom.xml
@@ -261,6 +261,11 @@
       <artifactId>dubbo-rest-spring</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.apache.dubbo</groupId>
+      <artifactId>dubbo-triple-servlet</artifactId>
+      <version>${project.version}</version>
+    </dependency>
 
     <!-- registry -->
     <dependency>
@@ -377,6 +382,11 @@
       <artifactId>dubbo-spring-boot-autoconfigure</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.apache.dubbo</groupId>
+      <artifactId>dubbo-spring-boot-3-autoconfigure</artifactId>
+      <version>${project.version}</version>
+    </dependency>
     <dependency>
       <groupId>org.apache.dubbo</groupId>
       <artifactId>dubbo-spring-boot-actuator-compatible</artifactId>
diff --git a/pom.xml b/pom.xml
index a216e2afd1..8bfadb1f1c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -911,6 +911,12 @@
         </plugins>
       </build>
     </profile>
+    <profile>
+      <id>skip-spotless</id>
+      <properties>
+        <spotless.skip>true</spotless.skip>
+      </properties>
+    </profile>
   </profiles>
 
 </project>

Reply via email to