![](/img/trans.png)
[英]Guice + Jersey 2 + ContainerRequestFilter and @Context
[英]Jersey Async ContainerRequestFilter
我有一個Jersey REST API,並且正在使用ContainerRequestFilter
來處理授權。 我還在所有端點上使用@ManagedAsync
,以便我的API可以處理數千個並發請求。
我的授權過濾器命中了一個遠程服務,但是運行過濾器時,Jersey尚未將當前線程添加到其內部ExecutorService
,因此我完全失去了異步優勢。
我可以告訴Jersey我希望這個ContainerRequestFilter
是異步的嗎?
@Priority(Priorities.AUTHORIZATION)
public class AuthorizationFilter implements ContainerRequestFilter
{
@Inject
private AuthorizationService authSvc;
@Override
public void filter(ContainerRequestContext requestContext) throws IOException
{
String authToken = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);
// HITS A REMOTE SERVER
AuthorizationResponse authResponse = authSvc.authorize(authToken);
if (!authResponse.isAuthorized())
{
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED)
.entity("unauthorized!")
.build());
}
}
}
這是一個示例資源:
@Path("/stuff")
@Produces(MediaType.APPLICATION_JSON)
public class StuffResource
{
@GET
@Path("/{id}")
@ManagedAsync
public void getById(@PathParam("id") long id, @Suspended final AsyncResponse ar)
{
Stuff s;
// HIT THE DATABASE FOR STUFF
ar.resume(s);
}
}
更新剛剛收到澤西隊球員的回音,從2.7開始,這是不可能的。 只有資源方法本身被異步調用,而不是過濾器。 仍然歡迎任何建議。
從2.7開始,它尚未內置在Jersey中。
如果您有任何過濾器或攔截器可以進行任何認真的工作(如命中遠程授權服務),則@ManagedAsync
將無用。 它們可能會增加將來異步運行過濾器的功能,但現在您只能靠自己了。
更新 -還有其他方法...
經過漫長而危險的旅程之后,我發現了一個短期使用的非常棘手的解決方案。 以下是我嘗試過的內容以及失敗/起作用的原因的摘要。
Guice AOP-失敗
我使用Guice進行DI(使Guice注入與Jersey一起工作本身就是一項壯舉 !),所以我認為我可以使用Guice AOP解決該問題。 盡管Guice注入有效,但是Guice無法使用Jersey 2創建資源類,因此Guice AOP無法與資源類方法一起使用。 如果您拼命嘗試讓Guice使用Jersey 2創建資源類, 請不要浪費時間,因為它不會起作用 。 這是一個眾所周知的問題 。
HK2 AOP- 推薦解決方案
HK2最近發布了AOP功能,有關如何使其工作的詳細信息,請參閱此問題 。
監控 -也有效
這不是出於膽小,在Jersey docs中完全不建議這樣做。 您可以注冊ApplicationEventListener
並重寫onRequest
以返回一個RequestEventListener
,以偵聽RESOURCE_METHOD_START
並調用身份驗證/授權服務。 此事件是從@ManagedAsync
線程觸發的,這是這里的全部目標。 需要注意的是, abortWith
方法是一種禁止操作的方法,因此它不能像普通的ContainerRequestFilter
那樣工作。 相反,如果auth失敗,則可以引發異常,然后注冊ExceptionMapper
來處理您的異常。 如果有人足夠大膽嘗試一下,請告訴我,我將發布代碼。
我不確定這是否是您想要的,但是,您是否研究過Spring的OncePerRequestFilter
? 我目前正在將其用於我的授權層,其中每個請求都經過某個過濾器,該過濾器根據將我的過濾器映射到URL的方式擴展了OncePerRequestFilter
。 以下是我的使用方式的快速概述:
我對這些過濾器的異步調度部分不是很清楚,但我希望此鏈接至少可以為您要實現的目標提供一些啟示!
我們使用Spring安全性進行身份驗證/授權。 我使用帶有空路徑的子資源定位器解決了該問題,如下所示:
@Path("/customers")
public class CustomerResource {
@Inject
private CustomerService customerService;
@Path("")
public CustomerSubResource delegate() {
final Authentication auth = SecurityContextHolder.getContext().getAuthentication();
return new CustomerSubResource(auth);
}
public class CustomerSubResource {
private final Authentication auth;
public CustomerSubResource(final Authentication auth) {
this.auth = auth;
}
@POST
@Path("")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@ManagedAsync
public void createCustomer(final Customer customer, @Suspended final AsyncResponse response) {
// Stash the Spring security context into the Jersey-managed thread
SecurityContextHolder.getContext().setAuthentication(this.auth);
// Invoke service method requiring pre-authorization
final Customer newCustomer = customerService.createCustomer(customer);
// Resume the response
response.resume(newCustomer);
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.