簡體   English   中英

Java Guice DI錯誤:UnsatisfiedDependencyException: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中注冊這些資源的實例。

鐵拳與HK2

要將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);

就是這樣。 正如我測試過的那樣,它應該可以工作。

與Guice綁定資源

通過以上配置,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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM