将GuiceServletContextListener连接到现有的注入器

时间:2016-09-12 12:10:07

标签: java jersey jetty guice swagger

我有一个已经使用Guice的大型现有java程序。我试图添加一个带有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);

其中Bindings看起来像

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

1 个答案:

答案 0 :(得分:1)

我仔细查看了您的代码,以下是您如何使用它:

将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桥接器添加到您的配置中。现在,您需要将其连接起来。为此,我们将创建一个功能,如本文所述:

Guice don't inject to Jersey's resources

@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;
    }

}

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

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

EmbeddedWeb#buildApiContext:

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

同样,我们使用您已创建的相同注射器。

最后,这就是您需要的一切,并且您的服务正确连线。

试验:

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

希望有所帮助,

阿图尔

编辑&#39;&#39;重要事项&#39;&#39;:

对于注射,您不能使用guice注释。泽西岛似乎没有认识到它们(可能是因为他们不想添加guice依赖项)。幸运的是,guice可以同时使用javax和guice注释。因此,在TestSwaggerBad类中,您还需要将导入更改为标准javax注释。