Jersey提供了两个类来与资源上的注释交互:
- ResourceFilterFactory,一个类可以继承它,在应用程序启动时触发一次
- ContainerRequestFilter, ContainerResponseFilter,几个类可以继承它们,在每个请求/响应时触发
ResourceFilterFactory定义了一个create
方法(要实现),它接受一个AbstractMethod
来访问方法和类注释。
ContainerRequestFilter和ContainerResponseFilter定义了一个filter
方法(要实现),该方法接受请求/响应,但这些方法只能访问被调用的方法注释,而不是类注释。
我试图实现一个CacheControl注释定义HTTP缓存头如下方式。
@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 ?
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混乱(存储当前适用于给定线程的抽象方法)。不确定这是不是你想要的。为每个对象使用一个单独的对象并不那么昂贵。
UPDATE:还要注意,您不希望为每个方法创建一个新的实例。你只需要对带有@CacheControl注释的方法或它们的资源这样做,对吧?你也可以为相同的@CacheControl值共享过滤器实例——也就是说,如果一个方法与其他方法使用相同的缓存控制设置,则重用相同的过滤器,否则,为该方法创建一个单独的过滤器实例。换句话说——你可以为每个不同的缓存控制设置设置一个过滤器,而不是为每个方法设置一个过滤器——因为你并不真正关心方法——你关心的是附加在它上面的注释。