Add sentinel-transport-spring-mvc module (#1957)
This commit is contained in:
parent
77caaffd31
commit
8025ef5934
5
pom.xml
5
pom.xml
|
|
@ -144,6 +144,11 @@
|
||||||
<artifactId>sentinel-transport-netty-http</artifactId>
|
<artifactId>sentinel-transport-netty-http</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.csp</groupId>
|
||||||
|
<artifactId>sentinel-transport-spring-mvc</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba.csp</groupId>
|
<groupId>com.alibaba.csp</groupId>
|
||||||
<artifactId>sentinel-transport-common</artifactId>
|
<artifactId>sentinel-transport-common</artifactId>
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@
|
||||||
<module>sentinel-demo-quarkus</module>
|
<module>sentinel-demo-quarkus</module>
|
||||||
<module>sentinel-demo-annotation-cdi-interceptor</module>
|
<module>sentinel-demo-annotation-cdi-interceptor</module>
|
||||||
<module>sentinel-demo-motan</module>
|
<module>sentinel-demo-motan</module>
|
||||||
|
<module>sentinel-demo-transport-spring-mvc</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
server.port=10000
|
||||||
|
|
@ -16,5 +16,6 @@
|
||||||
|
|
||||||
<module>sentinel-transport-simple-http</module>
|
<module>sentinel-transport-simple-http</module>
|
||||||
<module>sentinel-transport-netty-http</module>
|
<module>sentinel-transport-netty-http</module>
|
||||||
|
<module>sentinel-transport-spring-mvc</module>
|
||||||
</modules>
|
</modules>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,117 @@
|
||||||
|
/*
|
||||||
|
* 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.log.RecordLog;
|
||||||
|
import com.alibaba.csp.sentinel.transport.config.TransportConfig;
|
||||||
|
import com.alibaba.csp.sentinel.transport.log.CommandCenterLog;
|
||||||
|
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||||
|
import org.springframework.beans.BeanWrapper;
|
||||||
|
import org.springframework.beans.BeanWrapperImpl;
|
||||||
|
import org.springframework.context.ApplicationEvent;
|
||||||
|
import org.springframework.context.ApplicationListener;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
|
import org.springframework.web.servlet.HandlerExecutionChain;
|
||||||
|
import org.springframework.web.servlet.handler.AbstractHandlerMapping;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shenbaoyong
|
||||||
|
*/
|
||||||
|
public class SentinelApiHandlerMapping extends AbstractHandlerMapping implements ApplicationListener {
|
||||||
|
|
||||||
|
private static final String SPRING_BOOT_WEB_SERVER_INITIALIZED_EVENT_CLASS = "org.springframework.boot.web.context.WebServerInitializedEvent";
|
||||||
|
private static Class webServerInitializedEventClass;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
webServerInitializedEventClass = ClassUtils.forName(SPRING_BOOT_WEB_SERVER_INITIALIZED_EVENT_CLASS, null);
|
||||||
|
RecordLog.info("[SentinelApiHandlerMapping] class {} is present, this is a spring-boot app, we can auto detect port", SPRING_BOOT_WEB_SERVER_INITIALIZED_EVENT_CLASS);
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
RecordLog.info("[SentinelApiHandlerMapping] class {} is not present, this is not a spring-boot app, we can not auto detect port", SPRING_BOOT_WEB_SERVER_INITIALIZED_EVENT_CLASS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final static Map<String, CommandHandler> handlerMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
private boolean ignoreInterceptor = true;
|
||||||
|
|
||||||
|
public SentinelApiHandlerMapping() {
|
||||||
|
setOrder(Ordered.LOWEST_PRECEDENCE - 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
|
||||||
|
String commandName = request.getRequestURI();
|
||||||
|
if (commandName.startsWith("/")) {
|
||||||
|
commandName = commandName.substring(1);
|
||||||
|
}
|
||||||
|
CommandHandler commandHandler = handlerMap.get(commandName);
|
||||||
|
return commandHandler != null ? new SentinelApiHandler(commandHandler) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
|
||||||
|
return ignoreInterceptor ? new HandlerExecutionChain(handler) : super.getHandlerExecutionChain(handler, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIgnoreInterceptor(boolean ignoreInterceptor) {
|
||||||
|
this.ignoreInterceptor = ignoreInterceptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void registerCommand(String commandName, CommandHandler handler) {
|
||||||
|
if (StringUtil.isEmpty(commandName) || handler == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handlerMap.containsKey(commandName)) {
|
||||||
|
CommandCenterLog.warn("[SentinelApiHandlerMapping] Register failed (duplicate command): " + commandName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
handlerMap.put(commandName, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void registerCommands(Map<String, CommandHandler> handlerMap) {
|
||||||
|
if (handlerMap != null) {
|
||||||
|
for (Map.Entry<String, CommandHandler> e : handlerMap.entrySet()) {
|
||||||
|
registerCommand(e.getKey(), e.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onApplicationEvent(ApplicationEvent applicationEvent) {
|
||||||
|
if (webServerInitializedEventClass != null && webServerInitializedEventClass.isAssignableFrom(applicationEvent.getClass())) {
|
||||||
|
Integer port = null;
|
||||||
|
try {
|
||||||
|
BeanWrapper beanWrapper = new BeanWrapperImpl(applicationEvent);
|
||||||
|
port = (Integer) beanWrapper.getPropertyValue("webServer.port");
|
||||||
|
} catch (Exception e) {
|
||||||
|
RecordLog.warn("[SentinelApiHandlerMapping] resolve port from event " + applicationEvent + " fail", e);
|
||||||
|
}
|
||||||
|
if (port != null && TransportConfig.getPort() == null) {
|
||||||
|
RecordLog.info("[SentinelApiHandlerMapping] resolve port {} from event {}", port, applicationEvent);
|
||||||
|
TransportConfig.setRuntimePort(port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* 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.CommandHandlerProvider;
|
||||||
|
import com.alibaba.csp.sentinel.spi.Spi;
|
||||||
|
import com.alibaba.csp.sentinel.transport.CommandCenter;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shenbaoyong
|
||||||
|
*/
|
||||||
|
@Spi(order = Spi.ORDER_LOWEST - 100)
|
||||||
|
public class SpringMvcHttpCommandCenter implements CommandCenter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() throws Exception {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop() throws Exception {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeStart() throws Exception {
|
||||||
|
// Register handlers
|
||||||
|
Map<String, CommandHandler> handlers = CommandHandlerProvider.getInstance().namedHandlers();
|
||||||
|
SentinelApiHandlerMapping.registerCommands(handlers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* 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.http;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Jason Joo
|
||||||
|
*/
|
||||||
|
public enum StatusCode {
|
||||||
|
/**
|
||||||
|
* 200 OK.
|
||||||
|
*/
|
||||||
|
OK(200, "OK"),
|
||||||
|
BAD_REQUEST(400, "Bad Request"),
|
||||||
|
REQUEST_TIMEOUT(408, "Request Timeout"),
|
||||||
|
LENGTH_REQUIRED(411, "Length Required"),
|
||||||
|
UNSUPPORTED_MEDIA_TYPE(415, "Unsupported Media Type"),
|
||||||
|
INTERNAL_SERVER_ERROR(500, "Internal Server Error");
|
||||||
|
|
||||||
|
private int code;
|
||||||
|
private String desc;
|
||||||
|
private String representation;
|
||||||
|
|
||||||
|
StatusCode(int code, String desc) {
|
||||||
|
this.code = code;
|
||||||
|
this.desc = desc;
|
||||||
|
this.representation = code + " " + desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDesc() {
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return representation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,123 @@
|
||||||
|
/*
|
||||||
|
* 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.heartbeat;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.Constants;
|
||||||
|
import com.alibaba.csp.sentinel.config.SentinelConfig;
|
||||||
|
import com.alibaba.csp.sentinel.log.RecordLog;
|
||||||
|
import com.alibaba.csp.sentinel.spi.Spi;
|
||||||
|
import com.alibaba.csp.sentinel.transport.HeartbeatSender;
|
||||||
|
import com.alibaba.csp.sentinel.transport.config.TransportConfig;
|
||||||
|
import com.alibaba.csp.sentinel.transport.endpoint.Endpoint;
|
||||||
|
import com.alibaba.csp.sentinel.transport.endpoint.Protocol;
|
||||||
|
import com.alibaba.csp.sentinel.transport.heartbeat.client.HttpClientsFactory;
|
||||||
|
import com.alibaba.csp.sentinel.util.AppNameUtil;
|
||||||
|
import com.alibaba.csp.sentinel.util.HostNameUtil;
|
||||||
|
import com.alibaba.csp.sentinel.util.PidUtil;
|
||||||
|
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||||
|
import org.apache.http.client.config.RequestConfig;
|
||||||
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
import org.apache.http.client.utils.URIBuilder;
|
||||||
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Eric Zhao
|
||||||
|
* @author Carpenter Lee
|
||||||
|
* @author Leo Li
|
||||||
|
*/
|
||||||
|
@Spi(order = Spi.ORDER_LOWEST - 100)
|
||||||
|
public class SpringMvcHttpHeartbeatSender implements HeartbeatSender {
|
||||||
|
|
||||||
|
private final CloseableHttpClient client;
|
||||||
|
|
||||||
|
private static final int OK_STATUS = 200;
|
||||||
|
|
||||||
|
private final int timeoutMs = 3000;
|
||||||
|
private final RequestConfig requestConfig = RequestConfig.custom()
|
||||||
|
.setConnectionRequestTimeout(timeoutMs)
|
||||||
|
.setConnectTimeout(timeoutMs)
|
||||||
|
.setSocketTimeout(timeoutMs)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
private final Protocol consoleProtocol;
|
||||||
|
private final String consoleHost;
|
||||||
|
private final int consolePort;
|
||||||
|
|
||||||
|
public SpringMvcHttpHeartbeatSender() {
|
||||||
|
List<Endpoint> dashboardList = TransportConfig.getConsoleServerList();
|
||||||
|
if (dashboardList == null || dashboardList.isEmpty()) {
|
||||||
|
RecordLog.info("[HttpHeartbeatSender] No dashboard server available");
|
||||||
|
consoleProtocol = Protocol.HTTP;
|
||||||
|
consoleHost = null;
|
||||||
|
consolePort = -1;
|
||||||
|
} else {
|
||||||
|
consoleProtocol = dashboardList.get(0).getProtocol();
|
||||||
|
consoleHost = dashboardList.get(0).getHost();
|
||||||
|
consolePort = dashboardList.get(0).getPort();
|
||||||
|
RecordLog.info("[HttpHeartbeatSender] Dashboard address parsed: <{}:{}>", consoleHost, consolePort);
|
||||||
|
}
|
||||||
|
this.client = HttpClientsFactory.getHttpClientsByProtocol(consoleProtocol);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean sendHeartbeat() throws Exception {
|
||||||
|
if (StringUtil.isEmpty(consoleHost)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
URIBuilder uriBuilder = new URIBuilder();
|
||||||
|
uriBuilder.setScheme(consoleProtocol.getProtocol()).setHost(consoleHost).setPort(consolePort)
|
||||||
|
.setPath(TransportConfig.getHeartbeatApiPath())
|
||||||
|
.setParameter("app", AppNameUtil.getAppName())
|
||||||
|
.setParameter("app_type", String.valueOf(SentinelConfig.getAppType()))
|
||||||
|
.setParameter("v", Constants.SENTINEL_VERSION)
|
||||||
|
.setParameter("version", String.valueOf(System.currentTimeMillis()))
|
||||||
|
.setParameter("hostname", HostNameUtil.getHostName())
|
||||||
|
.setParameter("ip", TransportConfig.getHeartbeatClientIp())
|
||||||
|
.setParameter("port", TransportConfig.getPort())
|
||||||
|
.setParameter("pid", String.valueOf(PidUtil.getPid()));
|
||||||
|
|
||||||
|
HttpGet request = new HttpGet(uriBuilder.build());
|
||||||
|
request.setConfig(requestConfig);
|
||||||
|
// Send heartbeat request.
|
||||||
|
CloseableHttpResponse response = client.execute(request);
|
||||||
|
response.close();
|
||||||
|
int statusCode = response.getStatusLine().getStatusCode();
|
||||||
|
if (statusCode == OK_STATUS) {
|
||||||
|
return true;
|
||||||
|
} else if (clientErrorCode(statusCode) || serverErrorCode(statusCode)) {
|
||||||
|
RecordLog.warn("[HttpHeartbeatSender] Failed to send heartbeat to "
|
||||||
|
+ consoleHost + ":" + consolePort + ", http status code: " + statusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long intervalMs() {
|
||||||
|
return 5000;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean clientErrorCode(int code) {
|
||||||
|
return code > 399 && code < 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean serverErrorCode(int code) {
|
||||||
|
return code > 499 && code < 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* 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.heartbeat.client;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.transport.endpoint.Protocol;
|
||||||
|
import com.alibaba.csp.sentinel.transport.ssl.SslFactory;
|
||||||
|
import org.apache.http.conn.ssl.NoopHostnameVerifier;
|
||||||
|
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
||||||
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
import org.apache.http.impl.client.HttpClients;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Leo Li
|
||||||
|
*/
|
||||||
|
public class HttpClientsFactory {
|
||||||
|
|
||||||
|
private static class SslConnectionSocketFactoryInstance {
|
||||||
|
private static final SSLConnectionSocketFactory SSL_CONNECTION_SOCKET_FACTORY = new SSLConnectionSocketFactory(SslFactory.getSslConnectionSocketFactory(), NoopHostnameVerifier.INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CloseableHttpClient getHttpClientsByProtocol(Protocol protocol) {
|
||||||
|
return protocol == Protocol.HTTP ? HttpClients.createDefault() : HttpClients.custom().
|
||||||
|
setSSLSocketFactory(SslConnectionSocketFactoryInstance.SSL_CONNECTION_SOCKET_FACTORY).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
com.alibaba.csp.sentinel.transport.command.SpringMvcHttpCommandCenter
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
com.alibaba.csp.sentinel.transport.heartbeat.SpringMvcHttpHeartbeatSender
|
||||||
Loading…
Reference in New Issue