多Swagger2Feature实例集成异常:第二个实例扫描错误包路径求助
解决多Swagger实例扫描错误包的问题
看起来你遇到的核心问题是多个Swagger实例的资源扫描范围冲突,加上Web层的Servlet配置没有正确隔离两个上下文。我来一步步帮你修正配置:
问题根源分析
- Web层Servlet配置缺失:你的
web.xml只配置了一个CXFServlet,仅加载context2.xml,根本没把第一个上下文(rest1)部署进去,两个上下文需要独立的Servlet来做隔离。 - JAX-RS Server Bean名称冲突:两个context里的
<jaxrs:server>id都是container,如果同时加载会导致Spring容器内的bean名称重复,引发覆盖问题。 - Swagger扫描策略错误:
scanAllResources="true"会强制Swagger扫描所有已注册的JAX-RS资源,完全忽略你指定的resourcePackage,这就是第二个实例扫到第一个包的直接原因。
修正后的完整配置
1. 修改web.xml:添加两个独立的CXFServlet
每个Servlet对应一个上下文,映射到不同的URL路径,确保两个实例完全隔离:
<web-app> <!-- 第一个Swagger实例:对应rest1路径 --> <servlet> <servlet-name>AppSwaggerCXFServlet1</servlet-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> <init-param> <param-name>config-location</param-name> <param-value>classpath*:/context1.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>AppSwaggerCXFServlet1</servlet-name> <url-pattern>/rest1/*</url-pattern> </servlet-mapping> <!-- 第二个Swagger实例:对应rest2路径 --> <servlet> <servlet-name>AppSwaggerCXFServlet2</servlet-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> <init-param> <param-name>config-location</param-name> <param-value>classpath*:/context2.xml</param-value> </init-param> <load-on-startup>2</load-on-startup> </servlet> <servlet-mapping> <servlet-name>AppSwaggerCXFServlet2</servlet-name> <url-pattern>/rest2/*</url-pattern> </servlet-mapping> </web-app>
2. 修改context1.xml:修正Server ID和Swagger扫描策略
把<jaxrs:server>的id改成唯一的container1,并将scanAllResources设为false,确保只扫描指定包:
<context:component-scan base-package="org.app.rest.cxf.service"/> <bean id="swagger2customizer" class="org.apache.cxf.jaxrs.swagger.Swagger2Customizer"> <property name="dynamicBasePath" value="true"/> <property name="replaceTags" value="true"/> </bean> <bean id="swagger2Feature" class="org.apache.cxf.jaxrs.swagger.Swagger2Feature"> <property name="title" value="Test"/> <property name="version" value="1.0"/> <property name="description" value="Test 1.0"/> <property name="contact" value="dev@syncope.apache.org"/> <property name="resourcePackage" value="org.app.rest.api.service"/> <!-- 关键:关闭全量扫描,只扫描指定包 --> <property name="scanAllResources" value="false"/> <property name="activateOnlyIfJaxrsSupported" value="true"/> <property name="customizer" ref="swagger2customizer"/> </bean> <!-- 修改id为container1,避免与第二个实例的bean冲突 --> <jaxrs:server id="container1" address="/" basePackages="org.app.rest.api.service, org.app.rest.cxf.service" staticSubresourceResolution="true"> <jaxrs:properties> <entry key="search.lax.property.match" value="true"/> <entry key="convert.wadl.resources.to.dom" value="false"/> </jaxrs:properties> <jaxrs:inInterceptors> <ref bean="gzipInInterceptor"/> <ref bean="validationInInterceptor"/> </jaxrs:inInterceptors> <jaxrs:outInterceptors> <ref bean="gzipOutInterceptor"/> <ref bean="validationOutInterceptor"/> </jaxrs:outInterceptors> <jaxrs:providers> <ref bean="dateParamConverterProvider"/> <ref bean="jaxbProvider"/> <ref bean="jsonProvider"/> <ref bean="exceptionMapper"/> <ref bean="searchContextProvider"/> <ref bean="addDomainFilter"/> <ref bean="addETagFilter"/> <ref bean="wadlGenerator"/> </jaxrs:providers> <jaxrs:features> <ref bean="swagger2Feature"/> </jaxrs:features> </jaxrs:server>
3. 修改context2.xml:同样修正Server ID和Swagger扫描策略
把<jaxrs:server>的id改成container2,scanAllResources设为false:
<context:component-scan base-package="com.app2.rest.cxf.service"/> <bean id="swagger2customizer2" class="org.apache.cxf.jaxrs.swagger.Swagger2Customizer"> <property name="dynamicBasePath" value="true"/> <property name="replaceTags" value="true"/> </bean> <bean id="swagger2Feature2" class="org.apache.cxf.jaxrs.swagger.Swagger2Feature"> <property name="title" value="Test"/> <property name="version" value="1.0"/> <property name="description" value="Test 1.0"/> <property name="contact" value="dev@syncope.apache.org"/> <property name="resourcePackage" value="com.app2.rest.api.service"/> <!-- 关键:关闭全量扫描,只扫描指定包 --> <property name="scanAllResources" value="false"/> <property name="activateOnlyIfJaxrsSupported" value="true"/> <property name="customizer" ref="swagger2customizer2"/> </bean> <!-- 修改id为container2,避免与第一个实例的bean冲突 --> <jaxrs:server id="container2" address="/" basePackages="com.app2.rest.api.service, com.app2.rest.cxf.service" staticSubresourceResolution="true"> <jaxrs:properties> <entry key="search.lax.property.match" value="true"/> <entry key="convert.wadl.resources.to.dom" value="false"/> </jaxrs:properties> <jaxrs:inInterceptors> <ref bean="gzipInInterceptor"/> <ref bean="validationInInterceptor"/> </jaxrs:inInterceptors> <jaxrs:outInterceptors> <ref bean="gzipOutInterceptor"/> <ref bean="validationOutInterceptor"/> </jaxrs:outInterceptors> <jaxrs:providers> <ref bean="dateParamConverterProvider"/> <ref bean="jaxbProvider"/> <ref bean="jsonProvider"/> <ref bean="exceptionMapper"/> <ref bean="searchContextProvider"/> <ref bean="addDomainFilter"/> <ref bean="addETagFilter"/> <ref bean="wadlGenerator"/> </jaxrs:providers> <jaxrs:features> <ref bean="swagger2Feature2"/> </jaxrs:features> </jaxrs:server>
验证效果
配置完成后重启应用,访问:
- 第一个Swagger:
http://localhost:8080/app/rest1/swagger.json,应该只包含org.app.rest.api.service下的端点 - 第二个Swagger:
http://localhost:8080/app/rest2/swagger.json,应该只包含com.app2.rest.api.service下的端点
核心逻辑就是通过独立的Servlet隔离两个上下文,加上关闭Swagger的全量扫描确保只扫描指定包,同时避免Spring Bean名称冲突。
内容的提问来源于stack exchange,提问作者Briston12
相关产品推荐
相关产品推荐

