配置 SpringBoot 使用 JNDI 数据源

最近一个新项目准备使用 SpringBoot,因为 SpringBoot 开发配置简单些。但由于公司部署流程的原因,测试和生产环境需要将代码打成 WAR 包部署到 Tomcat 下,并且数据库连接使用 JNDI 数据源方式配置 Tomcat 里面。

这种部署方式本没有问题,但是在本地环境我们用 main 方式启动的 SpringBoot 时就遇到问题,由于 Tomcat 是以内核的方式嵌入在 SpringBoot 里面的,那怎样配置 JNDI 数据源呢?

SpringBoot 里使用 JNDI 数据源很简单,只需在 application.properties 文件中配置一下就可以了,如:

1
2
# JNDI 数据源。开发环境在代码中配置,测试、生产在容器中配置。
spring.datasource.jndi-name=java:comp/env/jdbc/testcore/DefaultDS

测试和生成环境,以 WAR 包方式部署在 Tomcat 里的情况,需要在 Tomcat 的 conf/context.xml 文件添加配置,如:

1
2
3
4
5
6
7
8
9
10
11
12
<Resource
name="jdbc/testcore/DefaultDS"
url="jdbc:postgresql://127.0.0.1:7523/test"
username="root"
password="123456"
type="javax.sql.DataSource"
auth="Container"
driverClassName="org.postgresql.Driver"
maxIdle="30"
maxWait="10000"
maxActive="100"
/>

本地以 main 方式启动的需要修改 Tomcat 内核,打开 JNDI 数据源,并配置。比如我们项目是 dev 环境才是 Main 方式启动,则需要:

1,新增 application-dev.properties 文件:

1
2
3
4
5
6
7
8
9
10
# DEV 环境才会加载
DataSource.jndiName=jdbc/testcore/DefaultDS
DataSource.auth=Container
DataSource.driverClassName=org.postgresql.Driver
DataSource.url=jdbc:postgresql://127.0.0.1:7523/test
DataSource.username=root
DataSource.pwd=123456
DataSource.maxActive=100
DataSource.maxIdle=30
DataSource.maxWait=10000

2,创建一个 PropConfig 类,接收配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Getter
@Setter
@Component
@ConfigurationProperties(prefix = "DataSource")
public class DataSourcePropConfig {
private String jndiName;
private String auth;
private String driverClassName;
private String url;
private String username;
private String pwd;
private String maxActive;
private String maxIdle;
private String maxWait;
}

3,代码的方式修改配置,加入数据源:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@Configuration
public class MyWebMvcConfigurerAdapter extends WebMvcConfigurerAdapter {

@Resource
private DataSourcePropConfig dataSourcePropConfig;

// 开发环境手工添加数据源。测试、生产环境部署在容器中,在容器中配置数据源。
@ConditionalOnProperty(name = "spring.profiles.active", havingValue = "dev")
@Bean
public TomcatEmbeddedServletContainerFactory servletContainerFactory() {
return new TomcatEmbeddedServletContainerFactory() {
@Override
protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(Tomcat tomcat) {
tomcat.enableNaming(); // 打开 JNDI 数据源
return super.getTomcatEmbeddedServletContainer(tomcat);
}

@Override
protected void postProcessContext(Context context) {
context.getNamingResources().addResource(initDBNamingResource());
}
};

// JNDI 数据源
private ContextResource initDBNamingResource() {
ContextResource resource = new ContextResource();
resource.setType(DataSource.class.getName());
resource.setProperty("driverClassName", "org.postgresql.Driver");
resource.setProperty("url", "jdbc:postgresql://127.0.0.1:7523/test");
resource.setProperty("username", "root");
resource.setProperty("pwaaword", "123456");
// 其它 property 设置。。。
return resource;
}
}
}

这样同一份代码就可以兼容两种方式了。

SpringBoot2.x 版本配置差异

以上是基于 SpringBoot1.5.8 版本,代码中配置 JNDI 数据源 SpringBoot2.x 版本与 1.x 版本稍微有点差别,具体可参考:项目从 SpringBoot1.5.X 升级到 SpringBoot2.2 踩坑记录