SpringBoot使用JNDI数据源

6,413 阅读2分钟

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

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

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

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

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

<Resource
    name="jdbc/timcore/DefaultDS"
    url="jdbc:postgresql://30.31.0.14:7523/timc"
    username="timcopr"
    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文件:

# DEV环境才会加载
DataSource.jndiName=jdbc/timcore/DefaultDS
DataSource.auth=Container
DataSource.driverClassName=org.postgresql.Driver
DataSource.url=jdbc:postgresql://30.31.0.14:7523/timc
DataSource.username=timcopr
DataSource.pwd=123456
DataSource.maxActive=100
DataSource.maxIdle=30
DataSource.maxWait=10000

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

@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,代码的方式修改配置,加入数据源:

@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) {
                ContextResource resource = new ContextResource();
                resource.setType(DataSource.class.getName());
                resource.setName(dataSourcePropConfig.getJndiName());
                resource.setAuth(dataSourcePropConfig.getAuth());
                resource.setProperty("driverClassName", dataSourcePropConfig.getDriverClassName());
                resource.setProperty("url", dataSourcePropConfig.getUrl());
                resource.setProperty("username", dataSourcePropConfig.getUsername());
                resource.setProperty("password", dataSourcePropConfig.getPwd());
                // 连接池配置,和测试、生产配置一致。
                resource.setProperty("maxActive", dataSourcePropConfig.getMaxActive()); // 最大连接数
                resource.setProperty("maxIdle", dataSourcePropConfig.getMaxIdle()); // 空闲连接数
                resource.setProperty("maxWait", dataSourcePropConfig.getMaxWait()); // 最大等待时间
                context.getNamingResources().addResource(resource);
            }
        };
    }
}

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