Docker运行Spring Boot应用时触发javax.naming.NameNotFoundException
解决Docker中Spring Boot应用的JNDI NameNotFound错误
咱们先把问题根源捋清楚:你本地运行完全正常,但Docker容器里一启动就报NameNotFound,核心原因是Spring Boot自带的内嵌Tomcat默认没开启JNDI支持。你本地能跑,大概率是部署到了外部Tomcat——外部Tomcat的context.xml里已经配置好了JNDI数据源绑定,但Docker里用的是内嵌Tomcat,它根本不知道你定义的jdbc/SubscriptionServicesDataSource在哪,自然就找不到了。
下面是具体的修复步骤:
1. 给内嵌Tomcat手动开启JNDI并绑定数据源
创建一个Tomcat配置类,用来启用JNDI并把你的数据库配置绑定到JNDI上下文里:
import org.apache.tomcat.util.descriptor.web.ContextResource; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jndi.JndiTemplate; import javax.naming.NamingException; import javax.sql.DataSource; @Configuration public class TomcatJndiConfig { @Bean public TomcatServletWebServerFactory tomcatFactory() { return new TomcatServletWebServerFactory() { @Override protected void postProcessContext(org.apache.catalina.Context context) { // 定义JNDI资源,对应你application.properties里的配置 ContextResource resource = new ContextResource(); resource.setName("jdbc/SubscriptionServicesDataSource"); resource.setType(DataSource.class.getName()); resource.setProperty("driverClassName", "oracle.jdbc.OracleDriver"); resource.setProperty("url", "jdbc:oracle:thin:@localhost:21521:webtst"); resource.setProperty("username", "xxxUnameXXX"); resource.setProperty("password", "xxxPassxxx"); resource.setProperty("factory", "org.apache.tomcat.jdbc.pool.DataSourceFactory"); resource.setProperty("initialSize", "1"); resource.setProperty("maxActive", "15"); // 把资源添加到Tomcat的命名上下文 context.getNamingResources().addResource(resource); } }; } // 把JNDI数据源注入到Spring容器中供业务使用 @Bean public DataSource subscriptionServicesDataSource() throws NamingException { return (DataSource) new JndiTemplate().lookup("java:comp/env/jdbc/SubscriptionServicesDataSource"); } }
2. 调整application.properties配置
现在我们已经通过配置类手动绑定了JNDI数据源,你可以把原来的database.datasources系列配置注释掉,或者保留但确保Spring优先使用我们配置类里的DataSource Bean——这样就不会再依赖原来的自定义数据源配置逻辑了。
3. 重新构建并运行Docker镜像
先重新打包构建镜像:
docker build -t it/spring-boot-docker-jdbc .
然后启动容器:
docker run -p 8080:8080 it/spring-boot-docker-jdbc
额外提醒
如果你的数据库是部署在宿主机(本地电脑)上,Docker容器里的localhost指的是容器自身,不是你的电脑。这种情况下,需要把数据库URL里的localhost换成宿主机的IP地址,或者在Docker Desktop环境下用host.docker.internal代替,否则容器会连不上数据库哦!
内容的提问来源于stack exchange,提问作者Itsik Mauyhas
相关产品推荐
相关产品推荐

