JAX-RS不适用于Spring Boot 1.4.1

我正在尝试使用Spring Boot 1.4.1.RELEASE开发一个简单的基于JAX-RS的Web服务。 但得到这个例外 –

java.lang.IllegalStateException: No generator was provided and there is no default generator registered at org.glassfish.hk2.internal.ServiceLocatorFactoryImpl.internalCreate(ServiceLocatorFactoryImpl.java:308) ~[hk2-api-2.5.0-b05.jar:na] at org.glassfish.hk2.internal.ServiceLocatorFactoryImpl.create(ServiceLocatorFactoryImpl.java:268) ~[hk2-api-2.5.0-b05.jar:na] at org.glassfish.jersey.internal.inject.Injections._createLocator(Injections.java:138) ~[jersey-common-2.23.2.jar:na] at org.glassfish.jersey.internal.inject.Injections.createLocator(Injections.java:123) ~[jersey-common-2.23.2.jar:na] at org.glassfish.jersey.server.ApplicationHandler.(ApplicationHandler.java:330) ~[jersey-server-2.23.2.jar:na] at org.glassfish.jersey.servlet.WebComponent.(WebComponent.java:392) ~[jersey-container-servlet-core-2.23.2.jar:na] at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:177) ~[jersey-container-servlet-core-2.23.2.jar:na] at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:369) ~[jersey-container-servlet-core-2.23.2.jar:na] 

这是我的计划详情 –

POM.xml中包含的依赖项 –

   org.springframework.boot spring-boot-starter-jersey   org.springframework.boot spring-boot-starter-test test   

这里是JerseyConfig文件 –

 package com.test.main; import org.glassfish.jersey.server.ResourceConfig; import org.springframework.stereotype.Component; import com.test.resources.TutorialResource; @Component public class JerseyConfig extends ResourceConfig{ public JerseyConfig() { register(TutorialResource.class); packages("com.test.resources"); } } 

重要提示:在最新版本的Spring Boot中看起来不存在此问题。 但是,当您想要使用Spring Boot和Jersey创建应用程序时,此答案的内容仍可用作指南。


Spring Boot 1.4.1中JAR的布局已更改

Spring Boot 1.4.1 中可执行jar的布局已经改变 :应用程序的依赖项现在打包在BOOT-INF/lib而不是lib ,而应用程序自己的类现在打包在BOOT-INF/classes而不是jar的根目录中。 它会影响泽西岛:

Jersey类路径扫描限制

对可执行jar的布局的更改意味着Jersey的类路径扫描中的限制现在会影响可执行jar文件以及可执行war文件。 要解决此问题,您希望由Jersey扫描的类应打包在jar中,并作为依赖项包含在BOOT-INF/lib 。 然后应将Spring Boot启动程序配置为在启动时解压缩这些jar,以便Jersey可以扫描其内容。

我发现注册类而不是包工作。 请参阅下面使用Spring Boot和Jersey创建应用程序的步骤。

使用Spring Boot和Jersey创建Web应用程序

确保您的pom.xml文件将spring-boot-starter-parent声明为父项目:

  org.springframework.boot spring-boot-starter-parent 1.4.1.RELEASE  

您还需要以下依赖项:

   org.springframework.boot spring-boot-starter-web   org.springframework.boot spring-boot-starter-jersey   org.springframework.boot spring-boot-starter-test test   junit junit test   

和Spring Boot Maven插件:

    org.springframework.boot spring-boot-maven-plugin    

例如,创建一个使用@Path注释的Jersey资源类,并定义一个资源方法来处理GET请求,生成text/plain

 @Path("/greetings") public class GreetingResource { @GET @Produces(MediaType.TEXT_PLAIN) public Response getGreeting() { return Response.ok("Hello, World!").build(); } } 

然后创建一个扩展ResourceConfigApplication的类来注册Jersey资源并使用@ApplicationPath注释它。 注册类而不是注册包与Spring Boot 1.4.1一起使用:

 @Component @ApplicationPath("api") public class JerseyConfig extends ResourceConfig { @PostConstruct private void init() { registerClasses(GreetingResource.class); } } 

最后创建一个Spring Boot类来执行应用程序:

 @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } 

如果要测试此Web服务,可以使用JAX-RS Client API :

 @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class GreetingResourceTest { @LocalServerPort private int port; private URI uri; @Before public void setUp() throws Exception { this.uri = new URI("http://localhost:" + port); } @Test public void testGreeting() { Client client = ClientBuilder.newClient(); Response response = client.target(uri).path("api").path("greetings") .request(MediaType.TEXT_PLAIN).get(); String entity = response.readEntity(String.class); assertEquals("Hello, World!", entity); } } 

要编译并运行该应用程序,请按照下列步骤操作:

  • 打开命令行窗口或终端。
  • 导航到pom.xml所在项目的根目录。
  • 编译项目: mvn clean compile
  • 打包应用程序: mvn package
  • 查看目标目录。 您应该看到一个具有以下名称或类似名称的文件: spring-jersey-1.0-SNAPSHOT.jar
  • 切换到目标目录。
  • 执行JAR: java -jar spring-jersey-1.0-SNAPSHOT.jar
  • 该应用程序应该在http://localhost:8080/api/greetings

注1:看一下Spring Boot文档。 有专门针对泽西岛的部分 。

注意2:生成JSON时,请确保已注册JSON提供程序 。 尽管ResourceConfig应该注意这一点(只需确保依赖关系在类路径上)。

虽然Jersey无法在新版本的胖启动jar中扫描你的类,但使用Spring类路径扫描工具可以达到同样的效果。 这样,您可以类似于ResourceConfig.packages()扫描包:

 ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false); scanner.addIncludeFilter(new AnnotationTypeFilter(Provider.class)); scanner.addIncludeFilter(new AnnotationTypeFilter(Path.class)); config.registerClasses(scanner.findCandidateComponents("your.package.to.scan").stream() .map(beanDefinition -> ClassUtils.resolveClassName(beanDefinition.getBeanClassName(), config.getClassLoader())) .collect(Collectors.toSet())); 

注意:请查看org.glassfish.jersey.server.internal.scanning.AnnotationAcceptingListener的来源。 这是库存解决方案,您可以看到它执行相同的操作:它扫描使用@Path@Provider注释的类(但由于扫描机制损坏,无法找到任何内容)。

更新:

我有一个自定义配置,它没有扩展ResourceConfig,但返回了一个bean的实例。 如果你看一下官方的Spring例子 ,你可以将上面的代码插入到JerseyConfig()构造函数中(而不是两个register(...)调用)。 唯一的区别是,您只需在构造函数中调用registerClasses(...) ,而不是调用config.registerClasses(...)

我认为你应该使用@Configuration而不是@Component来注释你的JerseyConfig