Skip to content

Commit

Permalink
*router piugin support springboot3
Browse files Browse the repository at this point in the history
Signed-off-by: provenceee <[email protected]>
  • Loading branch information
provenceee committed Nov 20, 2024
1 parent 8812773 commit bc976bf
Show file tree
Hide file tree
Showing 24 changed files with 530 additions and 545 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2022 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (C) 2022-2024 Huawei Technologies Co., Ltd. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -18,17 +18,23 @@

import io.sermant.core.plugin.agent.entity.ExecuteContext;
import io.sermant.core.utils.LogUtils;
import io.sermant.core.utils.ReflectUtils;
import io.sermant.flowcontrol.common.config.ConfigConst;
import io.sermant.flowcontrol.common.entity.FlowControlResult;
import io.sermant.flowcontrol.common.entity.HttpRequestEntity;
import io.sermant.flowcontrol.common.entity.RequestEntity.RequestType;
import io.sermant.flowcontrol.service.InterceptorSupporter;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
Expand All @@ -42,6 +48,28 @@
public class DispatcherServletInterceptor extends InterceptorSupporter {
private final String className = DispatcherServletInterceptor.class.getName();

private Function<Object, String> getRequestUri;

private Function<Object, String> getPathInfo;

private Function<Object, String> getMethod;

private Function<Object, Enumeration<String>> getHeaderNames;

private BiFunction<Object, String, String> getHeader;

private Function<Object, PrintWriter> getWriter;

private BiConsumer<Object, Integer> setStatus;

/**
* constructor
*/
public DispatcherServletInterceptor() {
super();
initFunction();
}

/**
* http request data conversion adapts to plugin -> service data transfer Note that this method is not
* extractable,Because host dependencies can only be loaded by this interceptor, pulling out results in classes not
Expand All @@ -50,18 +78,18 @@ public class DispatcherServletInterceptor extends InterceptorSupporter {
* @param request request
* @return HttpRequestEntity
*/
private Optional<HttpRequestEntity> convertToHttpEntity(HttpServletRequest request) {
private Optional<HttpRequestEntity> convertToHttpEntity(Object request) {
if (request == null) {
return Optional.empty();
}
String uri = request.getRequestURI();
String uri = getRequestUri.apply(request);
return Optional.of(new HttpRequestEntity.Builder()
.setRequestType(RequestType.SERVER)
.setPathInfo(request.getPathInfo())
.setPathInfo(getPathInfo.apply(request))
.setServletPath(uri)
.setHeaders(getHeaders(request))
.setMethod(request.getMethod())
.setServiceName(request.getHeader(ConfigConst.FLOW_REMOTE_SERVICE_NAME_HEADER_KEY))
.setMethod(getMethod.apply(request))
.setServiceName(getHeader.apply(request, ConfigConst.FLOW_REMOTE_SERVICE_NAME_HEADER_KEY))
.build());
}

Expand All @@ -71,12 +99,12 @@ private Optional<HttpRequestEntity> convertToHttpEntity(HttpServletRequest reque
* @param request request information
* @return headers
*/
private Map<String, String> getHeaders(HttpServletRequest request) {
final Enumeration<String> headerNames = request.getHeaderNames();
private Map<String, String> getHeaders(Object request) {
final Enumeration<String> headerNames = getHeaderNames.apply(request);
final Map<String, String> headers = new HashMap<>();
while (headerNames.hasMoreElements()) {
final String headerName = headerNames.nextElement();
headers.put(headerName, request.getHeader(headerName));
headers.put(headerName, getHeader.apply(request, headerName));
}
return Collections.unmodifiableMap(headers);
}
Expand All @@ -85,19 +113,19 @@ private Map<String, String> getHeaders(HttpServletRequest request) {
protected final ExecuteContext doBefore(ExecuteContext context) throws Exception {
LogUtils.printHttpRequestBeforePoint(context);
final Object[] allArguments = context.getArguments();
final HttpServletRequest argument = (HttpServletRequest) allArguments[0];
final Object request = allArguments[0];
final FlowControlResult result = new FlowControlResult();
final Optional<HttpRequestEntity> httpRequestEntity = convertToHttpEntity(argument);
final Optional<HttpRequestEntity> httpRequestEntity = convertToHttpEntity(request);
if (!httpRequestEntity.isPresent()) {
return context;
}
chooseHttpService().onBefore(className, httpRequestEntity.get(), result);
if (result.isSkip()) {
context.skip(null);
final HttpServletResponse response = (HttpServletResponse) allArguments[1];
final Object response = allArguments[1];
if (response != null) {
response.setStatus(result.getResponse().getCode());
response.getWriter().print(result.buildResponseMsg());
setStatus.accept(response, result.getResponse().getCode());
getWriter.apply(response).print(result.buildResponseMsg());
}
}
return context;
Expand All @@ -116,4 +144,75 @@ protected final ExecuteContext doThrow(ExecuteContext context) {
LogUtils.printHttpRequestOnThrowPoint(context);
return context;
}

private String getRequestUri(Object httpServletRequest) {
return getString(httpServletRequest, "getRequestURI");
}

private String getPathInfo(Object httpServletRequest) {
return getString(httpServletRequest, "getPathInfo");
}

private String getMethod(Object httpServletRequest) {
return getString(httpServletRequest, "getMethod");
}

private Enumeration<String> getHeaderNames(Object httpServletRequest) {
return (Enumeration<String>) ReflectUtils.invokeMethodWithNoneParameter(httpServletRequest, "getHeaderNames")
.orElse(null);
}

private String getHeader(Object httpServletRequest, String key) {
return (String) ReflectUtils.invokeMethod(httpServletRequest, "getHeader", new Class[]{String.class},
new Object[]{key}).orElse(null);
}

private PrintWriter getWriter(Object httpServletRequest) {
return (PrintWriter) ReflectUtils.invokeMethodWithNoneParameter(httpServletRequest, "getWriter")
.orElse(null);
}

private void setStatus(Object httpServletResponse, int code) {
ReflectUtils.invokeMethod(httpServletResponse, "setStatus", new Class[]{int.class}, new Object[]{code});
}

private String getString(Object object, String method) {
return (String) ReflectUtils.invokeMethodWithNoneParameter(object, method).orElse(null);
}

private void initFunction() {
boolean canLoadLowVersion = canLoadLowVersion();
if (canLoadLowVersion) {
getRequestUri = obj -> ((HttpServletRequest) obj).getRequestURI();
getPathInfo = obj -> ((HttpServletRequest) obj).getPathInfo();
getMethod = obj -> ((HttpServletRequest) obj).getMethod();
getHeaderNames = obj -> ((HttpServletRequest) obj).getHeaderNames();
getHeader = (obj, key) -> ((HttpServletRequest) obj).getHeader(key);
getWriter = obj -> {
try {
return ((HttpServletResponse) obj).getWriter();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
};
setStatus = (obj, code) -> ((HttpServletResponse) obj).setStatus(code);
} else {
getRequestUri = this::getRequestUri;
getPathInfo = this::getPathInfo;
getMethod = this::getMethod;
getHeaderNames = this::getHeaderNames;
getHeader = this::getHeader;
getWriter = this::getWriter;
setStatus = this::setStatus;
}
}

private boolean canLoadLowVersion() {
try {
Class.forName(HttpServletRequest.class.getCanonicalName());
} catch (NoClassDefFoundError | ClassNotFoundException error) {
return false;
}
return true;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (C) 2022-2024 Huawei Technologies Co., Ltd. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -20,9 +20,12 @@
import io.sermant.core.plugin.agent.entity.ExecuteContext;
import io.sermant.core.plugin.agent.interceptor.AbstractInterceptor;
import io.sermant.core.utils.LogUtils;
import io.sermant.core.utils.ReflectUtils;
import io.sermant.monitor.common.MetricCalEntity;
import io.sermant.monitor.util.MonitorCacheUtil;

import java.util.function.Function;

import javax.servlet.http.HttpServletRequest;

/**
Expand All @@ -34,6 +37,15 @@
public class DispatcherServletInterceptor extends AbstractInterceptor {
private static final String START_TIME = "startTime";

private Function<Object, String> getRequestUri;

/**
* 构造方法
*/
public DispatcherServletInterceptor() {
initFunction();
}

@Override
public ExecuteContext before(ExecuteContext context) {
LogUtils.printHttpRequestBeforePoint(context);
Expand All @@ -50,7 +62,7 @@ public ExecuteContext after(ExecuteContext context) {
LogUtils.printHttpRequestAfterPoint(context);
return context;
}
String uri = ((HttpServletRequest) context.getArguments()[0]).getRequestURI();
String uri = getRequestUri.apply(context.getArguments()[0]);
MetricCalEntity metricCalEntity = MonitorCacheUtil.getMetricCalEntity(uri);
metricCalEntity.getReqNum().incrementAndGet();
long startTime = (Long) context.getExtMemberFieldValue(START_TIME);
Expand All @@ -70,11 +82,33 @@ public ExecuteContext onThrow(ExecuteContext context) {
LogUtils.printHttpRequestOnThrowPoint(context);
return context;
}
String uri = ((HttpServletRequest) context.getArguments()[0]).getRequestURI();
String uri = getRequestUri.apply(context.getArguments()[0]);
MetricCalEntity metricCalEntity = MonitorCacheUtil.getMetricCalEntity(uri);
metricCalEntity.getReqNum().incrementAndGet();
metricCalEntity.getFailedReqNum().incrementAndGet();
LogUtils.printHttpRequestOnThrowPoint(context);
return context;
}

private String getRequestUri(Object httpServletRequest) {
return (String) ReflectUtils.invokeMethodWithNoneParameter(httpServletRequest, "getRequestURI").orElse(null);
}

private void initFunction() {
boolean canLoadLowVersion = canLoadLowVersion();
if (canLoadLowVersion) {
getRequestUri = obj -> ((HttpServletRequest) obj).getRequestURI();
} else {
getRequestUri = this::getRequestUri;
}
}

private boolean canLoadLowVersion() {
try {
Class.forName(HttpServletRequest.class.getCanonicalName());
} catch (NoClassDefFoundError | ClassNotFoundException error) {
return false;
}
return true;
}
}
12 changes: 0 additions & 12 deletions sermant-plugins/sermant-router/spring-router-plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,6 @@
<version>${jakarta.el.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
Expand All @@ -79,12 +73,6 @@
<version>${spring.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
<version>${spring.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.projectreactor.netty</groupId>
<artifactId>reactor-netty</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (C) 2022-2024 Huawei Technologies Co., Ltd. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -19,23 +19,23 @@
import io.sermant.core.plugin.agent.matcher.ClassMatcher;

/**
* Add an injection interceptor by intercepting and inject a spring web interceptor
* get http request data
*
* @author provenceee
* @since 2022-07-12
*/
public class HandlerExecutionChainDeclarer extends AbstractDeclarer {
private static final String ENHANCE_CLASS = "org.springframework.web.servlet.HandlerExecutionChain";
public class DispatcherServletDeclarer extends AbstractDeclarer {
private static final String ENHANCE_CLASS = "org.springframework.web.servlet.DispatcherServlet";

private static final String INTERCEPT_CLASS
= "io.sermant.router.spring.interceptor.HandlerExecutionChainInterceptor";
= "io.sermant.router.spring.interceptor.DispatcherServletInterceptor";

private static final String METHOD_NAME = "applyPreHandle";
private static final String METHOD_NAME = "doService";

/**
* Constructor
*/
public HandlerExecutionChainDeclarer() {
public DispatcherServletDeclarer() {
super(ENHANCE_CLASS, INTERCEPT_CLASS, METHOD_NAME);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (C) 2022-2024 Huawei Technologies Co., Ltd. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -59,6 +59,7 @@ public ExecuteContext before(ExecuteContext context) {
Object serviceName = ReflectUtils.getFieldValue(obj, "serviceName").orElse(null);
if (serviceName instanceof String) {
AppCache.INSTANCE.setAppName((String) serviceName);
configService.init(RouterConstant.SPRING_CACHE_NAME, (String) serviceName);
} else {
LOGGER.warning("Service name is null or not instanceof string.");
}
Expand All @@ -69,7 +70,6 @@ public ExecuteContext before(ExecuteContext context) {

@Override
public ExecuteContext after(ExecuteContext context) {
configService.init(RouterConstant.SPRING_CACHE_NAME, AppCache.INSTANCE.getAppName());
return context;
}
}
Loading

0 comments on commit bc976bf

Please sign in to comment.