![](/img/trans.png)
[英]UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl
[英]Java Guice DI error: UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl
我有一個使用Jersey 2.x的簡單REST API項目。 我嘗試使用Google Guice注入依賴項,但似乎不起作用。 我收到此錯誤:
org.glassfish.hk2.api.UnsatisfiedDependencyException: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();
}
我想將此服務注入我的資源類
public class AccountService {
public AccountService() {}
public String test() {
return "test";
}
}
因此,按照Guice的指南,我創建了這個模塊類
import com.google.inject.*;
public class AccountsResourceModule extends AbstractModule {
@Override
protected void configure() {
bind(AccountService.class);
}
}
最后,我在主要方法中添加了進樣器
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();
}
}
}
呼叫服務器時,出現上述錯誤。 似乎依賴項注入無效。 請幫忙
所以澤西島對吉斯一無所知。 它已經使用了自己的DI框架HK2。 您可以做幾件事。 您可以將Guice與HK2綁定在一起,以便HK2可以找到綁定在Guice內的服務,或者另一種方法是只將您的資源類綁定在Guice內,然后在Jersey中注冊這些資源的實例。
要將Guice與HK2綁在一起,您需要使用Guice HK2 Bridge 。 首先,您需要添加以下依賴項
<dependency>
<groupId>org.glassfish.hk2</groupId>
<artifactId>guice-bridge</artifactId>
<version>${hk2.version}</version>
</dependency>
要獲取hk2.version
查看您的Jersey依賴項(您可以運行hk2.version
mvn dependency:tree
並查看hk2.version
的HK2 Jersey版本)。 您要確保使用的是完全相同的版本。
接下來,您需要以編程方式鏈接兩個系統。 一種實現方法是在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注冊功能即可。
ResourceConfig packageConfig = new ResourceConfig()
.packages("ca.ulaval.glo4002.trading")
.register(GuiceFeature.class);
就是這樣。 正如我測試過的那樣,它應該可以工作。
通過以上配置,Jersey將創建資源類的實例(帶@Path
注釋的類)。 我們需要橋接的原因是Jersey與HK2緊密耦合,因此,當我們注入資源類時,在創建實例時,Jersey將調用HK2嘗試查找該資源的所有依賴關系。
但是,在這種情況下,我們將不依賴Jersey來創建資源實例。 我們將資源綁定到Guice,並在請求時讓Guice創建實例。 我們將使用該實例向Jersey進行注冊。
首先綁定資源
public class AccountResourceModule extends AbstractModule {
@Override
protected void configure() {
bind(AccountService.class);
bind(AccountResource.class);
}
}
還要確保資源類中的@Inject
批注是com.google.inject.Inject
。
獲取資源實例並注冊
Injector injector = Guice.createInjector(new AccountResourceModule());
AccountResource accountResource = injector.getInstance(AccountResource.class);
ResourceConfig config = new ResourceConfig()
.register(accountResource);
您可能需要找出一種更干凈的方法來執行此操作,因為您不必為擁有的每個資源都執行此操作。 但是,這是您需要做什么的要點。
因此,這里有一個快速實施方案來清理第二個解決方案。 我們可以做的是遞歸地掃描程序包,以獲取所有帶@Path
注釋的類,然后將它們綁定到Guice中並向Jersey注冊。
從這篇SO文章中 ,我們可以使用Reflections庫輕松獲取所有類。 只需添加以下依賴項
<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模塊中
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)));
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.