从Jersey过滤器或拦截器内部访问资源方法参数。或将AOP与资源方法一起使用

时间:2018-08-27 12:59:58

标签: java jersey jax-rs aop jersey-2.0

我正在尝试使用用户ID丰富每个请求的SLF4J MDC。问题在于,ID可以通过多种方式传递,有时作为路径参数传递,有时在体内传递,有时由首先对其进行解密的自定义ValueFactoryProvider注入。

如果我能以某种方式访问​​所有注入的(即已经已反序列化)参数值,那么我可以轻松地处理所有这些情况。

例如

对于资源,例如:

@GET
//@Encrypted params are injected by a custom ValueFactoryProvider
public Something getSomething(@Encrypted("userId") String userId) {
    return ...;
}

@POST
public Something getSomething(@RequestBody RequestWithUserId requestWithUserId) {
    return ...;
}

我可以有一个过滤器,例如:

public class MdcFilter implements ContainerRequestFilter, ContainerResponseFilter {

    @Context
    private ResourceInfo resourceInfo;

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        Method theMethod = resourceInfo.getResourceMethod();
        for (Parameter parameter : theMethod.getParameters()) {
            //Deal with the @Encrypted case
            if (parameter.isAnnotationPresent(Encrypted.class) && parameter.getAnnotation(Encrypted.class).value().equals("userId")) {
                MDC.put("userId", somehowGetTheValue());
            }
            //Deal with the @RequestBody case
            if (parameter.isAnnotationPresent(RequestBody.class) && parameter.getType().equals(RequestWithUserId.class)) {
                MDC.put("userId", ((RequestWithUserId)somehowGetTheValue()).getUserId());
            }
            ... //other possibilities
        }
    }

    @Override
    public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
        MDC.clear();
    }
}

但是我没有办法通过somehowGetTheValue拦截器或其他任何方式来实现ContainerRequestFilter

2 个答案:

答案 0 :(得分:2)

Jersey在幕后使用HK2进行依赖项注入。 HK2有AOP support。您的用例的一种选择是使用此AOP支持。您需要做的就是实现MethodInterceptorInterceptionService。在php artisan migrate中,您可以从MethodInterceptor获取所有参数,还可以从MethodInvocation

获取参数注释。
Method

要使用拦截器,请配置class MyMethodInteceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { Method method = invocation.getMethod(); Object[] args = invocation.getArguments(); // do your logging or whatever with the args. // invoke method and get return value. Object returnValue = invocation.proceed(); // if you want to do something with the return // value before returning it, you can. return returnValue; } }

InterceptionService

您确定应该在public class MyInterceptionService implements InterceptionService { private final static MethodInterceptor METHOD_INTERCEPTOR = new MyMethodInterceptor(); private final static List<MethodInterceptor> METHOD_LIST = Collections.singletonList(METHOD_INTERCEPTOR); @Override public Filter getDescriptorFilter() { return BuilderHelper.allFilter(); } @Override public List<MethodInterceptor> getMethodInterceptors(Method method) { // you implement shouldIntercept if (shouldIntercept(method)) { return METHOD_LIST; } return null; } @Override public List<ConstructorInterceptor> getConstructorInterceptors(Constructor<?> constructor) { return null; } } 方法中拦截哪种方法。如果应拦截该方法,则返回拦截器列表,否则返回null。一种常见的处理方法是创建自定义注释,然后仅对方法进行注释。在上述方法中,只需检查

getMethodInterceptors()

要使其全部正常工作,您只需要向HK2注册if (method.isAnnotationPresent(YourAnno.class)) { return METHOD_LIST; } 。您可以在InteceptionService中进行此操作,这是Jersey应用中用于配置DI的方法。

AbstractBinder

您可以在this GitHub repo中看到完整的示例。 HK2网站中也有一个官方示例。只需查看文章顶部的链接“ AOP支持”即可。

答案 1 :(得分:0)

您可以这样获得

StringWriter stringWriter = new StringWriter();
IOUtils.copy(new InputStreamReader(requestContext.getEntityStream()), stringWriter);
System.out.println(stringWriter.toString());// String representation of the payload
requestContext.setEntityInputStream(new ByteArrayInputStream(requestEntity));

基本上,这个想法是复制流并进行任何处理,然后再将流设置回去。因为如果不这样做,那么在控制器方法中您将得到null,因为流已被读取。