我正在从DropWizard 0.7.1迁移到0.8.1。这包括从Jersey 1.x迁移到2.x.在我的
使用Jersey 1.18.1的实现,我有一个MyProvider
(为了简单起见改变了所有类名),它实现了InjectableProvider
。这个
class将创建MyInjectable
个对象,其中包含自定义注入注释MyToken
。 MyToken
包含各种属性
由MyInjectable
传递和阅读的内容。最后,在Application
类中,我注册了MyProvider
的新实例,如下所示。
我做过一些研究,似乎无法重温我在泽西岛2.x中如何重建(或替代,我认为)这样一个场景。
这是当前的1.18.1实施:
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.PARAMETER, ElementType.FIELD })
public @interface MyToken {
// Custom annotation containing various attributes
boolean someAttribute() default true;
// ...
}
public class MyProvider implements InjectableProvider<MyToken, Parameter> {
// io.dropwizard.auth.Authenticator
private final Authenticator<String, MyObject> authenticator;
public MyProvider(Authenticator<String, MyObject> authenticator) {
this.authenticator = authenticator;
}
@Override
public ComponentScope getScope() {
return ComponentScope.PerRequest;
}
@Override
public Injectable<?> getInjectable(ComponentContext ic, MyToken t, Parameter p) {
return new MyInjectable(authenticator, t.someAttribute());
}
}
class MyInjectable extends AbstractHttpContextInjectable<MyObject> {
private final Authenticator<String, Session> authenticator;
private final boolean someAttribute;
public MyInjectable(Authenticator<String, MyObject> authenticator, boolean someAttribute) {
this.authenticator = authenticator;
this.someAttribute = someAttribute;
// ... Removed a few paramters for simplicity's sake
}
@Override
public MyObject getValue(HttpContext c) {
final HttpRequestContext request = c.getRequest();
// ... Removed code not pertaining to the question
return myObject;
}
}
// Lastly, the register call in the io.dropwizard.Application class
environment.jersey().register(new MyProvider(new MyProviderValidator(someValidator)));
答案 0 :(得分:23)
是的,泽西岛在2.x中创造了更复杂的定制注射。使用Jersey 2.x
,您需要了解自定义注入的几个主要组件org.glassfish.hk2.api.Factory
- 创建可注入的对象/服务org.glassfish.hk2.api.InjectionResolver
- 用于为您自己的注释创建注入点。org.glassfish.jersey.server.spi.internal.ValueFactoryProvider
- 提供参数值注入。您可以在Custom Injection and Lifecycle Management中详细了解自定义注入。文档的一个缺点是缺乏如何注入参数值的解释。您可以简单地实现InjectResolver
,并且可以使用自定义注释注入字段,但为了注入方法参数,我们需要ValueFactoryProvider
。
幸运的是,我们可以扩展一些抽象类(文档也没有提及),这将使生活变得更容易。我必须搜索source code of the org.glassfish.jersey.server.internal.inject
package一点,试着把它全部弄清楚。
以下是帮助您入门的完整示例。
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
。我们可以访问{ {1}}。注意,所有这些HK2组件,我们可以将其他依赖项注入其中,例如ContainerRequestContext
,稍后我们将绑定到HK2。
TokenAuthenticator
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");
}
}
(每个项目符号第2点实现TokenParamInjectionResolver
。我只是扩展InjectResolver
。如果您对在{2}下发生的事情感兴趣引擎盖,你可以在我链接的源代码中找到该类)
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
,但是如果你常用的Dropwizard TokenAuthentictor
。我还使用了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);
注入Token
以及你常用的实体(如果我们没有实现@TokenParam
那就不可能
ValueFactoryProvider
它是您的特定用例的一半 - @ $$示例。一个更好的方法可能在你的@POST
@Consumes(MediaType.APPLICATION_JSON)
public String postToken(@TokenParam Token token, User user) {
}
类中有一个克隆方法并创建一个带有一些参数的新Factory
(也许你可以从你的注释TokenFactory
TokenFactory获得你可以有类似< / p>
. For example, in the
在public class TokenFactory extends AbstractContainerRequestValueFactory<Token> {
public TokenFactory clone(boolean someAttribute) {
return new TokenFactory(authenticator, someAttribute);
}
ine TokenFactoryProvider
方法中,然后调用克隆方法
createValueFactory
或者您实际上可以在方法中创建工厂。你有选择。
另见