From c4ba9498664516ac77451140111e3cca85726a51 Mon Sep 17 00:00:00 2001 From: provenceee <83857838+provenceee@users.noreply.github.com> Date: Tue, 12 Nov 2024 11:19:38 +0800 Subject: [PATCH] *router piugin support springboot3 Signed-off-by: provenceee <83857838+provenceee@users.noreply.github.com> --- .../flowcontrol-plugin/pom.xml | 2 +- .../DispatcherServletInterceptor.java | 81 +++++++++++++++++-- .../sermant-monitor/monitor-plugin/pom.xml | 6 ++ .../DispatcherServletInterceptor.java | 35 +++++++- .../DispatcherServletInterceptor.java | 51 ++++++++++-- .../DispatcherServletInterceptor.java | 69 ++++++++++++++-- 6 files changed, 220 insertions(+), 24 deletions(-) diff --git a/sermant-plugins/sermant-flowcontrol/flowcontrol-plugin/pom.xml b/sermant-plugins/sermant-flowcontrol/flowcontrol-plugin/pom.xml index 99034b5c20..acea97cd75 100644 --- a/sermant-plugins/sermant-flowcontrol/flowcontrol-plugin/pom.xml +++ b/sermant-plugins/sermant-flowcontrol/flowcontrol-plugin/pom.xml @@ -67,7 +67,7 @@ javax.servlet javax.servlet-api ${servlet-api.version} - test + provided org.springframework.boot diff --git a/sermant-plugins/sermant-flowcontrol/flowcontrol-plugin/src/main/java/com/huawei/flowcontrol/DispatcherServletInterceptor.java b/sermant-plugins/sermant-flowcontrol/flowcontrol-plugin/src/main/java/com/huawei/flowcontrol/DispatcherServletInterceptor.java index dcfb304d74..863f47594e 100644 --- a/sermant-plugins/sermant-flowcontrol/flowcontrol-plugin/src/main/java/com/huawei/flowcontrol/DispatcherServletInterceptor.java +++ b/sermant-plugins/sermant-flowcontrol/flowcontrol-plugin/src/main/java/com/huawei/flowcontrol/DispatcherServletInterceptor.java @@ -26,12 +26,19 @@ import com.huaweicloud.sermant.core.utils.LogUtils; import com.huaweicloud.sermant.core.utils.ReflectUtils; +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; /** * DispatcherServlet 的 API接口增强 埋点定义sentinel资源 @@ -42,6 +49,28 @@ public class DispatcherServletInterceptor extends InterceptorSupporter { private final String className = DispatcherServletInterceptor.class.getName(); + private Function getRequestUri; + + private Function getPathInfo; + + private Function getMethod; + + private Function> getHeaderNames; + + private BiFunction getHeader; + + private Function getWriter; + + private BiConsumer setStatus; + + /** + * 构造方法 + */ + public DispatcherServletInterceptor() { + super(); + initFunction(); + } + /** * http请求数据转换 适应plugin -> service数据传递 注意,该方法不可抽出,由于宿主依赖仅可由该拦截器加载,因此抽出会导致找不到类 * @@ -52,14 +81,14 @@ private Optional convertToHttpEntity(Object request) { if (request == null) { return Optional.empty(); } - String uri = getRequestUri(request); + String uri = getRequestUri.apply(request); return Optional.of(new HttpRequestEntity.Builder() .setRequestType(RequestType.SERVER) - .setPathInfo(getPathInfo(request)) + .setPathInfo(getPathInfo.apply(request)) .setServletPath(uri) .setHeaders(getHeaders(request)) - .setMethod(getMethod(request)) - .setServiceName(getHeader(request, ConfigConst.FLOW_REMOTE_SERVICE_NAME_HEADER_KEY)) + .setMethod(getMethod.apply(request)) + .setServiceName(getHeader.apply(request, ConfigConst.FLOW_REMOTE_SERVICE_NAME_HEADER_KEY)) .build()); } @@ -70,11 +99,11 @@ private Optional convertToHttpEntity(Object request) { * @return headers */ private Map getHeaders(Object request) { - final Enumeration headerNames = getHeaderNames(request); + final Enumeration headerNames = getHeaderNames.apply(request); final Map headers = new HashMap<>(); while (headerNames.hasMoreElements()) { final String headerName = headerNames.nextElement(); - headers.put(headerName, getHeader(request, headerName)); + headers.put(headerName, getHeader.apply(request, headerName)); } return Collections.unmodifiableMap(headers); } @@ -94,8 +123,8 @@ protected final ExecuteContext doBefore(ExecuteContext context) throws Exception context.skip(null); final Object response = allArguments[1]; if (response != null) { - setStatus(response, result.getResponse().getCode()); - getWriter(response).print(result.buildResponseMsg()); + setStatus.accept(response, result.getResponse().getCode()); + getWriter.apply(response).print(result.buildResponseMsg()); } } return context; @@ -149,4 +178,40 @@ private void setStatus(Object httpServletResponse, int 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 e) { + throw new RuntimeException(e); + } + }; + 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; + } } diff --git a/sermant-plugins/sermant-monitor/monitor-plugin/pom.xml b/sermant-plugins/sermant-monitor/monitor-plugin/pom.xml index 21f7f68421..8e8383e5f3 100644 --- a/sermant-plugins/sermant-monitor/monitor-plugin/pom.xml +++ b/sermant-plugins/sermant-monitor/monitor-plugin/pom.xml @@ -40,6 +40,12 @@ ${apache.dubbo.version} provided + + javax.servlet + javax.servlet-api + ${servlet-api.version} + provided + junit junit diff --git a/sermant-plugins/sermant-monitor/monitor-plugin/src/main/java/com/huawei/monitor/interceptor/DispatcherServletInterceptor.java b/sermant-plugins/sermant-monitor/monitor-plugin/src/main/java/com/huawei/monitor/interceptor/DispatcherServletInterceptor.java index e1d73cd471..6571bdbd49 100644 --- a/sermant-plugins/sermant-monitor/monitor-plugin/src/main/java/com/huawei/monitor/interceptor/DispatcherServletInterceptor.java +++ b/sermant-plugins/sermant-monitor/monitor-plugin/src/main/java/com/huawei/monitor/interceptor/DispatcherServletInterceptor.java @@ -25,6 +25,10 @@ import com.huaweicloud.sermant.core.utils.LogUtils; import com.huaweicloud.sermant.core.utils.ReflectUtils; +import java.util.function.Function; + +import javax.servlet.http.HttpServletRequest; + /** * HTTP拦截定义 * @@ -34,6 +38,15 @@ public class DispatcherServletInterceptor extends AbstractInterceptor { private static final String START_TIME = "startTime"; + private Function getRequestUri; + + /** + * 构造方法 + */ + public DispatcherServletInterceptor() { + initFunction(); + } + @Override public ExecuteContext before(ExecuteContext context) { LogUtils.printHttpRequestBeforePoint(context); @@ -50,7 +63,7 @@ public ExecuteContext after(ExecuteContext context) { LogUtils.printHttpRequestAfterPoint(context); return context; } - String uri = getRequestUri(context.getArguments()[0]); + String uri = getRequestUri.apply(context.getArguments()[0]); MetricCalEntity metricCalEntity = MonitorCacheUtil.getMetricCalEntity(uri); metricCalEntity.getReqNum().incrementAndGet(); long startTime = (Long) context.getExtMemberFieldValue(START_TIME); @@ -70,7 +83,7 @@ public ExecuteContext onThrow(ExecuteContext context) { LogUtils.printHttpRequestOnThrowPoint(context); return context; } - String uri = getRequestUri(context.getArguments()[0]); + String uri = getRequestUri.apply(context.getArguments()[0]); MetricCalEntity metricCalEntity = MonitorCacheUtil.getMetricCalEntity(uri); metricCalEntity.getReqNum().incrementAndGet(); metricCalEntity.getFailedReqNum().incrementAndGet(); @@ -81,4 +94,22 @@ public ExecuteContext onThrow(ExecuteContext 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; + } } diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/DispatcherServletInterceptor.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/DispatcherServletInterceptor.java index 38efd2b9a0..f52cd92393 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/DispatcherServletInterceptor.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/com/huaweicloud/sermant/router/spring/interceptor/DispatcherServletInterceptor.java @@ -42,6 +42,10 @@ import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.function.BiFunction; +import java.util.function.Function; + +import javax.servlet.http.HttpServletRequest; /** * 获取http请求数据 @@ -54,6 +58,16 @@ public class DispatcherServletInterceptor extends AbstractInterceptor { private final SpringConfigService configService; + private Function getQueryString; + + private Function getRequestUri; + + private Function getMethod; + + private Function> getHeaderNames; + + private BiFunction> getHeaders; + /** * 构造方法 */ @@ -63,6 +77,7 @@ public DispatcherServletInterceptor() { handlers.add(new LaneHandler()); handlers.add(new RouteHandler()); handlers.sort(Comparator.comparingInt(Handler::getOrder)); + initFunction(); } @Override @@ -75,11 +90,11 @@ public ExecuteContext before(ExecuteContext context) { } Object request = context.getArguments()[0]; Map> headers = getHeaders(request); - String queryString = SpringRouterUtils.getQueryString(request); + String queryString = getQueryString.apply(request); String decode = Optional.ofNullable(queryString).map(this::decode).orElse(StringUtils.EMPTY); Map> queryParams = SpringRouterUtils.getParametersByQuery(decode); - String path = SpringRouterUtils.getRequestUri(request); - String method = SpringRouterUtils.getMethod(request); + String path = getRequestUri.apply(request); + String method = getMethod.apply(request); handlers.forEach(handler -> ThreadLocalUtils.addRequestTag( handler.getRequestTag(path, method, headers, queryParams, new Keys(matchKeys, injectTags)))); return context; @@ -109,10 +124,10 @@ private String decode(String str) { private Map> getHeaders(Object request) { Map> headers = new HashMap<>(); - Enumeration enumeration = SpringRouterUtils.getHeaderNames(request); + Enumeration enumeration = getHeaderNames.apply(request); while (enumeration.hasMoreElements()) { String key = (String) enumeration.nextElement(); - headers.put(key, enumeration2List(SpringRouterUtils.getHeaders(request, key))); + headers.put(key, enumeration2List(getHeaders.apply(request, key))); } return headers; } @@ -127,4 +142,30 @@ private List enumeration2List(Enumeration enumeration) { } return collection; } + + private void initFunction() { + boolean canLoadLowVersion = canLoadLowVersion(); + if (canLoadLowVersion) { + getQueryString = obj -> ((HttpServletRequest) obj).getQueryString(); + getRequestUri = obj -> ((HttpServletRequest) obj).getRequestURI(); + getMethod = obj -> ((HttpServletRequest) obj).getMethod(); + getHeaderNames = obj -> ((HttpServletRequest) obj).getHeaderNames(); + getHeaders = (obj, key) -> ((HttpServletRequest) obj).getHeaders(key); + } else { + getQueryString = SpringRouterUtils::getQueryString; + getRequestUri = SpringRouterUtils::getRequestUri; + getMethod = SpringRouterUtils::getMethod; + getHeaderNames = SpringRouterUtils::getHeaderNames; + getHeaders = SpringRouterUtils::getHeaders; + } + } + + private boolean canLoadLowVersion() { + try { + Class.forName(HttpServletRequest.class.getCanonicalName()); + } catch (NoClassDefFoundError | ClassNotFoundException error) { + return false; + } + return true; + } } \ No newline at end of file diff --git a/sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/main/java/com/huawei/registry/grace/interceptors/DispatcherServletInterceptor.java b/sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/main/java/com/huawei/registry/grace/interceptors/DispatcherServletInterceptor.java index 73bdea5bd8..95f4ad74b2 100644 --- a/sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/main/java/com/huawei/registry/grace/interceptors/DispatcherServletInterceptor.java +++ b/sermant-plugins/sermant-service-registry/spring-cloud-registry-plugin/src/main/java/com/huawei/registry/grace/interceptors/DispatcherServletInterceptor.java @@ -36,6 +36,12 @@ import com.huaweicloud.sermant.core.utils.ReflectUtils; import com.huaweicloud.sermant.core.utils.StringUtils; +import java.util.function.BiFunction; +import java.util.function.Function; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + /** * Spring Web请求拦截器 * @@ -47,12 +53,21 @@ public class DispatcherServletInterceptor extends GraceSwitchInterceptor { private final GraceConfig graceConfig; + private Consumer addHeader; + + private Function getServerPort; + + private Function getRemoteAddr; + + private BiFunction getHeader; + /** * 构造方法 */ public DispatcherServletInterceptor() { graceService = PluginServiceManager.getPluginService(GraceService.class); graceConfig = PluginConfigManager.getPluginConfig(GraceConfig.class); + initFunction(); } @Override @@ -70,11 +85,11 @@ public ExecuteContext doBefore(ExecuteContext context) { if (graceShutDownManager.isShutDown() && graceConfig.isEnableGraceShutdown()) { // 已被标记为关闭状态, 开始统计进入的请求数 final ClientInfo clientInfo = RegisterContext.INSTANCE.getClientInfo(); - addHeader(response, GraceConstants.MARK_SHUTDOWN_SERVICE_ENDPOINT, + addHeader.accept(response, GraceConstants.MARK_SHUTDOWN_SERVICE_ENDPOINT, buildEndpoint(clientInfo.getIp(), clientInfo.getPort())); - addHeader(response, GraceConstants.MARK_SHUTDOWN_SERVICE_ENDPOINT, + addHeader.accept(response, GraceConstants.MARK_SHUTDOWN_SERVICE_ENDPOINT, buildEndpoint(clientInfo.getHost(), clientInfo.getPort())); - addHeader(response, GraceConstants.MARK_SHUTDOWN_SERVICE_NAME, clientInfo.getServiceName()); + addHeader.accept(response, GraceConstants.MARK_SHUTDOWN_SERVICE_NAME, clientInfo.getServiceName()); } return context; } @@ -94,17 +109,17 @@ public ExecuteContext doThrow(ExecuteContext context) { private void addGraceAddress(Object request) { if (graceConfig.isEnableSpring() && graceConfig.isEnableGraceShutdown() && graceConfig.isEnableOfflineNotify() && GraceConstants.GRACE_OFFLINE_SOURCE_VALUE - .equals(getHeader(request, GraceConstants.GRACE_OFFLINE_SOURCE_KEY))) { - String address = getHeader(request, GraceConstants.SERMANT_GRACE_ADDRESS); + .equals(getHeader.apply(request, GraceConstants.GRACE_OFFLINE_SOURCE_KEY))) { + String address = getHeader.apply(request, GraceConstants.SERMANT_GRACE_ADDRESS); if (StringUtils.isBlank(address)) { - address = getRemoteAddr(request) + ":" + getServerPort(request); + address = getRemoteAddr.apply(request) + ":" + getServerPort.apply(request); } graceService.addAddress(address); } } - private void addHeader(Object httpServletRequest, String key, String value) { - ReflectUtils.invokeMethod(httpServletRequest, "addHeader", new Class[]{String.class, String.class}, + private void addHeader(Object httpServletResponse, String key, String value) { + ReflectUtils.invokeMethod(httpServletResponse, "addHeader", new Class[]{String.class, String.class}, new Object[]{key, value}); } @@ -124,4 +139,42 @@ private String getHeader(Object httpServletRequest, String key) { private String getString(Object object, String method) { return (String) ReflectUtils.invokeMethodWithNoneParameter(object, method).orElse(null); } + + private void initFunction() { + boolean canLoadLowVersion = canLoadLowVersion(); + if (canLoadLowVersion) { + addHeader = (obj, key, value) -> ((HttpServletResponse) obj).addHeader(key, value); + getServerPort = obj -> ((HttpServletRequest) obj).getServerPort(); + getRemoteAddr = obj -> ((HttpServletRequest) obj).getRemoteAddr(); + getHeader = (obj, key) -> ((HttpServletRequest) obj).getHeader(key); + } else { + addHeader = this::addHeader; + getServerPort = this::getServerPort; + getRemoteAddr = this::getRemoteAddr; + getHeader = this::getHeader; + } + } + + private boolean canLoadLowVersion() { + try { + Class.forName(HttpServletRequest.class.getCanonicalName()); + } catch (NoClassDefFoundError | ClassNotFoundException error) { + return false; + } + return true; + } + + /** + * mapping + * + * @param parameter1 + * @param parameter2 + * @param parameter3 + * @author proveceee + * @since 2024-11-15 + */ + @FunctionalInterface + private interface Consumer { + void accept(T t, R r, U u); + } }