如何使 Jersey 与 Dagger 依赖注入一起工作?
Jersey 通常使用 HK2 依赖注入,但我想将 Jersey 与 Dagger 2 一起使用.Dagger 和 HK2 都实现了 JSR 330,我已将其作为证据,证明这应该可以不费力气.我找到了让 Jersey 与 CDI(例如 Weld)、Spring DI 和 Guice 一起工作的方法,但我在 Dagger 上找不到任何东西.
Jersey normally uses HK2 dependency injection, but I would like to use Jersey with Dagger 2. Both Dagger and HK2 implement JSR 330, which I have taken as evidence that this should be possible without too much effort. I found ways to make Jersey work with CDI (e.g. Weld), Spring DI and Guice, but I can't find anything on Dagger.
提供一些上下文:我在 SE 环境中运行 Grizzly–Jersey 服务器,而不是在 EE 容器中.我的 Maven 项目有 com.google.dagger:dagger
和 org.glassfish.jersey.containers:jersey-container-grizzly2-http
作为依赖项,但不是 org.glassfish.jersey.inject:jersey-hk2
,因为我想用 Dagger 替换 HK2.
To provide some context: I'm running a Grizzly–Jersey server in an SE environment, not in an EE container. My Maven project has com.google.dagger:dagger
and org.glassfish.jersey.containers:jersey-container-grizzly2-http
as dependencies, but not org.glassfish.jersey.inject:jersey-hk2
, since I want to replace HK2 with Dagger.
资源类如下所示:
@Path("/example")
public final class ExampleResource {
private final Dependency dependency;
@Inject
public ExampleResource(final Dependency dependency) {
this.dependency = Objects.requireNonNull(dependency);
}
@GET
@Produces(MediaType.APPLICATION_JSON)
public Example getExample() {
return this.dependency.giveExample();
}
}
Dagger 组件可以例如定义如下:
And the Dagger component could e.g. be defined as follows:
@Component
public interface Application {
public ExampleResource exampleEndpoint();
public XyzResource xyzEndpoint();
// etc.
}
所以 main 方法看起来类似于:
So that the main method would look similar to:
public final class Main {
public static void main(final String[] args) {
final Application application = DaggerApplication.create();
final URI baseUri = UriBuilder.fromUri("http://0.0.0.0/").port(80).build();
final ResourceConfig resourceConfig = new ResourceConfig();
// how to initialize `resourceConfig` using `application`?
final HttpServer httpServer = GrizzlyHttpServerFactory
.createHttpServer(baseUri, resourceConfig, false);
try {
httpServer.start();
} catch (final IOException ex) {
...
}
}
}
立即运行应用程序导致异常:IllegalStateException: InjectionManagerFactory not found.
看来需要这个工厂的Dagger实现.
Running the application immediately results in an exception: IllegalStateException: InjectionManagerFactory not found.
It seems that a Dagger implementation of this factory is needed.
我的问题是:如何将 Dagger 与 Jersey 集成?
推荐答案
你不应该认为它是如何将匕首与球衣结合起来".弄清楚如何设置球衣,然后一旦弄清楚了,就可以担心使用匕首了.
You shouldn't think of it as "how to integrate dagger with jersey". Figure out how to setup jersey, then once you have that figured out, then you can worry about using dagger.
这是(非常粗略地)我会怎么做.
Here's (very roughly) how I would do it.
创建您自己的 ResourceConfig 类实现.
Create your own implementation of the ResourceConfig class.
@ApplicationPath("/service")
public class MyResourceConfig extends ResourceConfig {
@Inject
public MyResourceConfig(
@Nonnull final ExampleResource exampleResource) {
this.register(exampleResource);
}
}
然后创建一个模块来设置创建 HttpServer 所需的一切
Then create a module that sets up everything you need to create an HttpServer
@Module
public class MyServiceModule {
@Provides
@Singleton
@Named("applicationPort")
public Integer applicationPort() {
return 80;
}
@Provides
@Singleton
@Named("applicationBaseUri")
public URI baseUri(
@Named("applicationPort") @Nonnull final Integer applicationPort) {
return UriBuilder.fromUri("http://0.0.0.0/").port(applicationPort).build();
};
@Provides
@Singleton
public HttpServer httpServer(
@Named("applicationBaseUri") @Nonnull final URI applicationBaseUri,
@Nonnull final MyResourceConfig myResourceConfig) {
return GrizzlyHttpServerFactory
.createHttpServer(applicationBaseUri, myResourceConfig, false);
}
}
然后创建公开 HttpServer 的组件.我通常喜欢制作尽可能少暴露的组件.在这种情况下,您只需要公开 HttpServer.
Then create your component that exposes the HttpServer. I typically like to make components that expose as little as possible. In this case, all you need to expose is the HttpServer.
@Singleton
@Component(modules = { MyServiceModule.class })
protected interface ServiceComponent {
HttpServer httpServer();
@Component.Builder
interface Builder {
// Bind any parameters here...
ServiceComponent build();
}
}
然后继续构建您的组件,并启动您的 HttpServer
Then just go ahead and build your component, and start your HttpServer
public static void main(String[] args) {
final ServiceComponent component = DaggerServiceComponent.builder().build()
try {
component.httpServer().start();
} catch (Exception ex) {
// handle exception...
}
}
还有一点需要注意.我个人从不使用 @Named("") 注释.我更喜欢使用限定符.因此,您创建了一个具有唯一值的限定符注释.然后你可以注入类似的东西
One more thing to note. I personally do not ever use the @Named("") annotation. I prefer to use a Qualifier. So you create a Qualifier annotation with a unique value. Then you can inject things like
@Provides
@Singleton
@MyUniqueQualifier
public String myUniqueQualifierProviderValue() {
return "something";
}
然后在注入的时候
@Inject
public SomeClass(@MyUniqueQualifier @Nonnull final String myUniqueQualifiedValue)
如果您使用 @Named 注释,您将不会在编译时检查冲突或缺失值.您会在运行时发现未注入值或名称与其他内容冲突.它很快就会变得混乱.
If you use the @Named annotation you don't get compile time checks for conflicts or missing values. You would find out at run time that a value was not injected or then name conflicts with something else. It gets messy quick.
相关文章