java - Jersey Web 应用程序动态注册资源

标签 java web-services maven tomcat

我有一个 Web 应用程序,它将从 jar 文件动态加载其资源。

我开始使用org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory.createHttpServer设置我自己的服务器并通过 ServiceLoader 加载所有资源并通过 ResourceConfig#register 注册了他们.这工作得很好,但我总是有第二台服务器在运行。

现在我想创建一个简单的应用程序 war 并将其部署在例如 Tomcat 。这个想法是,当加载 war 时,资源也通过 ServiceLoader 加载。然后可用(与独立服务器相同)。

我必须如何重写加载和注册资源以及启动服务器的主类,以便它在 Web 应用程序中运行?

我目前有一个 javax.ws.rs.core.Application定义,在标有 @PostConstruct 的方法中加载资源。虽然这是可行的,但它会根据每个请求进行初始化。

我尝试添加 javax.inject.Singleton到应用程序,但这导致了错误:

java.lang.IllegalStateException: Unable to perform operation: post construct on com.test.server.IntegrationServer
at org.jvnet.hk2.internal.ClazzCreator.create(ClazzCreator.java:392)
at org.jvnet.hk2.internal.SystemDescriptor.create(SystemDescriptor.java:471)
at org.jvnet.hk2.internal.SingletonContext$1.compute(SingletonContext.java:83)
at org.jvnet.hk2.internal.SingletonContext$1.compute(SingletonContext.java:71)
at org.glassfish.hk2.utilities.cache.Cache$OriginThreadAwareFuture$1.call(Cache.java:97)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at org.glassfish.hk2.utilities.cache.Cache$OriginThreadAwareFuture.run(Cache.java:154)
at org.glassfish.hk2.utilities.cache.Cache.compute(Cache.java:199)
at org.jvnet.hk2.internal.SingletonContext.findOrCreate(SingletonContext.java:122)
at org.jvnet.hk2.internal.Utilities.createService(Utilities.java:2020)
at org.jvnet.hk2.internal.ServiceLocatorImpl.internalGetService(ServiceLocatorImpl.java:766)
at org.jvnet.hk2.internal.ServiceLocatorImpl.getService(ServiceLocatorImpl.java:705)
at org.glassfish.jersey.server.ApplicationHandler.createApplication(ApplicationHandler.java:385)
at org.glassfish.jersey.server.ApplicationHandler.<init>(ApplicationHandler.java:342)
at org.glassfish.jersey.servlet.WebComponent.<init>(WebComponent.java:392)
at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:177)
at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:369)
at javax.servlet.GenericServlet.init(GenericServlet.java:158)

我的方法完全错误吗?或者我如何创建这样一个系统,作为可部署的 war 运行?

* 编辑 *

通过使用 ServletContextListener,我可以解决多个 init 调用,但我的资源没有加载。

所以,我有这样的资源

@Path("test")

公共(public)类 TestResource 实现 MarkerInterface { @得到 @Produces(MediaType.TEXT_PLAIN) @Path("得到") 公共(public)字符串获取(){ 返回“你好”; } } 此资源打包在一个 jar 文件中,位于文件系统中。

应用程序现在加载此文件位置并通过 ServiceLoader 加载所有MarkerInterface类并应注册它们。

我有

