You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

迁移至Jakarta Mail时遇StreamProvider类型不匹配问题求助

迁移至Jakarta Mail时出现StreamProvider类型不匹配问题

我正在将一个基于Java 1.8、Spring 3、SpringMVC、Spring Security且部署在Tomcat 9上的非Spring Boot应用,迁移至Java 17、Spring 6、Spring Security 6并部署在Tomcat 11环境。目前已完成Tomcat9+Spring5+Security5+Java11的迁移,但升级到目标环境后,在从javax.mail迁移至jakarta.mail时遇到问题:先解决了“找不到jakarta.mail.util.StreamProvider实现”的问题,现在又出现错误jakarta.mail.util.StreamProvider: org.eclipse.angus.mail.util.MailStreamProvider not a subtype。


相关配置文件

context.xml

<Context>
   <Resource auth="Container" mail.debug="true" mail.from="email"
       mail.smtp.host="email" mail.smtp.port="25" mail.user="user"
       name="mail/Session" type="jakarta.mail.Session" />
</Context>

pom.xml(关键依赖部分)

<dependency>
    <groupId>jakarta.mail</groupId>
    <artifactId>jakarta.mail-api</artifactId>
    <version>2.1.3</version>
</dependency>
<dependency>
    <groupId>org.eclipse.angus</groupId>
    <artifactId>angus-mail</artifactId>
    <version>2.0.3</version>
</dependency>
<dependency>
    <groupId>jakarta.activation</groupId>
    <artifactId>jakarta.activation-api</artifactId>
    <version>2.1.3</version>
</dependency>
<dependency>
    <groupId>org.eclipse.angus</groupId>
    <artifactId>angus-activation</artifactId>
    <version>2.0.2</version>
    <scope>runtime</scope>
</dependency>

applicationContext.xml

<bean id="javaMailSession" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName" value="java:comp/env/mail/Session"/>
</bean>

<bean id="javaMailSenderImpl" class="org.springframework.mail.javamail.JavaMailSenderImpl">
    <property name="session" ref="javaMailSession"/>
</bean>

堆栈跟踪信息

