未从 VertxResteasyDeployment 调用 JAX-RS DynamicFeature 实现
JAX-RS DynamicFeature implementation not called from VertxResteasyDeployment
我正在尝试使用 MDC 将每个 http 请求的唯一请求 ID 记录到我的资源中,以便调试和跟踪特定请求。同样,我创建了一个自定义注释@TagRequestID。下面是用于记录请求的 ID。但是我无法实现请求的不是通过 DynamicFilter 实现,我认为 VertxResteasyDeployment 中应该有一些方法或方式 class 这应该有助于解决这个问题。
基本上,即使我尝试使用 VertxResteasyDeployment class 的 setProviders 方法,请求也不会通过过滤器。有人可以指导我在这里缺少什么吗?我相信应该有一些配置请求通过我们注入 RequestIdConfig bean 的 DynamicFeature 实现传递请求。 (假设我已经创建了 RequestIdConfig bean)。
@TagRequestID 代码:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TagRequestID {
}
自定义 class RequestIdConfig :
import lombok.Data;
import javax.validation.constraints.NotNull;
@Data
public class RequestIdConfig {
@NotNull
private String resourcePackage;
@NotNull
private String requestIdHeaderKey;
@NotNull
private Boolean requestIdMandatoryFlag;
}
自定义 class RequestIdFeature :
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import javax.ws.rs.ConstrainedTo;
import javax.ws.rs.RuntimeType;
import javax.ws.rs.container.DynamicFeature;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.FeatureContext;
import javax.ws.rs.ext.Provider;
@Slf4j
@AllArgsConstructor
@Provider
public class RequestIdFeature
implements DynamicFeature {
RequestIdConfig requestIdConfig;
@Override
public void configure(ResourceInfo resourceInfo, FeatureContext featureContext) {
log.info("testing now===");
final Class<?> resourceClass = resourceInfo.getResourceClass();
//Check if the current resource is to validated
if (resourceClass.getPackage().getName().startsWith(requestIdConfig.getResourcePackage())) {
//Check if the Validation annotation is present
if (resourceInfo.getResourceMethod().getAnnotation(TagRequestID.class) != null) {
log.info(resourceInfo.getResourceMethod() + " registered for clientID validation");
featureContext.register(new RequestIdFilter(requestIdConfig, resourceInfo));
}
}
}
}
自定义 class 过滤器:
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jboss.logging.MDC;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.UUID;
@Data
@AllArgsConstructor
@Slf4j
@Provider
public class RequestIdFilter
implements ContainerRequestFilter {
RequestIdConfig requestIdConfig;
ResourceInfo resourceInfo;
public static final String REQUEST_ID = "request-Id";
@Override
public void filter(ContainerRequestContext containerRequestContext) throws IOException {
log.info("ClientIdValidation filter method invoked");
Method resourceMethod = resourceInfo.getResourceMethod();
// Validate Clients
validatePermissions(containerRequestContext);
}
private void validatePermissions(final ContainerRequestContext containerRequestContext) {
String requestId = containerRequestContext.getHeaderString(requestIdConfig.getRequestIdHeaderKey());
//Make sure the Header key is present if mandatory flag is true
if (requestIdConfig.getRequestIdMandatoryFlag() && StringUtils.isAnyEmpty(requestId)) {
throw new WebApplicationException(requestIdConfig.getRequestIdHeaderKey() + " can't be null", Response.Status.UNAUTHORIZED);
}
//If no request ID present, generate a UUID
if (StringUtils.isAnyEmpty(requestId)) {
requestId = UUID.randomUUID()
.toString();
}
containerRequestContext.setProperty(REQUEST_ID, requestId);
MDC.put(REQUEST_ID, requestId);
}
}
资源或控制器代码:
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.container.AsyncResponse;
import javax.ws.rs.container.Suspended;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import io.vertx.core.Vertx;
import io.vertx.core.WorkerExecutor;
public class Processor {
@POST
@TagRequestID
@Path("/update_record")
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON })
public void updateEvent(String data) throws Exception{
//do something here
}
来自我们运行这个的服务器代码:
import mypackage.Processor;
import io.vertx.core.AbstractVerticle;
import org.jboss.resteasy.plugins.server.vertx.VertxRequestHandler;
import org.jboss.resteasy.plugins.server.vertx.VertxResteasyDeployment;
import org.springframework.context.ApplicationContext;
public class VertxServer extends AbstractVerticle {
VertxServer(final ApplicationContext context) {
}
@Override
public void start() throws Exception {
VertxResteasyDeployment deployment = new VertxResteasyDeployment();
deployment.start();
deployment.getRegistry().addPerInstanceResource(Processors.class);
vertx.createHttpServer()
.requestHandler(new VertxRequestHandler(vertx, deployment))
.listen(8080);
}
}
一旦服务器启动并且 运行ning 然后就可以在上面的控制器上同时点击两个请求。即:
curl -X POST \ http://localhost:8080/v1/update_record \ -H
'Cache-Control: no-cache' \ -H 'Content-Type: application/json' \
-H 'Postman-Token: c9494189-4ac9-9f6c-44f6-216186c74431' \ -d '{"id":"123"}'
VertxServer.java
deployment.getProviderFactory().register(RequestIdFilter.class)
在 VertxServer.java 中,在注册资源之前在 providerFactory 中注册您的 dynamicFeature 实例。这个在providerFactory中注册的dynamicFeatures和filters会在注册资源的时候用到。
您的代码将如下所示:
VertxResteasyDeployment deployment = new VertxResteasyDeployment();
deployment.start();
deployment.getProviderFactory().register(new RequestIdFeature(getRequiredBean());
deployment.getRegistry().addPerInstanceResource(Processors.class);
vertx.createHttpServer()
.requestHandler(new VertxRequestHandler(vertx, deployment))
.listen(8080);
我正在尝试使用 MDC 将每个 http 请求的唯一请求 ID 记录到我的资源中,以便调试和跟踪特定请求。同样,我创建了一个自定义注释@TagRequestID。下面是用于记录请求的 ID。但是我无法实现请求的不是通过 DynamicFilter 实现,我认为 VertxResteasyDeployment 中应该有一些方法或方式 class 这应该有助于解决这个问题。
基本上,即使我尝试使用 VertxResteasyDeployment class 的 setProviders 方法,请求也不会通过过滤器。有人可以指导我在这里缺少什么吗?我相信应该有一些配置请求通过我们注入 RequestIdConfig bean 的 DynamicFeature 实现传递请求。 (假设我已经创建了 RequestIdConfig bean)。
@TagRequestID 代码:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TagRequestID {
}
自定义 class RequestIdConfig :
import lombok.Data;
import javax.validation.constraints.NotNull;
@Data
public class RequestIdConfig {
@NotNull
private String resourcePackage;
@NotNull
private String requestIdHeaderKey;
@NotNull
private Boolean requestIdMandatoryFlag;
}
自定义 class RequestIdFeature :
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import javax.ws.rs.ConstrainedTo;
import javax.ws.rs.RuntimeType;
import javax.ws.rs.container.DynamicFeature;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.FeatureContext;
import javax.ws.rs.ext.Provider;
@Slf4j
@AllArgsConstructor
@Provider
public class RequestIdFeature
implements DynamicFeature {
RequestIdConfig requestIdConfig;
@Override
public void configure(ResourceInfo resourceInfo, FeatureContext featureContext) {
log.info("testing now===");
final Class<?> resourceClass = resourceInfo.getResourceClass();
//Check if the current resource is to validated
if (resourceClass.getPackage().getName().startsWith(requestIdConfig.getResourcePackage())) {
//Check if the Validation annotation is present
if (resourceInfo.getResourceMethod().getAnnotation(TagRequestID.class) != null) {
log.info(resourceInfo.getResourceMethod() + " registered for clientID validation");
featureContext.register(new RequestIdFilter(requestIdConfig, resourceInfo));
}
}
}
}
自定义 class 过滤器:
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jboss.logging.MDC;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.UUID;
@Data
@AllArgsConstructor
@Slf4j
@Provider
public class RequestIdFilter
implements ContainerRequestFilter {
RequestIdConfig requestIdConfig;
ResourceInfo resourceInfo;
public static final String REQUEST_ID = "request-Id";
@Override
public void filter(ContainerRequestContext containerRequestContext) throws IOException {
log.info("ClientIdValidation filter method invoked");
Method resourceMethod = resourceInfo.getResourceMethod();
// Validate Clients
validatePermissions(containerRequestContext);
}
private void validatePermissions(final ContainerRequestContext containerRequestContext) {
String requestId = containerRequestContext.getHeaderString(requestIdConfig.getRequestIdHeaderKey());
//Make sure the Header key is present if mandatory flag is true
if (requestIdConfig.getRequestIdMandatoryFlag() && StringUtils.isAnyEmpty(requestId)) {
throw new WebApplicationException(requestIdConfig.getRequestIdHeaderKey() + " can't be null", Response.Status.UNAUTHORIZED);
}
//If no request ID present, generate a UUID
if (StringUtils.isAnyEmpty(requestId)) {
requestId = UUID.randomUUID()
.toString();
}
containerRequestContext.setProperty(REQUEST_ID, requestId);
MDC.put(REQUEST_ID, requestId);
}
}
资源或控制器代码:
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.container.AsyncResponse;
import javax.ws.rs.container.Suspended;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import io.vertx.core.Vertx;
import io.vertx.core.WorkerExecutor;
public class Processor {
@POST
@TagRequestID
@Path("/update_record")
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON })
public void updateEvent(String data) throws Exception{
//do something here
}
来自我们运行这个的服务器代码:
import mypackage.Processor;
import io.vertx.core.AbstractVerticle;
import org.jboss.resteasy.plugins.server.vertx.VertxRequestHandler;
import org.jboss.resteasy.plugins.server.vertx.VertxResteasyDeployment;
import org.springframework.context.ApplicationContext;
public class VertxServer extends AbstractVerticle {
VertxServer(final ApplicationContext context) {
}
@Override
public void start() throws Exception {
VertxResteasyDeployment deployment = new VertxResteasyDeployment();
deployment.start();
deployment.getRegistry().addPerInstanceResource(Processors.class);
vertx.createHttpServer()
.requestHandler(new VertxRequestHandler(vertx, deployment))
.listen(8080);
}
}
一旦服务器启动并且 运行ning 然后就可以在上面的控制器上同时点击两个请求。即:
curl -X POST \ http://localhost:8080/v1/update_record \ -H 'Cache-Control: no-cache' \ -H 'Content-Type: application/json' \
-H 'Postman-Token: c9494189-4ac9-9f6c-44f6-216186c74431' \ -d '{"id":"123"}'
VertxServer.java
deployment.getProviderFactory().register(RequestIdFilter.class)
在 VertxServer.java 中,在注册资源之前在 providerFactory 中注册您的 dynamicFeature 实例。这个在providerFactory中注册的dynamicFeatures和filters会在注册资源的时候用到。
您的代码将如下所示:
VertxResteasyDeployment deployment = new VertxResteasyDeployment();
deployment.start();
deployment.getProviderFactory().register(new RequestIdFeature(getRequiredBean());
deployment.getRegistry().addPerInstanceResource(Processors.class);
vertx.createHttpServer()
.requestHandler(new VertxRequestHandler(vertx, deployment))
.listen(8080);