Spring boot uses JNDI data sources

More of my articles can be found at: https://zhangzw.com/

Recently, a new project is going to use SpringBoot, because the development configuration of SpringBoot is simpler. However, due to the company's deployment process, the test and production environment needs to print the code as a WAR package and deploy it under tomcat, and the database connection uses the JNDI data source mode to configure Tomcat.

There is no problem with this deployment method, but in the local environment, when we start spring boot in main mode, we encounter problems. Because Tomcat is embedded in spring boot in kernel mode, how to configure JNDI data source?

Using JNDI data source in SpringBoot is very simple. You only need to configure it in the application.properties file, for example:

# JNDI data source. The development environment is configured in the code, and the testing and production are configured in the container.
spring.datasource.jndi-name=java:comp/env/jdbc/timcore/DefaultDS

To test and generate the environment and deploy it in Tomcat in the form of WAR package, you need to add configuration in the conf/context.xml file of tomcat, such as:

<Resource
    name="jdbc/testcore/DefaultDS"
    url="jdbc:postgresql://30.31.0.14:7523/test"
    username="timcopr"
    password="123456"
    type="javax.sql.DataSource"
    auth="Container"
    driverClassName="org.postgresql.Driver" 
    maxIdle="30"
    maxWait="10000"
    maxActive="100"
/>

The Tomcat kernel needs to be modified to start locally in main mode, open JNDI data source and configure. For example, if our project is started in main mode in dev environment, we need to:

1. Add the application-dev.properties file:

# DEV environment will load
DataSource.jndiName=jdbc/testcore/DefaultDS
DataSource.auth=Container
DataSource.driverClassName=org.postgresql.Driver
DataSource.url=jdbc:postgresql://30.31.0.14:7523/test
DataSource.username=timcopr
DataSource.pwd=123456
DataSource.maxActive=100
DataSource.maxIdle=30
DataSource.maxWait=10000

2. Create a PropConfig class to receive the configuration:

@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. Modify the configuration in code mode and add data source:

@Configuration
public class MyWebMvcConfigurerAdapter extends WebMvcConfigurerAdapter {
    
    @Resource
    private DataSourcePropConfig dataSourcePropConfig;
    
    // The development environment adds data sources manually. The test and production environment is deployed in the container, and the data source is configured in the container.
    @ConditionalOnProperty(name = "spring.profiles.active", havingValue = "dev") 
    @Bean
    public TomcatEmbeddedServletContainerFactory servletContainerFactory() {
        return new TomcatEmbeddedServletContainerFactory() {
            @Override
            protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(Tomcat tomcat) {
                tomcat.enableNaming(); // Open JNDI data source
                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());
                // The connection pool configuration is consistent with the test and production configurations.
                resource.setProperty("maxActive", dataSourcePropConfig.getMaxActive()); // maximum connection
                resource.setProperty("maxIdle", dataSourcePropConfig.getMaxIdle()); // Number of idle connections
                resource.setProperty("maxWait", dataSourcePropConfig.getMaxWait()); // Maximum waiting time
                context.getNamingResources().addResource(resource);
            }
        };
    }
}

In this way, the same code can be compatible with two ways.

Tags: Tomcat JDBC Spring PostgreSQL

Posted on Sat, 02 Nov 2019 08:52:51 -0700 by dacio