如何拦截 Java EE 7 兼容容器中 JAX-RS 中的选择性方法和类?

bra*_*orm 4 java jax-rs interceptor java-ee-7

我想拦截任何class或methods注释为@Foo

类级别拦截:

@Foo
@path("/foo")
public class Attack {...}
Run Code Online (Sandbox Code Playgroud)

方法级拦截:

@path("/bar")
public class defend {

@Foo
@GET
public String myMethod(){....}
Run Code Online (Sandbox Code Playgroud)

我想拦截任何带有注释的类或方法,@Foo但不拦截其他方法或类。我想在继续方法执行之前打印出整个路径或 URI。一方法调用完成,我想打印出“执行成功”

这是这样的事情:

 system.out.println(path) // this is the path the request is made. something like /api/2/imp/foo
   method call happens
   method call finishes
   System.out.println("executed successfully")
Run Code Online (Sandbox Code Playgroud)

我的情况有所不同,但这是我遇到的根本问题。我不想具体实施。Java EE 7 规范有一种方法可以使用 @Postconstruct、@AroundInvoke 等来做到这一点。但我真的很难组装它。

这篇文章绝对是解决这个问题的好方法。但它是特定于实现的(RESTeasy)并且AcceptByMethod它使用的已被弃用。

谢谢

Pau*_*tha 5

浏览JAX-RS 的 Java EE 教程,似乎他们没有提到jsr339-jaxrs-2.0-final-spec中有关过滤器和拦截器概念的任何内容。您可能应该下载一份副本以获取完整信息。

过滤器和实体拦截器可以注册以在 JAX-RS 实现中定义良好的扩展点处执行。它们用于扩展实现,以提供日志记录、机密性、身份验证、实体压缩等功能

实体拦截器在特定扩展点包装方法调用。过滤器在扩展点执行代码,但不包装方法调用。

基本上,最后一段是说拦截器与方法调用出现在同一执行堆栈中,而过滤器则不然。这并不意味着我们不能对您的日志记录案例使用过滤器。传递给过滤器接口方法的过滤器上下文实际上有更多可以使用的信息。

ContainerRequestFilter和ContainerResponseFilter分别传递ContainerRequestContext和ContainerResponseContext,我们可以从中获取诸如 之类的东西来获取路径。UriInfo

public interface ContainerResponseFilter {
    void filter(ContainerRequestContext requestContext, 
           ContainerResponseContext responseContext)
}

public interface ContainerRequestFilter {
    void filter(ContainerRequestContext requestContext)
}
Run Code Online (Sandbox Code Playgroud)

这是一个日志过滤器的简单示例。有几种不同的方法来绑定过滤器,但在这个示例中,我将使用动态绑定,显式实例化过滤器,因此我没有容器管理状态,并将类和方法名称传递给过滤器

public class LoggingFilter implements ContainerRequestFilter,
                                      ContainerResponseFilter {

    private static final Logger logger
            = Logger.getLogger(LoggingFilter.class.getName());

    protected String className;
    protected String methodName;

    public NewLoggingFilter(String className, String methodName) {
        this.className = className;
        this.methodName = methodName;
    }

    @Override
    public void filter(ContainerRequestContext requestContext) 
                                                      throws IOException {
        logger.log(Level.INFO, "Request path: {0}",
                requestContext.getUriInfo().getAbsolutePath().toString());
        logger.log(Level.INFO, "Starting Method: {0}.{1}",
                new Object[]{className, methodName});
    }

    @Override
    public void filter(ContainerRequestContext requestContext,
                       ContainerResponseContext responseContext)
                                                       throws IOException {

        logger.log(Level.INFO, "Finished Method: {0}.{1}",
                                       new Object[]{className, methodName});
    }
}
Run Code Online (Sandbox Code Playgroud)

以下是我将方法绑定到过滤器的方法。每个资源方法都经过这个绑定器。如果它或它的类使用我们的自定义注释进行注释,它将被绑定到 out LoggingFilter。我们还传递LogginFilter资源方法的类和方法名称。我们将使用这些名称进行日志记录

@Provider
public class LoggingBinder implements DynamicFeature {

    @Override
    public void configure(ResourceInfo ri, FeatureContext fc) {
        Class<?> clazz = ri.getResourceClass();
        Method method = ri.getResourceMethod();
        if (method.isAnnotationPresent(Logged.class) 
                || clazz.isAnnotationPresent(Logged.class)) {
            fc.register(new LoggingFilter(clazz.getName(), method.getName()));
        }
    }  
}
Run Code Online (Sandbox Code Playgroud)

它检查方法或类以查看它是否具有注释@Logged(这是自定义注释 - 您可以轻松调用它@Foo)

@NameBinding
@Retention(RUNTIME)
@Target({METHOD, TYPE})
public @interface Logged {
}
Run Code Online (Sandbox Code Playgroud)

使用该资源类

@Path("/log")
public class LogResource {
    @GET
    @Logged
    public Response getLoggingResourceMethod() {
        return Response.ok("Hello Logging Response").build();
    }
}
Run Code Online (Sandbox Code Playgroud)

我们在日志中得到以下结果

Oct 25, 2014 4:36:05 PM jaxrs.stackoverflow.filter.NewLoggingFilter filter
INFO: Request path: http://localhost:8081/rest/log
Oct 25, 2014 4:36:05 PM jaxrs.stackoverflow.filter.NewLoggingFilter filter
INFO: Starting Method: jaxrs.stackoverflow.filter.LogResource.getLoggingResourceMethod
Oct 25, 2014 4:36:05 PM jaxrs.stackoverflow.filter.NewLoggingFilter filter
INFO: Finished Method: jaxrs.stackoverflow.filter.LogResource.getLoggingResourceMethod
Oct 25, 2014 4:36:05 PM jaxrs.stackoverflow.filter.NewLoggingFilter filter
INFO: Method successful.
Run Code Online (Sandbox Code Playgroud)

不要忘记下载规范以获取更多详细信息。