我正在Spring Boot 1.5.2上缩减包含Web服务的大型Web应用程序,使其仅成为Jersey Web Service。因为该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>
我的新Jersey配置看起来像这样:
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 [/*]。但是,当我使用Web浏览器访问/时,出现404 Not Found错误。看起来GET定义似乎没有被采用。
Mapping servlet: 'com.example.configuration.JerseyConfiguration' to [/*]
404 Not Found
此问题在JAX- RS规范的第3.6节“注释继承”中进行了说明。
JAX-RS批注可用于超类或已实现接口的方法和方法参数。此类注释由相应的子类或实现类方法继承, 条件是该方法及其参数自己没有任何JAX- RS注释。 如果子类或实现方法具有任何JAX-RS批注,那么将忽略超类或接口方法上的所有批注。 例如: 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注释中,on ReadOnlyAtomFeed.getFeed未被继承,ActivityLog.getFeed并且它需要自己的请求方法标识符(@GET),因为它重新定义了@Produces注释。 为了与其他Java EE规范保持一致,建议始终重复注释,而不要依赖注释继承。
JAX-RS批注可用于超类或已实现接口的方法和方法参数。此类注释由相应的子类或实现类方法继承, 条件是该方法及其参数自己没有任何JAX- RS注释。
如果子类或实现方法具有任何JAX-RS批注,那么将忽略超类或接口方法上的所有批注。 例如:
public interface ReadOnlyAtomFeed { @GET @Produces("application/atom+xml") Feed getFeed(); } @Path("feed") public class ActivityLog implements ReadOnlyAtomFeed { public Feed getFeed() {...} }
在上面,从接口ActivityLog.getFeed继承@GET和@Produces注释。
ActivityLog.getFeed
@GET
@Produces
反过来:
@Path("feed") public class ActivityLog implements ReadOnlyAtomFeed { @Produces("application/atom+xml") public Feed getFeed() {...} }
在上面的@GET注释中,on ReadOnlyAtomFeed.getFeed未被继承,ActivityLog.getFeed并且它需要自己的请求方法标识符(@GET),因为它重新定义了@Produces注释。
ReadOnlyAtomFeed.getFeed
为了与其他Java EE规范保持一致,建议始终重复注释,而不要依赖注释继承。
我已经强调了重要的端口。应该很清楚为什么它不适合您。在您的中EndpointImpl,您重复了@Context注释,因此导致 “超类或接口方法上的所有注释都被忽略” 。这包括@GET。因此最终,由于端点需要一个,因此这将导致该端点无法注册@METHOD。
EndpointImpl
@Context
@METHOD
至于blockquote中的最后一段,您可以选择是否遵循。我只是为了完整性而把它扔在那里。