我有一个带有基于令牌的用户身份验证的Jersey REST应用程序。当收到请求时,会创建一个自定义RestContext
对象,并将其作为属性添加到ContainerRequestContext
(通过在收到请求后立即运行的过滤器)。此上下文管理用户授权(通过角色)和对其他业务逻辑的访问。它在资源中可用于执行业务逻辑。当请求被处理时,RestContext
在第二个过滤器中被清除,该过滤器在管道的最后执行。
虽然这需要两个过滤器,但效果良好。我一直在阅读关于HK2和InjectionResolver
的使用,我想知道是否可以使用注入将这个RestContext
注入到我的资源和其他过滤器中(例如,我有一个从RestContext
创建SecurityContext
的过滤器),但我找不到答案。通常,如何根据请求上下文为每个请求注入对象?这可能吗?有没有更简单的方法,例如使用@Context
?
EDIT:如前所述,我基本上是在尝试按照文档的思路在资源中注入一个自定义类。然而,我似乎无法正确注册AbstractBinder
来绑定类的注入。我得到以下信息:
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=RestContext,parent=RestContextFilter,qualifiers={}),position=0,optional=false,self=false,unqualified=null,1435496015)
编辑2:我设法取得了一些小进步。我以以下方式创建配置:
new ResourceConfig(allResources())
.packages(packagesToScan())
.registerInstances(new RestContextBinder());
因为文档清楚地指出,绑定器的注入不是通过类支持的,而是通过实例支持的。
然而,我现在得到的是:
A MultiException has 3 exceptions. They are:
1. java.lang.IllegalStateException: Not inside a request scope.
2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of my.package.RestContextFilter errors were found
3. java.lang.IllegalStateException: Unable to perform operation: resolve on my.package.RestContextFilter
RestContext在请求/响应过滤器中是@Inject
-ed。然后,它被用来创建一个SecurityContext
并将其设置在ContainerRequestContext
中,并在响应过滤器中进行清理。响应筛选器请求的作用域不是吗?为什么我会出错?
UPDATE现在Jersey 2.7已经发布,解决方案更简单了。
听起来你想要一个RequestScoped
绑定。以下是如何使用Jersey 2.7:进行设置
您将需要一个请求筛选器,因为RestContext
将是RequestScoped
,所以您可以在筛选器中注入一个提供程序,在其上设置一些属性,并知道它们将可用于请求的其余部分。
@Priority(Priorities.AUTHORIZATION) // filter deals with roles, comes after AUTHENTICATION
public class RestContextFilter implements ContainerRequestFilter
{
// you need to inject a provider, rather than the class directly
// because this filter is instantiated before the request scope is ready
private Provider<RestContext> rcProvider;
@Inject
public RestContextFilter(Provider<RestContext> rcProvider)
{
this.rcProvider = rcProvider;
}
@Override
public void filter(ContainerRequestContext requestContext) throws IOException
{
// now you're in a request scope and can get your context
RestContext rc = rcProvider.get();
// set some properties on rc here (current user or roles or whatever)
}
}
您需要注册过滤器并使用HK2绑定将RestContext
绑定到ResourceConfig
中:
public class MyResourceConfig extends ResourceConfig
{
public MyResourceConfig()
{
register(RestContextFilter.class);
register(new AbstractBinder()
{
@Override
protected void configure()
{
bindFactory(new Factory<RestContext>()
{
@Override
public RestContext provide()
{
return new RestContext();
}
// this will get called at the end of the request
// allowing you to close your request scoped object
@Override
public void dispose(RestContext instance)
{
instance.close();
}
}, RequestScoped.class).to(RestContext.class).in(RequestScoped.class);
}
});
}
}
然后你可以在你的资源中注入RestContext
,它将由你的过滤器设置所有信息。例如:
@Path("/my/path")
public class MyResource
{
private RestContext rc;
@Inject
public MyResource(RestContext rc)
{
this.rc = rc;
}
@POST
@Consumes(MediaType.APPLICATION_JSON)
public void upload(MyPostObj data)
{
// do stuff here, and rc is all set up
}
}
比起字段注入,我更喜欢构造函数注入,因为我认为这会让其他阅读代码的开发人员更明显地了解您的依赖关系。如果我的牙套风格惹恼了你,也很抱歉,我来自.NET的奇妙世界:)。