如何在 Jersey ContainerResponseFilter 中获取资源注释 [英] How can I get resource annotations in a Jersey ContainerResponseFilter

查看:24
本文介绍了如何在 Jersey ContainerResponseFilter 中获取资源注释的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Jersey 提供了两个类来与资源注释进行交互:

Jersey offers two classes to interact with annotations on resources:

  • ResourceFilterFactory, one class can inherit it to be triggered one time when the application starts
  • ContainerRequestFilter, ContainerResponseFilter, several classes can inherit them to be triggered on every request/response

ResourceFilterFactory 定义了一个 create 方法(要实现),它采用一个 AbstractMethod 来访问方法和类注释.

ResourceFilterFactory defines a create method (to implement) that take an AbstractMethod which gives access to methods and classes annotations.

ContainerRequestFilter 和 ContainerResponseFilter 定义了一个 filter 方法(要实现),它接受请求/响应,但这些方法只能访问被调用的方法注释,而不是类.

ContainerRequestFilter and ContainerResponseFilter defines a filter method (to implement) that take request/response but those give solely access to the called method annotation, not the class one.

我正在尝试实现一个 CacheControl 注释,该注释通过以下方式定义 HTTP 缓存标头.

I'm trying to implement a CacheControl annotation that defines HTTP cache headers the following way.

@Path("/path")
@CacheControl(maxAge = 172800)
public class Resource
{   
    @GET
    @Path("/{id}")
    @CacheControl(mustRevalidate = true)
    public Response get(@PathParam("id") Long id)
    {
        ...
    }
}

<小时>

我的问题是我不想为应用程序中定义的每个 REST 方法创建一个新的 CacheControlFilter.

public class FilterFactory implements ResourceFilterFactory
{    
    @Override
    public List<ResourceFilter> create(AbstractMethod method)
    {
        List<ResourceFilter> filters = newArrayList();
        if (isAnnotationPresent(method, CacheControl.class))
            filters.add(new CacheControlFilter(method));
        return filters;
    }

    private boolean isAnnotationPresent(AbstractMethod method, Class<? extends Annotation> clazz)
    {
        return method.isAnnotationPresent(clazz) || method.getResource().isAnnotationPresent(clazz);
    }
}

<小时>

有没有办法访问 AbstractMethod 而不为每个 REST 方法实例化 CacheContronlFilter?


Is there a way to access the AbstractMethod without instancing a CacheContronlFilter for every REST method?

public class CacheControlFilter implements ResourceFilter, ContainerResponseFilter
{
    private AbstractMethod method;

    public CacheControlFilter(AbstractMethod method)
    {
        this.method = method;
    }

    @Override
    public ContainerResponse filter(ContainerRequest request, ContainerResponse response)
    {
        putCacheControlIfExists(response, method.getAnnotations());
        putCacheControlIfExists(response, method.getResource().getAnnotations());
        return response;
    }

    private void putCacheControlIfExists(ContainerResponse response, Annotation[] annotations)
    {
        CacheControl annotation = findCacheControl(annotations);
        if (annotation != null)
            response.getHttpHeaders().put(CACHE_CONTROL, createCacheControlHeader(annotation));
    }

    private CacheControl findCacheControl(Annotation[] annotations)
    {
        for (Annotation annotation : annotations)
            if (annotation instanceof CacheControl)
                return (CacheControl) annotation;
        return null;
    }

    private List<Object> createCacheControlHeader(CacheControl annotation)
    {
        javax.ws.rs.core.CacheControl header = new javax.ws.rs.core.CacheControl();
        header.setMaxAge(annotation.maxAge());
        header.setMustRevalidate(annotation.mustRevalidate());
        header.setNoCache(annotation.noCache());
        header.setNoStore(annotation.noStore());
        header.setNoTransform(annotation.noTransform());
        header.setProxyRevalidate(annotation.proxyRevalidate());
        return Lists.<Object> newArrayList(Splitter.on(',').split(header.toString()));
    }

    @Override
    public ContainerRequestFilter getRequestFilter()
    {
        return null;
    }

    @Override
    public ContainerResponseFilter getResponseFilter()
    {
        return this;
    }
}

推荐答案

为什么不为每个适用的方法都有一个单独的过滤器实例很重要?可能有很多并发访问,所以如果你不希望这些是单独的实例,它们必须是可变的,你将不得不进入 threadlocals 混乱(存储当前适用于给定线程的抽象方法).不确定这是否是您真正想要的.为每个对象拥有一个单独的对象并不昂贵.

Why is it important to not have a separate instance of the filter for every applicable method? There may be a lot of concurrent access, so if you don't want these to be separate instances, they would have to be mutable and you would have to get into the threadlocals mess (to store the abstract method currently applicable for the given thread). Not sure if that's what you really want. Having a separate object for each is not that expensive.

更新:另外请注意,您不想为每个方法创建一个新实例.您只想对附加到它们或其资源的任何 @CacheControl 注释的方法执行此操作,对吗?您还可以为常见的 @CacheControl 值共享过滤器实例 - 即,如果一个方法使用与其他方法相同的缓存控制设置,则重复使用相同的过滤器,如果没有,则为该方法创建一个单独的过滤器实例.换句话说——你可以为每个不同的缓存控制设置一个过滤器,而不是每个方法一个过滤器——因为你并不真正关心方法——你关心附加到它的注释.

UPDATE: Also note, you don't want to create a new instance for every method. You just want to do it for methods with any @CacheControl annotation attached to them or to their resources, right? Also you can share filter instances for common @CacheControl values - i.e. if a method uses the same cache control setting as some other method, reuse the same filter for that, if not, create a separate instance of the filter for that method. In other words - you can have one filter per one distinct cache-control setting as opposed to one filter per method - as you don't really care about the method - you care about the annotations attached to it.

这篇关于如何在 Jersey ContainerResponseFilter 中获取资源注释的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