@WebListener
public class IntegrationServer extends ResourceConfig implements ServletContextListener {

@Override
public void contextInitialized(ServletContextEvent sce) {
    LOGGER.info(() -> "CONTEXT INIT");
    try {
        register(JacksonFeature.class);
        // wrapper for the ServiceLoader implementation
        this.serviceLoader = new IntegrationServiceLoader();
       this.serviceLoader.loadIntegrations(MarkerInterface.class, gce -> {
            LOGGER.info(() -> "Adding " + gce.getClass() + " to Server");
            register(gce.getClass());
        });
    }
    catch (IOException e) {
        LOGGER.log(Level.SEVERE, e, () -> "Failed to init integration server");
    }
}

我在日志中看到注册输出,将其部署为 server.war在 tomcat 上,但是当我调用 http://localhost:8080/server/test/get我收到 HTTP 状态 404 - 未找到。

我的 web.xml 看起来像

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<servlet>
    <servlet-name>Jersey Web Application</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>Jersey Web Application</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>

** 编辑 2***

有关此讨论,请参阅 Cássio Mazzochi Molin 的回答。

我使用构建器注册我的资源并打印出来

Builder{names=[com.test.server.TestResource], path='backend', methodBuilders=[], childResourceBuilders=[Builder{names=[[unnamed]], path='info', methodBuilders=[org.glassfish.jersey.server.model.ResourceMethod$Builder@819f71f], childResourceBuilders=[], childResources=[], resourceMethods=[], subResourceLocator=null, handlerClasses=[], handlerInstances=[], parentResource=Builder{names=[com.cetrea.qa.server.TestResource], path='backend'}, extended=false}], childResources=[Resource{"achievements", 3 child resources, 0 resource methods, 0 sub-resource locator, 1 method handler classes, 0 method handler instances},

这是其中的一部分。 TestResource 有一个方法 info , 所以我可以调用 http://localhost:8080/server/backend/info并得到正确的结果。 资源achievements来自一个插件,例如一个all方法,所以我尝试了http://localhost:8080/server/backend/achievements/all (也没有 backend 部分),但这又给出了 404

最佳答案

Jersey 提供了一个用于以编程方式构建资源的 API。

根据documentation , Resource类是编程资源建模 API 的主要入口点,它提供了以编程方式扩展现有 JAX-RS 注释资源类或构建可由 Jersey 运行时使用的新资源模型的能力。

查看文档提供的示例:

@Path("hello")
public class HelloResource {

     @GET
     @Produces("text/plain")
     public String sayHello() {
         return "Hello!";
     }
}
// Register the annotated resource.
ResourceConfig resourceConfig = new ResourceConfig(HelloResource.class);

// Add new "hello2" resource using the annotated resource class
// and overriding the resource path.
Resource.Builder resourceBuilder =
        Resource.builder(HelloResource.class, new LinkedList<ResourceModelIssue>())
        .path("hello2");

// Add a new (virtual) sub-resource method to the "hello2" resource.
resourceBuilder.addChildResource("world").addMethod("GET")
        .produces("text/plain")
        .handledBy(new Inflector<Request, String>() {
                @Override
                public String apply(Request request) {
                    return "Hello World!";
                }
        });

// Register the new programmatic resource in the application's configuration.
resourceConfig.registerResources(resourceBuilder.build());

下表说明了上面示例中配置的应用程序支持的请求和提供的响应:

 Request              |  Response        |  Method invoked
----------------------+------------------+--------------------------
 GET /hello           | "Hello!"         | HelloResource.sayHello()
 GET /hello2          | "Hello!"         | HelloResource.sayHello()
 GET /hello2/world    | "Hello World!"   | Inflector.apply()

有关更多详细信息,请查看 Jersey documentation .

关于java - Jersey Web 应用程序动态注册资源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39697138/

相关文章:

java - 如何使连拍模式可用于相机

java - Spring MVC - 在 DispatcherServlet 中未找到带有 URI [/demo/test] 且名称为 'appServlet' 的 HTTP 请求的映射

web-services - 如何修复错误 'input Web Services Description Language (WSDL) file is not valid' ?

performance - 将数据库放在专用服务器上时性能会变差吗?

Java UncaughtExceptionHandler + LOG4J + Maven

Java docker 与 jar 加载 main

java - Sonarqube - 在插件中获取不正确的技术债务衡量标准

c# - 对 C# Web 服务的静态引用

java - Maven : No tests were executed

javascript - 如何使用 java 在 Jquery ajax 调用中下载 PDF