java 一个 web.xml 中的多个 jersey servlet
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11460977/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Multiple jersey servlets in one single web.xml
提问by Ben
Is it possible to have multiple jersey servlets in one single web.xml? I am trying to do the RESTfull versioning in this way:
是否可以在一个 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>
But the spring context-v1 and context-v2 should be loaded separately? Because they have beans, which have the same name etc.
但是spring的context-v1和context-v2应该是分开加载的吧?因为他们有豆子,它们有相同的名字等等。
EDIT:
编辑:
If you look in my console output it's loading the resources (admin/info) two times for each servlet:
如果您查看我的控制台输出,它会为每个 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'
回答by Giorgio
Yes you can specify two or more servlets into a web.xml . Remember to specify a different servlet-mapping for each one.
是的,您可以在 web.xml 中指定两个或多个 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>
the initParameter loadOnStartup defines the order in which the servlet are loaded (in this case first servletOne and then servletTwo).
initParameter loadOnStartup 定义了 servlet 的加载顺序(在这种情况下,首先是 servletOne,然后是 servletTwo)。
回答by pgiecek
The thing is that when you use Jersey and Spring together, the Jersey/Spring servlet goes through all available Spring beans and registers every resource and provider classes it will find among them.
问题是,当您同时使用 Jersey 和 Spring 时,Jersey/Spring servlet 会遍历所有可用的 Spring bean 并注册它会在其中找到的每个资源和提供程序类。
If you have multiple Jersey/Spring servlets using the same (root) context and thus sharing bean definitions, then the procedure is performed for each such servlet and resource and provider class are registered several times.
如果您有多个 Jersey/Spring servlet 使用相同的(根)上下文并因此共享 bean 定义,那么将为每个这样的 servlet 执行该过程,并且资源和提供程序类被注册多次。
In order to avoid multiple registration of the same bean, define such beans in a child context of a respective Jesrey/Spring servlet.
为了避免对同一 bean 进行多次注册,请在相应 Jesrey/Spring servlet 的子上下文中定义此类 bean。
It is even not necessary to provide initialization parameters for declaring classes in the web.xml unless a mixture of Spring-managed and Jersey-managed classes is required.
甚至不需要为在 web.xml 中声明类提供初始化参数,除非需要混合使用 Spring 管理和 Jersey 管理的类。
<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>
...
回答by Emin Javadov
I know this topic is old to answer. But my answer can help others.
我知道这个话题是旧的回答。但我的回答可以帮助其他人。
We can configure multiple resource packages in web.xml with these delimiters :
我们可以使用以下分隔符在 web.xml 中配置多个资源包:
- White space
- Comma (,)
- Semicolon (;)
- Nextline
- 留白
- 逗号 (,)
- 分号 (;)
- 下线
Example :
例子 :
<?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>
回答by Gábor Lipták
One more possibility is to override one method in com.sun.jersey.spi.spring.container.servlet.SpringServlet
. The initiate method looks like this (version 1.19.1):
另一种可能性是覆盖com.sun.jersey.spi.spring.container.servlet.SpringServlet
. 启动方法如下所示(版本 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;
}
}
If you change the code in a subclass like this, then you can filter out the unwanted spring beans based on your criteria (for example package name):
如果您像这样更改子类中的代码,那么您可以根据您的条件(例如包名称)过滤掉不需要的 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;
}
}
A bit hacky solution, but works for us perfectly.
一个有点hacky的解决方案,但对我们来说完美无缺。