浏览代码

Add sentinel-transport-spring-mvc module (#1957)

master
shenbaoyong GitHub 3 年前
父节点
当前提交
8025ef5934
找不到此签名对应的密钥 GPG 密钥 ID: 4AEE18F83AFDEB23
共有 16 个文件被更改,包括 726 次插入0 次删除
  1. +5
    -0
      pom.xml
  2. +1
    -0
      sentinel-demo/pom.xml
  3. +34
    -0
      sentinel-demo/sentinel-demo-transport-spring-mvc/pom.xml
  4. +96
    -0
      sentinel-demo/sentinel-demo-transport-spring-mvc/src/main/java/com/alibaba/csp/sentinel/demo/transport/springmvc/TransportSpringMvcDemoApplication.java
  5. +1
    -0
      sentinel-demo/sentinel-demo-transport-spring-mvc/src/main/resources/application.properties
  6. +1
    -0
      sentinel-transport/pom.xml
  7. +50
    -0
      sentinel-transport/sentinel-transport-spring-mvc/pom.xml
  8. +100
    -0
      sentinel-transport/sentinel-transport-spring-mvc/src/main/java/com/alibaba/csp/sentinel/transport/command/SentinelApiHandler.java
  9. +57
    -0
      sentinel-transport/sentinel-transport-spring-mvc/src/main/java/com/alibaba/csp/sentinel/transport/command/SentinelApiHandlerAdapter.java
  10. +117
    -0
      sentinel-transport/sentinel-transport-spring-mvc/src/main/java/com/alibaba/csp/sentinel/transport/command/SentinelApiHandlerMapping.java
  11. +47
    -0
      sentinel-transport/sentinel-transport-spring-mvc/src/main/java/com/alibaba/csp/sentinel/transport/command/SpringMvcHttpCommandCenter.java
  12. +54
    -0
      sentinel-transport/sentinel-transport-spring-mvc/src/main/java/com/alibaba/csp/sentinel/transport/command/http/StatusCode.java
  13. +123
    -0
      sentinel-transport/sentinel-transport-spring-mvc/src/main/java/com/alibaba/csp/sentinel/transport/heartbeat/SpringMvcHttpHeartbeatSender.java
  14. +38
    -0
      sentinel-transport/sentinel-transport-spring-mvc/src/main/java/com/alibaba/csp/sentinel/transport/heartbeat/client/HttpClientsFactory.java
  15. +1
    -0
      sentinel-transport/sentinel-transport-spring-mvc/src/main/resources/META-INF/services/com.alibaba.csp.sentinel.transport.CommandCenter
  16. +1
    -0
      sentinel-transport/sentinel-transport-spring-mvc/src/main/resources/META-INF/services/com.alibaba.csp.sentinel.transport.HeartbeatSender

+ 5
- 0
pom.xml 查看文件

@@ -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>


+ 1
- 0
sentinel-demo/pom.xml 查看文件

@@ -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>


+ 34
- 0
sentinel-demo/sentinel-demo-transport-spring-mvc/pom.xml 查看文件

@@ -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>

+ 96
- 0
sentinel-demo/sentinel-demo-transport-spring-mvc/src/main/java/com/alibaba/csp/sentinel/demo/transport/springmvc/TransportSpringMvcDemoApplication.java 查看文件

@@ -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();
}
}

+ 1
- 0
sentinel-demo/sentinel-demo-transport-spring-mvc/src/main/resources/application.properties 查看文件

@@ -0,0 +1 @@
server.port=10000

+ 1
- 0
sentinel-transport/pom.xml 查看文件

@@ -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
- 0
sentinel-transport/sentinel-transport-spring-mvc/pom.xml 查看文件

@@ -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>

+ 100
- 0
sentinel-transport/sentinel-transport-spring-mvc/src/main/java/com/alibaba/csp/sentinel/transport/command/SentinelApiHandler.java 查看文件

@@ -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);
}
}

}

+ 57
- 0
sentinel-transport/sentinel-transport-spring-mvc/src/main/java/com/alibaba/csp/sentinel/transport/command/SentinelApiHandlerAdapter.java 查看文件

@@ -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;
}
}

+ 117
- 0
sentinel-transport/sentinel-transport-spring-mvc/src/main/java/com/alibaba/csp/sentinel/transport/command/SentinelApiHandlerMapping.java 查看文件

@@ -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);
}
}
}
}

+ 47
- 0
sentinel-transport/sentinel-transport-spring-mvc/src/main/java/com/alibaba/csp/sentinel/transport/command/SpringMvcHttpCommandCenter.java 查看文件

@@ -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);
}
}

+ 54
- 0
sentinel-transport/sentinel-transport-spring-mvc/src/main/java/com/alibaba/csp/sentinel/transport/command/http/StatusCode.java 查看文件

@@ -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;
}
}

+ 123
- 0
sentinel-transport/sentinel-transport-spring-mvc/src/main/java/com/alibaba/csp/sentinel/transport/heartbeat/SpringMvcHttpHeartbeatSender.java 查看文件

@@ -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;
}
}

+ 38
- 0
sentinel-transport/sentinel-transport-spring-mvc/src/main/java/com/alibaba/csp/sentinel/transport/heartbeat/client/HttpClientsFactory.java 查看文件

@@ -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();
}
}

+ 1
- 0
sentinel-transport/sentinel-transport-spring-mvc/src/main/resources/META-INF/services/com.alibaba.csp.sentinel.transport.CommandCenter 查看文件

@@ -0,0 +1 @@
com.alibaba.csp.sentinel.transport.command.SpringMvcHttpCommandCenter

+ 1
- 0
sentinel-transport/sentinel-transport-spring-mvc/src/main/resources/META-INF/services/com.alibaba.csp.sentinel.transport.HeartbeatSender 查看文件

@@ -0,0 +1 @@
com.alibaba.csp.sentinel.transport.heartbeat.SpringMvcHttpHeartbeatSender

正在加载...
取消
保存