以下是一个完整的示例,可以帮助您入门。
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);
现在,您应该能够使用@TokenParam
注入Token
,以及您平常的实体主体(如果我们没有实现ValueFactoryProvider
,这是不可能的)。@POST
@Consumes(MediaType.APPLICATION_JSON)
public String postToken(@TokenParam Token token, User user) {
}
更新
对于您特定的用例来说,这只是半吊子示例。更好的方法可能是在您的Factory
类中拥有一个克隆方法,并使用一些参数(也许您可以从注释中获取)创建一个新的TokenFactory
。例如,在TokenFactory
中你可以有类似这样的内容:
public class TokenFactory extends AbstractContainerRequestValueFactory<Token> {
public TokenFactory clone(boolean someAttribute) {
return new TokenFactory(authenticator, someAttribute);
}
在TokenFactoryProvider
的createValueFactory
方法中,然后调用克隆方法。
TokenParam annotation = parameter.getAnnotation(TokenParam.class);
if (annotation != null && paramType.isAssignableFrom(Token.class)) {
return tokenFactory.clone(annotation.someAttribute());
}
或者你可以在方法内部实际上创建工厂。你有选择。
更新2
参见
@BeanParam
上,这就是为什么我需要ValueFactoryProvider
的原因吗?因为从InjectionResolver
周围的文档中,我得到了强烈的暗示,注入一个字段到BeanParam上就足够了,因为它是一个独立的对象。无论如何,感谢您的帮助,我将尝试使用Value Factory小部件。 - Patrick MValueFactoryProvider
。看起来InjectionResolver
还不够用。由于它似乎适用于方法参数,所以我认为它也可能适用于您的bean字段。我可能错了,但是尝试一下也无妨。 - Paul Samsotha