繁体   English   中英

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

[英]How do I intercept selective methods and classes in JAX-RS in Java EE 7 compliant container?

我想拦截用@Foo注释的任何classmethods

级别拦截:

@Foo
@path("/foo")
public class Attack {...}

方法级别拦截:

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

@Foo
@GET
public String myMethod(){....}

我想拦截用@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")

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

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

谢谢

浏览JAX-RSJava EE教程 ,似乎没有提到jsr339-jaxrs-2.0-final-spec中滤波器和拦截器概念的任何内容。 您应该下载副本以获取完整信息。

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

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

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

ContainerRequestFilterContainerResponseFilter分别传递ContainerRequestContextContainerResponseContext ,我们可以从中获取UriInfo类的UriInfo来获取路径。

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

public interface ContainerRequestFilter {
    void filter(ContainerRequestContext requestContext)
}

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

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});
    }
}

这是我如何将方法绑定到过滤器。 每种资源方法都通过这个绑定器。 如果它或它的类是带有我们的自定义注释的注释,它将被绑定到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()));
        }
    }  
}

它检查方法或类以查看它是否具有注释@Logged (这是一个自定义注释 - 您可以轻松地将其@Foo

@NameBinding
@Retention(RUNTIME)
@Target({METHOD, TYPE})
public @interface Logged {
}

使用此资源类

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

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

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.

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

拦截器非常简单:

@Foo @Interceptor
public class FooInterceptor
{
    @AroundInvoke
    public Object handleFoo(InvocationContext joinPoint) throws Exception
    {
        Method m = joinPoint.getMethod();

        // you can access all annotations on your @Foo-annotated method,
        // not just the @Foo annotation.
        Annotation[] as = m.getDeclaredAnnotations();

        // do stuff before the method call
        ...

        try
        {
            // here you call the actual method
            return joinPoint.proceed();
        }
        finally
        {
            // do stuff after the method call
            ...
        }
    }
}

这是注释的外观:

@InterceptorBinding
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.TYPE })
public @interface Foo
{
    @Nonbinding
    ... // you could add parameters for your annotation, e.g. @Foo(value)
}

这就是你如何使用它:

@Stateless
public class MyService
{
    @Foo("bar")
    public String myWrappedMethod()
    {
        ...
    }
}

myWrappedMethod中的代码将由FooInterceptor中的代码“包装”。 请注意,只有在对容器管理myWrappedMethod()的方法调用时,才会调用拦截器,即在MyService的托管实例上调用它(例如,通过@Inject)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM