이 포스트는 Spring boot + Mybatis 를 전제하고 있습니다.
스프링부트를 이용하면서 다른 종류의 DB를 동시에 사용해야하는 경우가 종종 있습니다.
그런데 이번엔 JNDI 환경까지 겹치면서 1번 DB는 Tomcat (jdbc pool) Datasource 를 사용하고 2번 DB는 JNDI를 이용해야 하는 이런 상황이 되었습니다.
여기에 멈추지 않고 Local 개발환경에서 JNDI 를 사용하기는 또 부담스럽고 귀찮으니 Tomcat embedded JNDI 도 사용해봤습니다.
보너스로 @Profile 을 이용해서 마음대로 각 DB에서 설정에 따라 자유롭게 Datasource 를 골라 쓸 수 있게 해보았습니다.
import javax.naming.NamingException; import javax.sql.DataSource; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.SqlSessionTemplate; import org.mybatis.spring.annotation.MapperScan; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Profile; import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup; @Configuration @MapperScan(value = Constants.PACKAGE_BASE + ".dao", sqlSessionFactoryRef = "coreSqlSessionFactory") public class CoreRepositoryConfig { @Bean @ConfigurationProperties(prefix = "spring.datasource.primary") public JndiPropertyHolder getJndiPropertyHolder() { return new JndiPropertyHolder(); } @Primary @Bean("coreDatasource") @Profile("jndi") public DataSource jndiDatasource() throws IllegalArgumentException, NamingException { String jndiName = getJndiPropertyHolder().getJndiName(); return (DataSource) new JndiDataSourceLookup().getDataSource(jndiName); } @Primary @Bean("coreDatasource") @Profile("!jndi") @ConfigurationProperties(prefix = "primary.spring.datasource") public org.apache.tomcat.jdbc.pool.DataSource coreDatasource() { return (org.apache.tomcat.jdbc.pool.DataSource) DataSourceBuilder.create() .type(org.apache.tomcat.jdbc.pool.DataSource.class).build(); } @Bean(name = "coreSqlSessionFactory") @Primary public SqlSessionFactory coreSqlSessionFactory(@Qualifier("coreDatasource") DataSource coreDatasource, ApplicationContext applicationContext) throws Exception { SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); sqlSessionFactoryBean.setDataSource(coreDatasource); sqlSessionFactoryBean.setConfigLocation(applicationContext.getResource("classpath:mybatis/config.xml")); return sqlSessionFactoryBean.getObject(); } @Bean(name = "coreSqlSessionTemplate") @Primary public SqlSessionTemplate coreSqlSessionTemplate(SqlSessionFactory coreSqlSessionFactory) throws Exception { return new SqlSessionTemplate(coreSqlSessionFactory); } class JndiPropertyHolder { private String jndiName; public String getJndiName() { return jndiName; } public void setJndiName(String jndiName) { this.jndiName = jndiName; } } } |
<CoreRepositoryConfig.java>
1번 DB의 Java Config 파일이라고 보시면 되겠습니다.
import org.apache.ibatis.session.SqlSessionFactory; import org.apache.tomcat.jdbc.pool.DataSource; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.SqlSessionTemplate; import org.mybatis.spring.annotation.MapperScan; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration @MapperScan(value = Constants.PACKAGE_BASE + ".secondary.dao", sqlSessionFactoryRef = "secondarySqlSessionFactory") public class SecondaryRepositoryConfig { @Bean("secondaryDatasource") @ConfigurationProperties(prefix = "secondary.spring.datasource") public DataSource secondaryDatasource() { return (DataSource) DataSourceBuilder.create().type(DataSource.class).build(); } @Bean(name = "secondarySqlSessionFactory") public SqlSessionFactory secondarySqlSessionFactory(@Qualifier("secondaryDatasource") DataSource secondaryDatasource, ApplicationContext applicationContext) throws Exception { SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); sqlSessionFactoryBean.setDataSource(secondaryDatasource); sqlSessionFactoryBean.setConfigLocation(applicationContext.getResource("classpath:secondary/mybatis-config.xml")); return sqlSessionFactoryBean.getObject(); } @Bean(name = "secondarySqlSessionTemplate") public SqlSessionTemplate secondarySqlSessionTemplate(SqlSessionFactory secondarySqlSessionFactory) throws Exception { return new SqlSessionTemplate(secondarySqlSessionFactory); } } |
<SecondaryRepositoryConfig.java>
SecondaryRepositoryConfig.java 는 2번 DB의 Java Config 입니다.
spring.profiles.active=local,jndi spring.datasource.primary.jndi-name=MYJNDI secondary.spring.datasource.driverClassName=oracle.jdbc.driver.OracleDriver secondary.spring.datasource.url=jdbc:oracle:thin:@IP:PORT:DB secondary.spring.datasource.username=아뒤 secondary.spring.datasource.password=패쓰워드 secondary.spring.datasource.max-active=1 secondary.spring.datasource.max-idle=1 secondary.spring.datasource.min-idle=1 secondary.spring.datasource.max-wait=-1 secondary.spring.datasource.initial-size=1 secondary.spring.datasource.test-on-borrow=true secondary.spring.datasource.test-while-idle=true secondary.spring.datasource.validation-query=select 'SECONDARY' from dual secondary.spring.datasource.time-between-eviction-runs-millis=300000 |
<application.properties>
이 녀석은 Spring Boot 의 설정파일인 application.properties 입니다.
CoreRepositoryConfig.java 에서만 JNDI 혹은 Tomcat Datasouce를 쓸건지 선택할 수 있도록 되어있는데 이부분은 application.properties 의 설정중에
spring.profiles.active 에 jndi가 포함되어 있느냐 없느냐를 @Profile("jndi") or @Profile("!jndi") 로 구분해서 선택적으로 Datasource를 제공하고 있습니다.
JNDI 의 이름은 @ConfigurationProperties(prefix = "spring.datasource.primary") 를 이용해
application.properties 의 spring.datasource.primary.jndi-name=MYJNDI 에서 획득하고 있습니다.
만약 1번 DB에서 JNDI 를 사용하지 않으려면 spring.profiles.active에서 jndi 를 지우고 2번 DB 설정처럼 primary.spring.datasource 설정들을 지정하면 됩니다.
그리고 2번 DB의 사용은 @ConfigurationProperties(prefix = "secondary.spring.datasource") 을 이용해 application.properties 에서 db설정 정보를 가져와
Tomcat datasource를 사용하고 있습니다.
마지막으로 Local 환경에서도 JNDI 로 테스트하기 위해 Embedded Tomcat JNDI를 이용해 보겠습니다.
import javax.sql.DataSource; import org.apache.catalina.Context; import org.apache.catalina.startup.Tomcat; import org.apache.tomcat.util.descriptor.web.ContextResource; import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer; import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; @Configuration @Profile({ "local", "dev" }) public class TomcatEmbdded { @Bean public TomcatEmbeddedServletContainerFactory tomcatFactory() { return new TomcatEmbeddedServletContainerFactory() { @Override protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(Tomcat tomcat) { tomcat.enableNaming(); return super.getTomcatEmbeddedServletContainer(tomcat); } @Override protected void postProcessContext(Context context) { ContextResource resource = new ContextResource(); resource.setName("JNDI이름"); resource.setType(DataSource.class.getName()); resource.setProperty("driverClassName", "oracle.jdbc.driver.OracleDriver"); resource.setProperty("url", "jdbc:oracle:thin:@IP:PORT:DB"); resource.setProperty("username", "아뒤"); resource.setProperty("password", "패쓔워드"); resource.setProperty("factory", "org.apache.tomcat.jdbc.pool.DataSourceFactory"); resource.setProperty("type", "javax.sql.DataSource"); context.getNamingResources().addResource(resource); } }; } } |
<TomcatEmbdded.java - 오타가 ..>
@Profile({ "local", "dev" }) 를 통해서 spring.profiles.active 에 local 이나 dev 가 포함되어 있다면 Embedded Tomcat JNDI 를 사용할 수 있게 됩니다.
maven dependency
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> |
@ConfigurationProperties 를 사용하기 위해 필요합니다.
org.apache.tomcat.jdbc.pool.DataSourceFactory 를 사용하기 위해선 tomcat-jdbc 가 필요한데
저같은 경우 mybatis-spring-boot-starter (mybatis-spring-boot-starter > spring-boot-starter-jdbc > tomcat-jdbc ) 에 포함된 걸 이용하고 있습니다.
'java' 카테고리의 다른 글
spring boot 2.0 default connection pool (2) | 2018.07.25 |
---|---|
fasterxml json parsing uppsercase (0) | 2018.07.24 |
spring resttemplate httpclient connection pool (0) | 2018.07.24 |
jackson fasterxml custom filter (exclude, masking) (0) | 2018.07.18 |
JNDI TEST (0) | 2018.07.09 |
fasterxml json camelcase (2) | 2018.06.18 |
spring jdbc sample (0) | 2018.06.04 |
spring boot logback.xml file rolling example 스프링부트 logback.xml 파일 롤링 예제 (0) | 2018.05.17 |