JAX-RS不适用于Spring Boot 1.4.1

aka*_*kr6 2 java jax-rs maven spring-boot

我正在尝试使用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.<init>(ApplicationHandler.java:330) ~[jersey-server-2.23.2.jar:na]
at org.glassfish.jersey.servlet.WebComponent.<init>(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]
Run Code Online (Sandbox Code Playgroud)

这是我的计划详情 -

POM.xml中包含的依赖项 -

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jersey</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
Run Code Online (Sandbox Code Playgroud)

这里是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");
    }
}
Run Code Online (Sandbox Code Playgroud)

cas*_*lin 14

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


Spring Boot 1.4.1中JAR的布局已更改

Spring Boot 1.4.1 中可执行jar布局已经改变:应用程序的依赖项现在打包BOOT-INF/lib而不是lib,应用程序自己的类现在打包在BOOT-INF/classesjar而不是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为父项目:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.4.1.RELEASE</version>
</parent>
Run Code Online (Sandbox Code Playgroud)

您还需要以下依赖项:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jersey</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
Run Code Online (Sandbox Code Playgroud)

和Spring Boot Maven插件:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>
Run Code Online (Sandbox Code Playgroud)

例如,创建一个带有注释的Jersey资源类,@Path并定义一个资源方法来处理GET请求,从而产生text/plain:

@Path("/greetings")
public class GreetingResource {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public Response getGreeting() {
        return Response.ok("Hello, World!").build();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

@Component
@ApplicationPath("api")
public class JerseyConfig extends ResourceConfig {

    @PostConstruct
    private void init() {
        registerClasses(GreetingResource.class);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果要测试此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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 打开命令行窗口或终端.
  • 导航到项目所在的根目录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应该注意这一点(只需确保依赖关系在类路径上).


mih*_*u86 7

虽然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()));
Run Code Online (Sandbox Code Playgroud)

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

更新:

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