将 GuiceServletContextListener 连接到现有的注入器

wiring up GuiceServletContextListener to an existing injector

我有一个现有的大型 java 程序已经在使用 Guice。我正在尝试添加一个带有 swagger 文档的嵌入式网站。我需要以某种方式将它与 Guice 连接起来,但是当我尝试使用我在主程序中注入的东西时,我尝试的一切都会抛出空指针异常。我想也许我可以通过注射器并以这种方式连接它,使用注射器或创建子注射器。

我已经创建了一个示例应用程序,仅使用使其正常工作所需的代码,其中一个 URL 可以正常工作但不会尝试使用我的主程序中的注入,而另一个确实可以尝试使用注入无效。

我正在尝试做所有这些而不需要 web.xml 通过:

    private ContextHandler buildApiContext() {

    ResourceConfig resourceConfig = new ResourceConfig();
    // Replace EntityBrowser with your resource class
    // io.swagger.jaxrs.listing loads up Swagger resources
    resourceConfig.packages("web", ApiListingResource.class.getPackage().getName());

    //apiServletContainer.reload(resourceConfig);
    ServletContainer apiServletContainer = new ServletContainer(resourceConfig);

    final ServletContextHandler apiContext = new ServletContextHandler(ServletContextHandler.SESSIONS);
    apiContext.setContextPath("/api");      
    ServletHolder apiBrowser = new ServletHolder(apiServletContainer);
    apiContext.addFilter(GuiceFilter.class, "/*", EnumSet.allOf(DispatcherType.class));
    myGuiceServletContextListener.setMainInjector(blackboard.getMainInjector());
    apiContext.addEventListener(myGuiceServletContextListener);
    apiContext.addServlet(apiBrowser, "/*");        
    return apiContext;
}

public class MyGuiceServletContextListener extends GuiceServletContextListener {

    @Inject private Blackboard blackboard;  
    @Override
    protected Injector getInjector() {
        return blackboard.getMainInjector();
    }}

我也试过:

return blackboard.getMainInjector().createChildInjector();

在我的主程序中,我开始主程序注入:

Config config = ReadConfig.createConfig();
Injector injector = Guice.createInjector(new Bindings(config));
BigProgramInterface bbInterface = injector.getInstance(BigProgramImpl.class);
bbInterface.start(injector);

绑定看起来像

public class Bindings implements Module {

private Config config;

public Bindings(Config config) {
    this.config = config;
}

public void configure(Binder binder) {

    Integer fixedThreadPoolSize = 2;
    Executor fixedExecutor = Executors.newFixedThreadPool(fixedThreadPoolSize, new FixedThreadFactory());
    binder.bind(Executor.class).toInstance(fixedExecutor);

    binder.bind(Config.class).toInstance(config);
    binder.bind(Blackboard.class).asEagerSingleton();
    binder.bind(BigProgramMain.class).asEagerSingleton();
    binder.bind(EmbeddedWeb.class).asEagerSingleton();
    //binder.bind(MyGuiceServletContextListener.class).asEagerSingleton();
}

黑板注入了,正在获取主注入器,但是不能使用

作品:

@Path("/test")
@Api (value = "/test")
public class TestSwagger {

private static final Logger log = LoggerFactory.getLogger(TestSwagger.class);
@GET
@Path("/get")
@ApiOperation(value = "a working test", 
    notes = "Returns my test class", 
    response = MyTest.class, 
    responseContainer="Class")
@Produces(MediaType.APPLICATION_JSON)
public Response getResult() {
    MyTest myTest = new MyTest();
    myTest.setMyTestString("this is a test");
    return Response.ok().entity(myTest).build();    
}}

不工作:

@Path("/testbad")
@Api (value = "/testbad")
public class TestSwaggerBad {

private static final Logger log = LoggerFactory.getLogger(TestSwaggerBad.class);
@Inject private Blackboard blackboard;
@GET
@Path("/get")
@ApiOperation(value = "a non - working test", 
    notes = "Returns my test class", 
    response = MyTest.class, 
    responseContainer="Class")
@Produces(MediaType.APPLICATION_JSON)
public Response getResult() {
    MyTest myTest = new MyTest();
    myTest.setMyTestString(blackboard.getBigProgramCounter().toString());
    return Response.ok().entity(myTest).build();    
}}

请查看我的代码以了解具体细节: https://github.com/phomlish/SwaggerSampleApiWebsite

我仔细查看了您的代码,下面是您如何让它工作:

将 guice 桥添加到您的 pom:

<!-- https://mvnrepository.com/artifact/org.glassfish.hk2/guice-bridge -->
<dependency>
    <groupId>org.glassfish.hk2</groupId>
    <artifactId>guice-bridge</artifactId>
    <version>2.5.0-b15</version>
</dependency>

这会将 guice hk2 网桥添加到您的配置中。现在,您需要将其连接起来。为此,我们将创建一个 post 概述的功能:

@Priority(0)
public class GuiceFeature implements Feature {

    private Injector i;

    public GuiceFeature(Injector i) {
        this.i = i;
    }

    @Override
    public boolean configure(FeatureContext context) {
        ServiceLocator locator = ServiceLocatorProvider.getServiceLocator(context);

        GuiceBridge.getGuiceBridge().initializeGuiceBridge(locator);
        GuiceIntoHK2Bridge guiceBridge = locator.getService(GuiceIntoHK2Bridge.class);
        guiceBridge.bridgeGuiceInjector(i);

        return true;
    }

}

请注意,我将您创建的注入器传递给该功能。这很重要,因为您将需要相同的注射器才能找到您的服务。绑定代码相当简单。

最后,您需要注册该功能。在您的 class EmbeddedWeb 中,您添加:

嵌入式网络#buildApiContext:

resourceConfig.register(new GuiceFeature(myGuiceServletContextListener.getInjector()));

同样,我们使用的是您已经创建的同一个注入器。

最后这就是您所需要的,并且您的服务已正确连接。

测试:

artur@pandaadb:~/dev/repo/SwaggerSampleApiWebsite$ curl "http://localhost:8080/api/testbad/get"
{"myTestString":"10"}

希望对您有所帮助,

阿图尔

编辑'''IMPORTANT''':

对于注入,不能使用guice注解。 Jersey 似乎无法识别它们(可能是因为它们不想添加 guice 依赖项)。幸运的是,guice 可以同时使用 javax 和 guice 注释。因此,在您的 TestSwaggerBad class 中,您还需要将导入更改为标准 javax 注释。