是的Jersey在2.x中使自定义注入的创建更加复杂。对于Jersey 2.x,您需要了解一些自定义注入的主要组件。
org.glassfish.hk2.api.Factory
-创建可注射对象/服务org.glassfish.hk2.api.InjectionResolver
-用于为自己的注释创建注入点。org.glassfish.jersey.server.spi.internal.ValueFactoryProvider
-提供参数值注入。
您可以在“
定制注入和生命周期管理”中阅读有关定制注入的更多信息。该文档的一个缺点是缺乏对如何注入参数值的解释。您可以通过简单地实现来摆脱困境
InjectResolver,并且可以使用自定义注释将其注入字段,但是为了注入方法参数,我们需要
ValueFactoryProvider。
幸运的是,我们可以扩展一些抽象类(文档中也没有提到),这些抽象类会使生活变得更轻松。我必须搜索软件包的源代码,
org.glassfish.jersey.server.internal.inject以尝试找出所有问题。
这是一个完整的示例,可帮助您入门。
Token
(注射物)
public class Token { private final String token; public Token(String token) { this.token = token; } public String getToken() { return token; }}@TokenParam
(我们的注解注解)
@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.PARAMETER, ElementType.FIELD})public @interface TokenParam { boolean someAttribute() default true;}TokenFactory
(
Factory每个第一个项目点的实现,但我们只需要扩展
AbstractContainerRequestValueFactory。即可
ContainerRequestContext。。请注意,所有这些HK2组件,我们都可以向其中注入其他依赖项,例如
TokenAuthenticator,稍后我们将其绑定到HK2
。
import javax.inject.Inject;import javax.ws.rs.WebApplicationException;import javax.ws.rs.core.HttpHeaders;import javax.ws.rs.core.Response;import org.glassfish.jersey.server.internal.inject.AbstractContainerRequestValueFactory;public class TokenFactory extends AbstractContainerRequestValueFactory<Token> { private final TokenAuthenticator tokenAuthenticator; @Inject public TokenFactory(TokenAuthenticator tokenAuthenticator) { this.tokenAuthenticator = tokenAuthenticator; } @Override public Token provide() { String auth = getContainerRequest().getHeaderString(HttpHeaders.AUTHORIZATION); try { if (tokenAuthenticator.authenticate(auth).get() == null) { throw new WebApplicationException(Response.Status.FORBIDDEN); } } catch (AuthenticationException ex) { Logger.getLogger(TokenFactory.class.getName()).log(Level.SEVERE, null, ex); } return new Token("New Token"); } }TokenParamInjectionResolver
(实现
InjectResolver每个要点两个。我简单地扩展
ParamInjectionResolver一下。如果您对引擎盖下发生的事情感兴趣,则可以在我链接到的源代码中找到该类)
import org.glassfish.jersey.server.internal.inject.ParamInjectionResolver;public class TokenParamInjectionResolver extends ParamInjectionResolver { public TokenParamInjectionResolver() { super(TokenFactoryProvider.class); }}TokenFactoryProvider
(实现
ValueFactoryProvider第三个要点。我只是扩展
AbstractValueFactoryProvider一下。再次,您可以查看引擎盖下信息的来源)
import javax.inject.Inject;import org.glassfish.hk2.api.Factory;import org.glassfish.hk2.api.ServiceLocator;import org.glassfish.jersey.server.internal.inject.AbstractValueFactoryProvider;import org.glassfish.jersey.server.internal.inject.MultivaluedParameterExtractorProvider;import org.glassfish.jersey.server.model.Parameter;public class TokenFactoryProvider extends AbstractValueFactoryProvider { private final TokenFactory tokenFactory; @Inject public TokenFactoryProvider( final MultivaluedParameterExtractorProvider extractorProvider, ServiceLocator locator, TokenFactory tokenFactory) { super(extractorProvider, locator, Parameter.Source.UNKNOWN); this.tokenFactory = tokenFactory; } @Override protected Factory<?> createvalueFactory(Parameter parameter) { Class<?> paramType = parameter.getRawType(); TokenParam annotation = parameter.getAnnotation(TokenParam.class); if (annotation != null && paramType.isAssignableFrom(Token.class)) { return tokenFactory; } return null; }}TokenFeature
(在这里,我们绑定了上面看到的所有组件,甚至包括了
TokenAuthentictor我遗漏的组件,但是如果您通常使用Dropwizard的话
Authenticator。我还使用了
Feature。我倾向于这样做来包装自定义功能的组件。在这里,您也可以使用可以决定所有范围(只需注意某些组件必须在
Singleton范围内)
import javax.inject.Singleton;import javax.ws.rs.core.Feature;import javax.ws.rs.core.FeatureContext;import org.glassfish.hk2.api.InjectionResolver;import org.glassfish.hk2.api.TypeLiteral;import org.glassfish.hk2.utilities.binding.AbstractBinder;import org.glassfish.jersey.server.spi.internal.ValueFactoryProvider;public class TokenFeature implements Feature { @Override public boolean configure(FeatureContext context) { context.register(new AbstractBinder(){ @Override public void configure() { bind(TokenAuthenticator.class) .to(TokenAuthenticator.class) .in(Singleton.class); bind(TokenFactory.class).to(TokenFactory.class) .in(Singleton.class); bind(TokenFactoryProvider.class) .to(ValueFactoryProvider.class) .in(Singleton.class); bind(TokenParamInjectionResolver.class) .to(new TypeLiteral<InjectionResolver<TokenParam>>(){}) .in(Singleton.class); } }); return true; } }最后,只需注册功能
register(TokenFeature.class);
现在,您应该能够注入
Tokenwith
@TokenParam以及您通常的实体主体(如果我们未实现的话,这是不可能的)
ValueFactoryProvider
@POST@Consumes(MediaType.APPLICATION_JSON)public String postToken(@TokenParam Token token, User user) {}更新
对于您的特定用例来说,这是一个一半@
$$$的示例。更好的方法可能是在
Factory类中使用clone方法并
TokenFactory使用一些参数创建一个新方法(也许是从注释
. Forexample, in theTokenFactory中获得的,
public class TokenFactory extends AbstractContainerRequestValueFactory<Token> { public TokenFactory clone(boolean someAttribute) { return new TokenFactory(authenticator, someAttribute); }然后在
TokenFactoryProviderine
createvalueFactory方法中,调用clone方法
TokenParam annotation = parameter.getAnnotation(TokenParam.class);if (annotation != null && paramType.isAssignableFrom(Token.class)) { return tokenFactory.clone(annotation.someAttribute());}或者,您实际上 可以 在方法内部 创建 工厂。你有选择。



