簡體   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