如何使用Spring Boot 1.5.2注入Jersey端点接口的实现?

时间:2017-04-06 22:42:15

标签: spring spring-boot jersey jax-rs

我正在缩减包含Web服务的大型Web应用程序,以便在Spring Boot 1.5.2上成为Jersey Web服务。因为Web服务已经有了一套由Apache Wink实现的完整的JAX-RS注释,所以我决定使用Spring + Jersey而不是Spring Rest。我发现这个spring-boot-jersey-sample应用程序用作参考。我正在处理的应用程序和示例之间的最大区别是我的端点定义在接口和实现之间划分。

我在pom.xml中添加了以下内容:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jersey</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
        <scope>provided</scope>
    </dependency>

我的新泽西配置看起来像这样:

package com.example.configuration;

import org.glassfish.jersey.server.ResourceConfig;
import com.example.EndpointImpl;
import org.springframework.stereotype.Component;

@Component
public class JerseyConfiguration extends ResourceConfig {
  public JerseyConfiguration() {
    registerEndpoints();
  }

  private void registerEndpoints() {
    register(EndpointImpl.class);     
  }
}

然后我有以下Application.java:

package com.example;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;

@SpringBootApplication
public class Application extends SpringBootServletInitializer{
  public static void main(String[] args) {
    new Application().configure(new SpringApplicationBuilder(Application.class)).run(args);
  }
}

端点被定义为接口和实现,如下所示(减去导入):

public interface Endpoint {
  @GET
  @Produces({MediaType.APPLICATION_JSON})
  public Response getHello(@Context ServletContext sc, @Context HttpServletRequest req, @Context HttpHeaders httpHeaders) ;
}
@Path("")
@Component
public class EndpointImpl implements Endpoint {
  @Override
  public Response getHello(@Context ServletContext sc, @Context HttpServletRequest req,
      @Context HttpHeaders httpHeaders)  {
      return Response.ok("hello").build();
  }
}

当我启动我的应用程序时,我看到有关Tomcat启动的消息,包括说Mapping servlet: 'com.example.configuration.JerseyConfiguration' to [/*]的消息。但是,当我使用网络浏览器时,我收到404 Not Found错误。看起来GET定义并没有被提升。

3 个答案:

答案 0 :(得分:1)

第3.6节“注释继承”中的JAX-RS spec解释了此问题。

  

JAX-RS注释可用于超类或实现接口的方法和方法参数。此类注释由相应的子类或实现类方法继承,前提是该方法及其参数没有自己的任何JAX-RS注释。

     

如果子类或实现方法具有任何JAX-RS注释,则忽略超类或接口方法上的所有注释。 E.g:

public interface ReadOnlyAtomFeed {
  @GET @Produces("application/atom+xml")
  Feed getFeed();
}

@Path("feed")
public class ActivityLog implements ReadOnlyAtomFeed {
  public Feed getFeed() {...}
}
     

在上文中,ActivityLog.getFeed继承了界面中的@GET@Produces注释。

     

相反:

@Path("feed")
public class ActivityLog implements ReadOnlyAtomFeed {
  @Produces("application/atom+xml")
  public Feed getFeed() {...}
}
     

在上文中,@GET上的ReadOnlyAtomFeed.getFeed注释不会被ActivityLog.getFeed继承,并且它需要自己的请求方法指示符(@GET),因为它重新定义@Produces注释。

     

为了与其他Java EE规范保持一致,建议始终重复注释,而不是依赖注释继承。

我突出了重要的端口。应该很清楚为什么它不适合你。在EndpointImpl中,您重复了@Context注释,因此导致“忽略超类或接口方法上的所有注释”。这包括@GET。因此,最终,这会导致端点无法注册,因为端点需要@METHOD

就blockquote中的最后一段而言,您可以选择是否遵循它。我只是为了完整而把它扔在那里。

答案 1 :(得分:1)

您的application.yml(.properties)是什么样的:

您可能需要声明两个路径映射,一个用于Jersey MVC调度程序servlet,另一个用于... # Spring MVC dispatcher servlet path. Needs to be different than Jersey's to enable/disable Actuator endpoints access (/info, /health, ...) server.servlet-path: / # Jersey dispatcher servlet spring.jersey.application-path: /api ... 调度程序servlet。类似的东西:

<强> application.yml

Jersey

您现在应该可以在/ api /.....

访问lsregister -dump个端点

我在2016年4月发表的博客文章中对此进行了介绍:your pattern

答案 2 :(得分:0)

除非在最近的Spring Boot / Spring MVC + Jersey版本中发生了某些变化,否则要让Spring Boot识别Jersey端点,你需要使用额外的@Component注册它,以扩展Jersey的ResourceConfig:

@Component
public class JerseyExampleConfig extends ResourceConfig {

    public JerseyExampleConfig() {
        register(EndpointImpl.class);
    } 
}