我有一个Web应用程序,它将从jar文件中动态加载其资源。
我开始使用org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory.createHttpServer
设置自己的服务器,并通过ServiceLoader
加载所有资源,并通过ResourceConfig#register
注册。这很好用,但我总是运行第二台服务器。
现在我想创建一个简单的应用程序之战并将其部署在例如tomcat的。这个想法是,当加载战争时,资源也通过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)
我的做法完全错了吗?或者我如何创建这样一个系统,作为可部署的战争运行?
*编辑*
使用ServletContextListener,我可以解决多个init调用,但是我的资源没有被加载。
所以,我有这样的资源
@Path("test")
公共类TestResource实现MarkerInterface { @得到 @Produces(MediaType.TEXT_PLAIN) @Path( “获取”) public String get(){ 返回“你好”; } } 此资源打包在一个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");
}
}
}
我在tomcat上将注册输出部署为server.war
时会看到日志中的注册输出,但是当我调用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ássioMazzochiMolin对此讨论的回答。
我使用构建器注册我的资源并将其打印出来
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
答案 0 :(得分:2)
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。
答案 1 :(得分:1)
尝试使用ServletContextListener。这应该为你提供一个做同样工作的钩子。
答案 2 :(得分:0)
我在最后几个小时内一直在寻找这个。在适当尊重解决方案的建议和其他问题的同一问题区域是半熟。大多数解决方案都以编程方式说明了扩展REST资源的代码。我缺少的是我在哪里放这个代码。
Jersey文档给出了正确的方法。以下是链接:
https://jersey.github.io/documentation/latest/resource-builder.html#d0e10860
诀窍是创建自己的自定义CustomResourceConfig
类,扩展标准球衣ResourceConfig
类。然后将CustomResourceConfig类作为init参数传递给Jersey servlet。
<servlet>
<servlet-name>org.glassfish.jersey.examples.helloworld.MyApplication</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>org.glassfish.jersey.examples.helloworld.MyResourceConfig</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
请遵循上面给出的球衣文件,我相信一切顺利。
希望这有帮助