是否可以在一个web.xml中包含多个jersey servlet?我试图以这种方式进行RESTfull版本控制:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>myapi</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/context-v1.xml /WEB-INF/context-v2.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>REST-V1</servlet-name>
<servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.myapi.rest.v1</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>REST-V1</servlet-name>
<url-pattern>/v1/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>REST-V2</servlet-name>
<servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.myapi.rest.v2</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>REST-V2</servlet-name>
<url-pattern>/v2/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>
但应该单独加载spring context-v1和context-v2?因为他们有豆子,它们具有相同的名称等。
修改
如果查看我的控制台输出,它会为每个servlet加载两次资源(admin / info):
15.07.2012 14:47:08 com.sun.jersey.api.core.PackagesResourceConfig init
INFO: Scanning for root resource and provider classes in the packages:
com.myapi.rest.v1
15.07.2012 14:47:08 com.sun.jersey.api.core.ScanningResourceConfig logClasses
INFO: Root resource classes found:
class com.myapi.rest.v1.LOAdminResource
class com.myapi.rest.v1.LOInfoResource
15.07.2012 14:47:08 com.sun.jersey.api.core.ScanningResourceConfig init
INFO: No provider classes found.
15.07.2012 14:47:09 com.sun.jersey.spi.spring.container.servlet.SpringServlet getContext
INFO: Using default applicationContext
15.07.2012 14:47:09 com.sun.jersey.spi.spring.container.SpringComponentProviderFactory registerSpringBeans
INFO: Registering Spring bean, adminResource_v2, of type com.myapi.rest.v2.LOAdminResource as a root resource class
15.07.2012 14:47:09 com.sun.jersey.spi.spring.container.SpringComponentProviderFactory registerSpringBeans
INFO: Registering Spring bean, infoResource_v2, of type com.myapi.rest.v2.LOInfoResource as a root resource class
15.07.2012 14:47:09 com.sun.jersey.spi.spring.container.SpringComponentProviderFactory registerSpringBeans
INFO: Registering Spring bean, adminResource_v1, of type com.myapi.rest.v1.LOAdminResource as a root resource class
15.07.2012 14:47:09 com.sun.jersey.spi.spring.container.SpringComponentProviderFactory registerSpringBeans
INFO: Registering Spring bean, infoResource_v1, of type com.myapi.rest.v1.LOInfoResource as a root resource class
15.07.2012 14:47:09 com.sun.jersey.server.impl.application.WebApplicationImpl _initiate
INFO: Initiating Jersey application, version 'Jersey: 1.8 06/24/2011 12:17 PM'
15.07.2012 14:47:09 com.sun.jersey.api.core.PackagesResourceConfig init
INFO: Scanning for root resource and provider classes in the packages:
com.myapi.rest.v2
15.07.2012 14:47:09 com.sun.jersey.api.core.ScanningResourceConfig logClasses
INFO: Root resource classes found:
class com.myapi.rest.v2.LOAdminResource
class com.myapi.rest.v2.LOInfoResource
15.07.2012 14:47:09 com.sun.jersey.api.core.ScanningResourceConfig init
INFO: No provider classes found.
15.07.2012 14:47:09 com.sun.jersey.spi.spring.container.servlet.SpringServlet getContext
INFO: Using default applicationContext
15.07.2012 14:47:09 com.sun.jersey.spi.spring.container.SpringComponentProviderFactory registerSpringBeans
INFO: Registering Spring bean, adminResource_v2, of type com.myapi.rest.v2.LOAdminResource as a root resource class
15.07.2012 14:47:09 com.sun.jersey.spi.spring.container.SpringComponentProviderFactory registerSpringBeans
INFO: Registering Spring bean, infoResource_v2, of type com.myapi.rest.v2.LOInfoResource as a root resource class
15.07.2012 14:47:09 com.sun.jersey.spi.spring.container.SpringComponentProviderFactory registerSpringBeans
INFO: Registering Spring bean, adminResource_v1, of type com.myapi.rest.v1.LOAdminResource as a root resource class
15.07.2012 14:47:09 com.sun.jersey.spi.spring.container.SpringComponentProviderFactory registerSpringBeans
INFO: Registering Spring bean, infoResource_v1, of type com.myapi.rest.v1.LOInfoResource as a root resource class
15.07.2012 14:47:09 com.sun.jersey.server.impl.application.WebApplicationImpl _initiate
INFO: Initiating Jersey application, version 'Jersey: 1.8 06/24/2011 12:17 PM'
答案 0 :(得分:8)
是的,您可以在web.xml中指定两个或更多servlet。请记住为每个servlet映射指定不同的servlet映射。
<servlet>
<servlet-name>servletOne</servlet-name>
<servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.packageOne</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>servletTwo</servlet-name>
<servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.packageTwo</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ServletOne</servlet-name>
<url-pattern>/v1/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>ServletTwo</servlet-name>
<url-pattern>/v2/*</url-pattern>
</servlet-mapping>
initParameter loadOnStartup定义了加载servlet的顺序(在本例中是第一个servletOne,然后是servletTwo)。
答案 1 :(得分:6)
当你一起使用Jersey和Spring时,Jersey / Spring servlet遍历所有可用的Spring bean并注册它们将在其中找到的每个资源和提供者类。
如果有多个Jersey / Spring servlet使用相同的(根)上下文并因此共享bean定义,那么将为每个这样的servlet执行该过程,并且多次注册资源和提供者类。
为了避免多次注册同一个bean,在相应的Jesrey / Spring servlet的子上下文中定义这样的bean。
除非需要混合使用Spring-managed和Jersey-managed类,否则甚至没有必要提供用于在web.xml中声明类的初始化参数。
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/root-context.xml</param-value>
</context-param>
...
<servlet>
<servlet-name>REST-V1</servlet-name>
<servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/context-v1.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>REST-V2</servlet-name>
<servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/context-v1.xml /WEB-INF/context-v2.xml</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
...
答案 2 :(得分:1)
我知道这个话题很难回答。但我的回答可以帮助别人。
我们可以使用这些分隔符在web.xml中配置多个资源包:
示例:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>MultiplePackageRest</display-name>
<servlet>
<servlet-name>JerseyMultiplePackage</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>info.javadoff.rest1,info.javadoff.rest2,...</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>JerseyMultiplePackage</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
</web-app>
答案 3 :(得分:1)
另一种可能性是覆盖com.sun.jersey.spi.spring.container.servlet.SpringServlet
中的一个方法。 initiate方法看起来像这样(版本1.19.1):
@Override
protected void initiate(ResourceConfig rc, WebApplication wa) {
try {
wa.initiate(rc, new SpringComponentProviderFactory(rc, getContext()));
} catch (RuntimeException e) {
LOGGER.log(Level.SEVERE, "Exception occurred when intialization", e);
throw e;
}
}
如果您更改这样的子类中的代码,那么您可以根据您的条件(例如包名称)过滤掉不需要的spring bean:
@Override
protected void initiate(ResourceConfig rc, WebApplication wa) {
try {
SpringComponentProviderFactory springComponentProviderFactory = new SpringComponentProviderFactory(rc, getContext());
rc.getClasses().removeIf( clazz -> clazz.getPackage().getName().startsWith( "bla" ));
wa.initiate(rc, springComponentProviderFactory);
} catch (RuntimeException e) {
LOGGER.log(Level.SEVERE, "Exception occurred when intialization", e);
throw e;
}
}
有点hacky解决方案,但对我们来说非常有效。