Caused by: java.util.ServiceConfigurationError: jakarta.mail.util.StreamProvider: org.eclipse.angus.mail.util.MailStreamProvider not a subtype
at java.util.ServiceLoader.fail(ServiceLoader.java:593) ~[?:?]
at java.util.ServiceLoader$LazyClassPathLookupIterator.hasNextService(ServiceLoader.java:1244) ~[?:?]
at java.util.ServiceLoader$LazyClassPathLookupIterator.hasNext(ServiceLoader.java:1273) ~[?:?]
at java.util.ServiceLoader$2.hasNext(ServiceLoader.java:1309) ~[?:?]
at java.util.ServiceLoader$3.hasNext(ServiceLoader.java:1393) ~[?:?]
at jakarta.mail.util.FactoryFinder.factoryFromServiceLoader(FactoryFinder.java:161) ~[jakarta.mail-api-2.1.3.jar:?]
at jakarta.mail.util.FactoryFinder.find(FactoryFinder.java:75) ~[jakarta.mail-api-2.1.3.jar:?]
at jakarta.mail.util.FactoryFinder.find(FactoryFinder.java:40) ~[jakarta.mail-api-2.1.3.jar:?]
at jakarta.mail.util.StreamProvider.provider(StreamProvider.java:199) ~[jakarta.mail-api-2.1.3.jar:?]
at jakarta.mail.Session.<init>(Session.java:257) ~[jakarta.mail-api-2.1.3.jar:?]
at jakarta.mail.Session.getInstance(Session.java:310) ~[jakarta.mail-api-2.1.3.jar:?]
at org.apache.naming.factory.MailSessionFactory.getObjectInstance(MailSessionFactory.java:125) ~[catalina.jar:11.0.1]
at org.apache.naming.factory.FactoryBase.getObjectInstance(FactoryBase.java:88) ~[catalina.jar:11.0.1]
at javax.naming.spi.NamingManager.getObjectInstance(NamingManager.java:342) ~[?:?]
at org.apache.naming.NamingContext.lookup(NamingContext.java:544) ~[catalina.jar:11.0.1]
at org.apache.naming.NamingContext.lookup(NamingContext.java:148) ~[catalina.jar:11.0.1]
at org.apache.naming.NamingContext.lookup(NamingContext.java:530) ~[catalina.jar:11.0.1]
at org.apache.naming.NamingContext.lookup(NamingContext.java:148) ~[catalina.jar:11.0.1]
at org.apache.naming.NamingContext.lookup(NamingContext.java:530) ~[catalina.jar:11.0.1]
at org.apache.naming.NamingContext.lookup(NamingContext.java:148) ~[catalina.jar:11.0.1]
at org.apache.naming.NamingContext.lookup(NamingContext.java:530) ~[catalina.jar:11.0.1]
at org.apache.naming.NamingContext.lookup(NamingContext.java:155) ~[catalina.jar:11.0.1]
at org.apache.naming.SelectorContext.lookup(SelectorContext.java:144) ~[catalina.jar:11.0.1]
at javax.naming.InitialContext.lookup(InitialContext.java:409) ~[?:?]
at org.springframework.jndi.JndiTemplate.lambda$lookup$0(JndiTemplate.java:157) ~[spring-context-6.2.0.jar:6.2.0]
at org.springframework.jndi.JndiTemplate.execute(JndiTemplate.java:92) ~[spring-context-6.2.0.jar:6.2.0]
at org.springframework.jndi.JndiTemplate.lookup(JndiTemplate.java:157) ~[spring-context-6.2.0.jar:6.2.0]
at org.springframework.jndi.JndiTemplate.lookup(JndiTemplate.java:179) ~[spring-context-6.2.0.jar:6.2.0]
at org.springframework.jndi.JndiLocatorSupport.lookup(JndiLocatorSupport.java:96) ~[spring-context-6.2.0.jar:6.2.0]
at org.springframework.jndi.JndiObjectLocator.lookup(JndiObjectLocator.java:114) ~[spring-context-6.2.0.jar:6.2.0]
at org.springframework.jndi.JndiObjectFactoryBean.lookupWithFallback(JndiObjectFactoryBean.java:239) ~[spring-context-6.2.0.jar:6.2.0]
at org.springframework.jndi.JndiObjectFactoryBean.afterPropertiesSet(JndiObjectFactoryBean.java:225) ~[spring-context-6.2.0.jar:6.2.0]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1849) ~[spring-beans-6.2.0.jar:6.2.0]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1798) ~[spring-beans-6.2.0.jar:6.2.0]
... 53 more

解决方案

这个错误的核心是类加载器冲突:Tomcat的系统类加载器加载了Jakarta Mail API,而应用类加载器加载了Angus Mail的实现类,导致两者的StreamProvider接口不是同一个类实例。

1. 排除Tomcat自带的Jakarta Mail相关依赖

修改Tomcat的catalina.properties文件,添加以下配置,让Tomcat跳过扫描Jakarta Mail和Angus Mail的JAR包,避免系统类加载器加载它们:

tomcat.util.scan.StandardJarScanFilter.jarsToSkip=jakarta.mail-api*.jar,angus-mail*.jar,jakarta.activation-api*.jar,angus-activation*.jar

2. 统一依赖版本并清理重复依赖

运行mvn dependency:tree检查是否有其他依赖引入了旧版本的javax.mail或不兼容的Jakarta Mail版本,通过<exclusions>标签排除这些重复依赖。同时确保angus-mail与jakarta.mail-api版本兼容(当前使用的2.0.3与2.1.3是匹配的,可保留)。

3. 改用Spring直接配置Mail Session(可选)

如果上述步骤无效,可以放弃Tomcat JNDI创建Mail Session的方式,直接在Spring中配置:

<bean id="javaMailSenderImpl" class="org.springframework.mail.javamail.JavaMailSenderImpl">
    <property name="host" value="你的SMTP主机地址"/>
    <property name="port" value="25"/>
    <property name="username" value="user"/>
    <property name="from" value="email"/>
    <property name="javaMailProperties">
        <props>
            <prop key="mail.debug">true</prop>
        </props>
    </property>
</bean>

这种方式由应用类加载器完全控制Mail相关类的加载,彻底避免类加载器冲突。


内容的提问来源于stack exchange,提问作者Tyler Jaacks

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 19:54:54