Skip to content

Commit

Permalink
Add sentinel-transport-spring-mvc module (#1957)
Browse files Browse the repository at this point in the history
  • Loading branch information
shenbaoyong authored Feb 23, 2021
1 parent 77caaff commit 8025ef5
Show file tree
Hide file tree
Showing 16 changed files with 726 additions and 0 deletions.
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,11 @@
<artifactId>sentinel-transport-netty-http</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-spring-mvc</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-common</artifactId>
Expand Down
1 change: 1 addition & 0 deletions sentinel-demo/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
<module>sentinel-demo-quarkus</module>
<module>sentinel-demo-annotation-cdi-interceptor</module>
<module>sentinel-demo-motan</module>
<module>sentinel-demo-transport-spring-mvc</module>
</modules>

<dependencies>
Expand Down
34 changes: 34 additions & 0 deletions sentinel-demo/sentinel-demo-transport-spring-mvc/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?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">
<parent>
<artifactId>sentinel-demo</artifactId>
<groupId>com.alibaba.csp</groupId>
<version>1.8.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>sentinel-demo-transport-spring-mvc</artifactId>

<properties>
<spring.boot.version>2.1.3.RELEASE</spring.boot.version>
</properties>

<dependencies>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-spring-mvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring.boot.version}</version>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Copyright 1999-2019 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.demo.transport.springmvc;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.init.InitExecutor;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.transport.command.SentinelApiHandlerAdapter;
import com.alibaba.csp.sentinel.transport.command.SentinelApiHandlerMapping;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
* <p>Add the JVM parameter to connect to the dashboard:</p>
* {@code -Dcsp.sentinel.dashboard.server=127.0.0.1:8080 -Dproject.name=sentinel-demo-transport-spring-mvc}
*
* <p>Add the JVM parameter to tell dashboard your application port:</p>
* {@code -Dcsp.sentinel.api.port=10000}
*
* @author shenbaoyong
*/
@SpringBootApplication
@Controller
public class TransportSpringMvcDemoApplication {

public static void main(String[] args) {
triggerSentinelInit();
initFlowRules();
SpringApplication.run(TransportSpringMvcDemoApplication.class);
}

public static void initFlowRules() {
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setResource("demo-hello-api");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setCount(1);
rules.add(rule);
FlowRuleManager.loadRules(rules);
}

@GetMapping("/hello")
@ResponseBody
public String hello() {
Entry entry = null;
try {
entry = SphU.entry("demo-hello-api");
return "ok: " + LocalDateTime.now();
} catch (BlockException e1) {
return "helloBlockHandler: " + LocalDateTime.now();
} finally {
if (entry != null) {
entry.exit();
}
}
}

private static void triggerSentinelInit() {
new Thread(() -> InitExecutor.doInit()).start();
}

@Bean
public SentinelApiHandlerMapping sentinelApiHandlerMapping() {
return new SentinelApiHandlerMapping();
}

@Bean
public SentinelApiHandlerAdapter sentinelApiHandlerAdapter() {
return new SentinelApiHandlerAdapter();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
server.port=10000
1 change: 1 addition & 0 deletions sentinel-transport/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@

<module>sentinel-transport-simple-http</module>
<module>sentinel-transport-netty-http</module>
<module>sentinel-transport-spring-mvc</module>
</modules>
</project>
50 changes: 50 additions & 0 deletions sentinel-transport/sentinel-transport-spring-mvc/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?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">
<parent>
<artifactId>sentinel-transport</artifactId>
<groupId>com.alibaba.csp</groupId>
<version>1.8.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>sentinel-transport-spring-mvc</artifactId>

<properties>
<apache.httpclient.version>4.5.3</apache.httpclient.version>
<servlet.api.version>3.1.0</servlet.api.version>
<spring.version>5.1.8.RELEASE</spring.version>
</properties>

<dependencies>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${servlet.api.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${apache.httpclient.version}</version>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* 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.transport.command;

import com.alibaba.csp.sentinel.command.CommandHandler;
import com.alibaba.csp.sentinel.command.CommandRequest;
import com.alibaba.csp.sentinel.command.CommandResponse;
import com.alibaba.csp.sentinel.config.SentinelConfig;
import com.alibaba.csp.sentinel.transport.command.http.StatusCode;
import com.alibaba.csp.sentinel.transport.log.CommandCenterLog;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.Map;

/**
* @author shenbaoyong
*/
public class SentinelApiHandler {

public static final String SERVER_ERROR_MESSAGE = "Command server error";

private CommandHandler commandHandler;

public SentinelApiHandler(CommandHandler commandHandler) {
this.commandHandler = commandHandler;
}

public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
PrintWriter printWriter = null;
try {
long start = System.currentTimeMillis();
printWriter = httpServletResponse.getWriter();
CommandCenterLog.debug("[SentinelApiHandler] request income: {}", httpServletRequest.getRequestURL());
CommandRequest request = new CommandRequest();
Map<String, String[]> parameterMap = httpServletRequest.getParameterMap();
for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
String[] value = entry.getValue();
if (value != null && value.length >= 1) {
request.addParam(entry.getKey(), value[0]);
}
}
CommandResponse<?> response = commandHandler.handle(request);
handleResponse(response, httpServletResponse, printWriter);

long cost = System.currentTimeMillis() - start;
CommandCenterLog.debug("[SentinelApiHandler] Deal request: {}, time cost: {} ms", httpServletRequest.getRequestURL(), cost);
} catch (Throwable e) {
CommandCenterLog.warn("[SentinelApiHandler] error", e);
try {
if (printWriter != null) {
writeResponse(httpServletResponse, printWriter, StatusCode.INTERNAL_SERVER_ERROR, SERVER_ERROR_MESSAGE);
}
} catch (Exception e1) {
CommandCenterLog.warn("Failed to write error response", e1);
}
}
}

private void writeResponse(HttpServletResponse httpServletResponse, PrintWriter out, StatusCode statusCode, String message) {
httpServletResponse.setStatus(statusCode.getCode());
if (message != null) {
out.print(message);
}
out.flush();
}

private <T> void handleResponse(CommandResponse<T> response, HttpServletResponse httpServletResponse, final PrintWriter printWriter) throws Exception {
if (response.isSuccess()) {
if (response.getResult() == null) {
writeResponse(httpServletResponse, printWriter, StatusCode.OK, null);
return;
}
// Here we directly use `toString` to encode the result to plain text.
byte[] buffer = response.getResult().toString().getBytes(SentinelConfig.charset());
writeResponse(httpServletResponse, printWriter, StatusCode.OK, new String(buffer));
} else {
String msg = SERVER_ERROR_MESSAGE;
if (response.getException() != null) {
msg = response.getException().getMessage();
}
writeResponse(httpServletResponse, printWriter, StatusCode.BAD_REQUEST, msg);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* 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.transport.command;

import org.springframework.core.Ordered;
import org.springframework.web.servlet.HandlerAdapter;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* @author shenbaoyong
*/
public class SentinelApiHandlerAdapter implements HandlerAdapter, Ordered {

private int order = Ordered.LOWEST_PRECEDENCE;

public void setOrder(int order) {
this.order = order;
}

@Override
public int getOrder() {
return order;
}

@Override
public boolean supports(Object handler) {
return handler instanceof SentinelApiHandler;
}

@Override
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
SentinelApiHandler sentinelApiHandler = (SentinelApiHandler) handler;
sentinelApiHandler.handle(request, response);
return null;
}

@Override
public long getLastModified(HttpServletRequest request, Object handler) {
return -1;
}
}
Loading

0 comments on commit 8025ef5

Please sign in to comment.