You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何将Spring Boot REST API集成到带ProGuard混淆的传统Servlet WAR包,同时确保共享依赖类可正常访问?

如何将Spring Boot REST API集成到带ProGuard混淆的传统Servlet WAR包,同时确保共享依赖类可正常访问?

我来给你梳理下这个问题的解决思路和具体方案,咱们先从核心矛盾入手:你现在的问题本质是ProGuard混淆了Core的类名,但PublicApi的代码还在引用原来的全限定名,导致运行时找不到类。要解决这个问题,关键是让PublicApi和混淆后的Core类名对齐,同时把Spring Boot应用正确嵌入到传统WAR里,完全能满足你要求的安全和部署规则。

一、先给你吃个定心丸:这种集成是100%可行的

不用纠结能不能做到,只要把混淆规则和嵌入流程理清楚,完全可以在同一个Tomcat实例的/Services上下文下,让传统Servlet处理/Services/*,Spring Boot API处理/Services/api/*,同时Core类全程保持混淆状态。

二、核心解决方案:让PublicApi跟着ProGuard的混淆映射走

现在的问题是PublicApi和Core的类名没有对齐,所以要让PublicApi的代码也经过ProGuard处理,复用Core的混淆映射,这样它引用Core的地方会自动替换成混淆后的类名。具体分几步走:

1. 拆分ProGuard流程,共享混淆映射文件

首先,我们要让Core的混淆结果可复用,而不是只在Services的WAR里单独混淆:

  • 第一步:单独对Core库运行ProGuard,生成混淆映射文件(mapping.txt)——这个文件是关键,它记录了所有原始类名、方法名到混淆后名称的对应关系。
  • 第二步:在构建PublicApi的时候,把这个mapping.txt作为ProGuard的输入参数,让ProGuard对PublicApi的代码做混淆处理。这样PublicApi里所有引用Core原始类名的地方,都会自动替换成混淆后的类名,和Core的混淆结果完全对齐。
  • 第三步:把经过ProGuard处理后的PublicApi编译产物(比如class文件或者瘦身JAR),和传统Services的代码、混淆后的Core库一起打包成最终的WAR。

2. 把Spring Boot API正确嵌入到传统WAR的web.xml里

现在PublicApi的代码已经能识别混淆后的Core类了,接下来要让Tomcat把/Services/api/*的请求转发给Spring Boot的DispatcherServlet:

  • 先修改PublicApi的启动类,让它适配传统Servlet容器的启动方式,继承SpringBootServletInitializer
public class PublicApiApplication extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(PublicApiApplication.class);
    }
}
  • 然后在传统Services的web.xml里,注册Spring的DispatcherServlet,指定它处理/api/*的请求,同时指向PublicApi的启动类作为Spring上下文的入口:
<servlet>
    <servlet-name>publicApiDispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>com.example.publicapi.PublicApiApplication</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>publicApiDispatcher</servlet-name>
    <url-pattern>/api/*</url-pattern>
</servlet-mapping>
  • 这里要注意:Spring相关的入口类、控制器类不能被混淆,否则Tomcat和Spring容器找不到它们。所以要在ProGuard配置里加规则保留这些类的类名和注解:
# 保留Spring Boot启动类的类名和方法
-keep public class com.example.publicapi.PublicApiApplication {
    public <methods>;
}
# 保留所有@RestController控制器的类名和公开方法
-keep @org.springframework.web.bind.annotation.RestController class * {
    public <methods>;
}
# 保留Spring注解,避免影响容器扫描
-keepattributes *Annotation*
# 复用Core的混淆映射,让PublicApi的引用自动替换
-applymapping path/to/core/mapping.txt

3. 统一构建打包的流程

把整个构建流程串起来,避免出错:

  1. 构建并混淆Core库,输出混淆后的Core JAR和mapping.txt
  2. mapping.txt为输入,构建并混淆PublicApi,输出混淆后的PublicApi产物。
  3. 将混淆后的Core JAR、PublicApi产物,和传统Services的代码一起打包成一个WAR。
  4. (可选)对最终WAR再运行一次ProGuard,但必须复用之前的mapping.txt,避免重复混淆Core类导致类名变化。

三、踩坑预警:这些细节千万要注意

  • 绝对不能让PublicApi的代码“裸奔”进WAR:如果PublicApi没经过ProGuard处理就打包进去,它还是会引用Core的原始类名,必然报ClassNotFoundException。
  • 不要重复混淆Core:第一次混淆生成的mapping.txt要全程复用,第二次混淆如果不指定这个文件,会重新生成类名,导致之前处理好的PublicApi又找不到类。
  • 传统Servlet的入口也要保留混淆豁免:比如你的Services里的Servlet、Filter类,也要在ProGuard配置里保留类名和公开方法,否则Tomcat找不到这些组件:
# 保留传统Servlet和Filter的类名与公开方法
-keep public class com.example.services.*Servlet {
    public <methods>;
}
-keep public class com.example.services.*Filter {
    public <methods>;
}

四、备选方案:如果不想拆分构建流程

如果调整PublicApi的构建流程太麻烦,还有个更简单的思路:直接把未混淆的PublicApi JAR打包进Services的WAR,然后对整个WAR运行一次ProGuard,用同一个配置文件混淆Core和PublicApi的代码:

  • 把PublicApi的JAR、Core的原始JAR、Services的代码一起打包成一个WAR。
  • 对这个WAR运行ProGuard,配置文件里指定混淆Core和PublicApi的代码,同时保留Spring和传统Servlet的入口类:
# 保留所有需要对外可见的类
-keep public class com.example.services.*Servlet { public <methods>; }
-keep public class com.example.services.*Filter { public <methods>; }
-keep public class com.example.publicapi.PublicApiApplication { public <methods>; }
-keep @org.springframework.web.bind.annotation.RestController class * { public <methods>; }

# 保留注解和签名信息
-keepattributes *Annotation*, Signature

# 混淆Core和其他非豁免代码
-obfuscate
-printmapping mapping.txt

这样ProGuard会一次性处理整个WAR里的所有代码,自动把PublicApi里引用Core的地方替换成混淆后的类名,一步到位。

最后再总结下

核心就是让PublicApi的代码和Core的混淆结果对齐,要么拆分流程复用映射文件,要么一次性混淆整个WAR。同时把Spring Boot的DispatcherServlet正确注册到传统web.xml里,保留必要的类不被混淆。按照这个思路走,你就能完美实现所有要求:同一个WAR、同一个上下文路径、Core全程混淆、两个应用都能正常运行。

如果还有构建工具(比如Maven/Gradle)的具体配置问题,咱们再细化讨论!

火山引擎 最新活动