Java Guice DI error: UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(Java Guice DI 错误:UnsatisfiedDependencyException:SystemInjecteeImpl 处没有可用于注入的对象)
问题描述
我有一个使用 Jersey 2.x 的简单 REST API 项目.我尝试使用 Google Guice 注入我的依赖项,但它似乎不起作用.我收到此错误:
I have a simple REST API project using Jersey 2.x. I tried using Google Guice to inject my dependencies, but it doesn't seem to work. I get this error:
org.glassfish.hk2.api.UnsatisfiedDependencyException: SystemInjecteeImpl 没有可用于注入的对象(requiredType=AccountService,parent=AccountsResource,qualifiers={},position=0,optional=false,self=false,unqualified=空,1658198405)
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=AccountService,parent=AccountsResource,qualifiers={},position=0,optional=false,self=false,unqualified=null,1658198405)
我有这个简单的资源类
@Path("/accounts")
@Produces(MediaType.APPLICATION_JSON)
public class AccountsResource {
private final AccountService accountService;
@Inject
public AccountsResource(AccountService accountService) {
this.accountService = accountService;
}
@GET
@Path("test")
public String test() {
return this.accountService.test();
}
我想将此服务注入到我的资源类中
I want to inject this service into my resource class
public class AccountService {
public AccountService() {}
public String test() {
return "test";
}
}
所以,按照 Guice 的指南,我创建了这个模块类
So, following Guice's guide, I created this module class
import com.google.inject.*;
public class AccountsResourceModule extends AbstractModule {
@Override
protected void configure() {
bind(AccountService.class);
}
}
最后,我在 main 方法中添加了注入器
Finally, I added the injector in my main method
public class TradingServer implements Runnable {
private static final int PORT = 8181;
public static void main(String[] args) {
Injector injector = Guice.createInjector(new AccountsResourceModule());
AccountsResource accountsResource = injector.getInstance(AccountsResource.class);
new TradingServer().run();
}
public void run() {
Server server = new Server(PORT);
ServletContextHandler contextHandler = new ServletContextHandler(server, "/");
ResourceConfig packageConfig = new ResourceConfig().packages("ca.ulaval.glo4002.trading");
ServletContainer container = new ServletContainer(packageConfig);
ServletHolder servletHolder = new ServletHolder(container);
contextHandler.addServlet(servletHolder, "/*");
try {
server.start();
server.join();
} catch (Exception e) {
e.printStackTrace();
} finally {
server.destroy();
}
}
}
当我调用我的服务器时,我收到了上面提到的错误.似乎依赖注入不起作用.请帮忙
When I call my server, I get the error mentioned above. It seems like the dependency injection didn't work. Please help
推荐答案
所以 Jersey 对 Guice 一无所知.它已经使用了自己的 DI 框架 HK2.您可以做几件事.您可以将 Guice 与 HK2 绑定在一起,以便 HK2 可以找到绑定在 Guice 中的服务,或者另一种方法是将您的资源类绑定到 Guice 中,然后将这些资源的实例注册到 Jersey.
So Jersey knows nothing about Guice. It already uses it's own DI framework, HK2. There are a couple things you can do. You can either tie Guice together with HK2 so that HK2 can find services that are bound inside Guice, or another way is to just bind your resource classes inside Guice and and register instances of those resources with Jersey.
要将 Guice 与 HK2 绑定,您需要使用 Guice HK2 Bridge.首先需要添加如下依赖
To tie Guice with HK2, you need to use the Guice HK2 Bridge. First you need to add the following dependency
<dependency>
<groupId>org.glassfish.hk2</groupId>
<artifactId>guice-bridge</artifactId>
<version>${hk2.version}</version>
</dependency>
要获得 hk2.version
,请查看您的 Jersey 依赖项(您可以运行 mvn dependency:tree
并查看 HK2 Jersey 的哪个版本).您要确保使用的是完全相同的版本.
To get the hk2.version
look at your Jersey dependencies (you can run mvn dependency:tree
and see what version of HK2 Jersey is pulling in). You want to make sure you are using the exact same version.
接下来您需要做的是以编程方式链接这两个系统.一种方法是在 Feature
中.
Next thing you need to do is to programmatically link the two systems. One way to do this is inside a Feature
.
public class GuiceFeature implements Feature {
@Override
public boolean configure(FeatureContext context) {
// This is the way in Jersey 2.26+ to get the ServiceLocator.
// In earlier versions, use
// ServiceLocatorProvider.getServiceLocator(context);
ServiceLocator locator = InjectionManagerProvider.getInjectionManager(context)
.getInstance(ServiceLocator.class);
Injector injector = Guice.createInjector(new AccountResourceModule());
GuiceBridge.getGuiceBridge().initializeGuiceBridge(locator);
GuiceIntoHK2Bridge guiceBridge = locator.getService(GuiceIntoHK2Bridge.class);
guiceBridge.bridgeGuiceInjector(injector);
return true;
}
}
然后只需向 Jersey 注册该功能.
Then just register the feature with Jersey.
ResourceConfig packageConfig = new ResourceConfig()
.packages("ca.ulaval.glo4002.trading")
.register(GuiceFeature.class);
就是这样.正如我测试过的那样,它应该工作.
And that's it. It should work, as I have tested.
通过上述配置,Jersey 将创建资源类的实例(@Path
注释类).我们需要桥接的原因是 Jersey 与 HK2 紧密耦合,所以当我们注入资源类时,在创建实例时,Jersey 会调用 HK2 来尝试查找资源的所有依赖项.
With the above configuration, Jersey will be creating instances of your resource classes (@Path
annotated classes). The reason we need the bridge is that Jersey is tightly coupled with HK2, so when we inject our resources classes, when creating the instance, Jersey will call HK2 to try to find all the dependencies for the resource.
不过,在这种情况下,我们不会依赖 Jersey 来创建资源实例.我们将资源绑定到 Guice 并让 Guice 在我们请求时创建实例.我们将使用该实例向 Jersey 注册.
In this case though, we will not rely on Jersey to create the instance of the resource. We will bind the resource to Guice and let Guice create the instance when we request it. We will use that instance to register with Jersey.
先绑定资源
public class AccountResourceModule extends AbstractModule {
@Override
protected void configure() {
bind(AccountService.class);
bind(AccountResource.class);
}
}
还要确保资源类中的 @Inject
注释是 com.google.inject.Inject
.
Also make sure that the @Inject
annotation in the resource class is com.google.inject.Inject
.
获取资源实例并注册
Injector injector = Guice.createInjector(new AccountResourceModule());
AccountResource accountResource = injector.getInstance(AccountResource.class);
ResourceConfig config = new ResourceConfig()
.register(accountResource);
您可能必须想出一种更简洁的方法来执行此操作,因为您不希望对您拥有的每个资源都执行此操作.但这就是你需要做的事情的要点.
You probably have to figure out a cleaner way to do this as you don't want to have to do this for every resource you have. But this is the gist if what you need to do.
所以这里有一个清理第二个解决方案的快速实现.我们可以做的是递归扫描一个包以获取所有 @Path
注释的类,然后将它们绑定到 Guice 并注册到 Jersey.
So here's a quick implementation to clean up the second solution. What we can do is scan a package recursively to get all the @Path
annotated classes and then bind them in Guice and register them with Jersey.
从这篇 SO 帖子,我们可以使用 Reflections 库轻松获取所有类.只需添加以下依赖项
From this SO post, we can use the Reflections library to easily get all the classes. Just add the following dependency
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.11</version>
</dependency>
然后做一个小助手类
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.Path;
import org.reflections.Reflections;
public class ResourceClassHelper {
private static Set<Class<?>> resourceClasses;
public static Set<Class<?>> getResourceClasses() {
if (resourceClasses != null) {
return resourceClasses;
}
// the package to scan for @Path classes "com.example"
Reflections reflections = new Reflections("com.example");
resourceClasses = reflections.getTypesAnnotatedWith(Path.class);
resourceClasses = Collections.unmodifiableSet(resourceClasses);
return resourceClasses;
}
}
然后在你的 Guice 模块中
Then in your Guice module
public class AccountResourceModule extends AbstractModule {
@Override
protected void configure() {
bind(AccountService.class);
ResourceClassHelper.getResourceClasses().forEach(this::bind);
}
}
还有你的资源注册
Injector injector = Guice.createInjector(new AccountResourceModule());
ResourceConfig config = new ResourceConfig();
ResourceClassHelper.getResourceClasses()
.forEach(cls -> config.register(injector.getInstance(cls)));
这篇关于Java Guice DI 错误:UnsatisfiedDependencyException:SystemInjecteeImpl 处没有可用于注入的对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:Java Guice DI 错误:UnsatisfiedDependencyException:SystemInjecteeImpl 处没有可用于注入的对象
基础教程推荐
- 在 Libgdx 中处理屏幕的正确方法 2022-01-01
- “未找到匹配项"使用 matcher 的 group 方法时 2022-01-01
- Java:带有char数组的println给出乱码 2022-01-01
- 减少 JVM 暂停时间 >1 秒使用 UseConcMarkSweepGC 2022-01-01
- 无法使用修饰符“public final"访问 java.util.Ha 2022-01-01
- 如何使用 Java 创建 X509 证书? 2022-01-01
- 设置 bean 时出现 Nullpointerexception 2022-01-01
- 降序排序:Java Map 2022-01-01
- Java Keytool 导入证书后出错,"keytool error: java.io.FileNotFoundException &拒绝访问" 2022-01-01
- FirebaseListAdapter 不推送聊天应用程序的单个项目 - Firebase-Ui 3.1 2022-01-01