Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Boot 2 Embedded Tomcat Jndi Datasource Configuration

Good morning in my timezone

I already have follow this two Stack Overflow questions :

Spring Boot Using Embedded Tomcat with JNDI

and

Howto use JNDI database connection with Spring Boot and Spring Data using embedded Tomcat?

And none have worked. I am using Spring Boot 2. I want to configure embedded Tomcat Server to work with JNDI. I have try to approaches :

Snippet of code :

 @SpringBootApplication 
   public class MyApplication {

    public static void main ...


    @Bean   
   public ServletWebServerFactory servletContainer() {      TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {


     @Override          
     protected void postProcessContext(Context context) {
                    ContextResource resource = new ContextResource();
                    resource.setName("jdbc/CCC");
                    resource.setType(DataSource.class.getName());
                    resource.setProperty("driverClassName", "oracle.jdbc.driver.OracleDriver");
                    resource.setProperty("url", "jdbc:oracle:thin:@a77k11111188.tt.ddd.test:3000:BHJR00TT00");
                    resource.setProperty("username", "user");
                    resource.setProperty("password", "pass");
                    context.getNamingResources().addResource(resource);             }

     @Override          
    protected TomcatWebServer getTomcatWebServer(Tomcat tomcat){
                    tomcat.enableNaming();
                    TomcatWebServer container =  super.getTomcatWebServer(tomcat);
                    for(Container child  :container.getTomcat().getHost().findChildren()){
                        if (child instanceof Context) {
                            ClassLoader contextClassLoader = ((Context)child).getLoader().getClassLoader();
                            Thread.currentThread().setContextClassLoader(contextClassLoader);
                            break;
                        }
                    }
                    return container;           }

            };      return tomcat;

An then use the application.properties

spring.datasource.jndi-name=java:comp/env/jdbc/CCC

Error log: Unable to start embedded Tomcat
Error creating bean with name 'servletEndpointRegistrar'
Error creating bean with name 'dataSource' DataSourceLookupFailureException: Failed to look up JNDI DataSource with name 'java:comp/env/jdbc/CCC'
.NamingException: Could not create resource factory instance

ClassNotFoundException: org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory

Instead if i not use the application properties and i configure the datasource bean directly in the Spring Boot Application like this

@Bean(destroyMethod = "")
    public DataSource jndiDataSource() throws IllegalArgumentException, NamingException {
        JndiObjectFactoryBean bean = new JndiObjectFactoryBean();
        bean.setJndiName("java:comp/env/jdbc/CCC");
        bean.setProxyInterface(DataSource.class);
        bean.setLookupOnStartup(false);
        bean.afterPropertiesSet();
        return (DataSource) bean.getObject();
    } 

The error log
UnsatisfiedDependencyException: Error creating bean with name 'entityManagerFactory'
BeanCreationException: Error creating bean with name 'jpaVendorAdapter'

JndiLookupFailureException: JndiObjectTargetSource failed to obtain new target object
NamingException: Could not create resource factory instance

In my pom i have the following dependecies

 <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
  </dependency>
  <dependency>
     <groupId>com.oracle</groupId>
     <artifactId>ojdbc7</artifactId>
     <version>12.1.0.2</version>
   </dependency>
 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-web</artifactId>
  </dependency>  

I am out of solutions Thanks in advance Best regards

like image 586
tt0686 Avatar asked Sep 28 '18 10:09

tt0686


People also ask

Is JNDI used in Spring?

JPA Configuration – Model, DAO and Service. With this, you have everything you need in order to use your JNDI datasource in your Spring application.

How do you configure a DataSource in Spring?

To configure your own DataSource , define a @Bean of that type in your configuration. Spring Boot reuses your DataSource anywhere one is required, including database initialization. If you need to externalize some settings, you can bind your DataSource to the environment (see “Section 25.8.


1 Answers

I was also facing the same issue and most of the example on internet was using TomcatEmbeddedServletContainerFactory however after trying several things finally i was able to get jndi connection in my application.

I am still figuring out exact root cause of the problem but following is the code for your reference.

@SpringBootApplication
public class MybatisJNDISampleApplication {
    public static void main(String[] args) {
        SpringApplication.run(MybatisJNDISampleApplication.class, args);
    }

    @Bean
    public TomcatServletWebServerFactory tomcatFactory() {
        return new TomcatServletWebServerFactory() {
            @Override
            protected TomcatWebServer getTomcatWebServer(org.apache.catalina.startup.Tomcat tomcat) {
                tomcat.enableNaming();
                return super.getTomcatWebServer(tomcat);
            }

            @Override
            protected void postProcessContext(Context context) {
                ContextResource resource = new ContextResource();           
                //resource.setProperty("factory", "org.apache.tomcat.jdbc.pool.DataSourceFactory");
                resource.setName("jdbc/myDatasourceName");
                resource.setType(DataSource.class.getName());
                resource.setProperty("driverClassName", "oracle.jdbc.OracleDriver");
                resource.setProperty("url", "db_url");
                resource.setProperty("username", "db_username");
                resource.setProperty("password", "db_password");
                context.getNamingResources().addResource(resource);
            }
        };
    }
}

Following is my configuration class :

@Configuration
@MapperScan("com.sample.mybatis")
public class DataConfig {

    public final String MAPPER_LOCATIONS_PATH = "classpath:mybatis-mappers/*.xml";

    @Bean(destroyMethod="")
    public DataSource dataSource() throws IllegalArgumentException, NamingException {
        JndiObjectFactoryBean bean = new JndiObjectFactoryBean();
        bean.setJndiName("java:comp/env/jdbc/myDatasourceName");
        //bean.setResourceRef(true); // this was previously uncommented
        bean.setProxyInterface(DataSource.class);
        //bean.setLookupOnStartup(false); // this was previously uncommented
        bean.afterPropertiesSet();
        return (DataSource)bean.getObject();
    }

    @Bean
    public DataSourceTransactionManager transactionManager() throws NamingException {
        return new DataSourceTransactionManager(dataSource());
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        configureSqlSessionFactory(sessionFactory, dataSource());
        return sessionFactory.getObject();
    }

    public void configureSqlSessionFactory(SqlSessionFactoryBean sessionFactoryBean, DataSource dataSource) throws IOException {
        PathMatchingResourcePatternResolver pathResolver = new PathMatchingResourcePatternResolver();
        sessionFactoryBean.setDataSource(dataSource);
        sessionFactoryBean.setMapperLocations(pathResolver.getResources(MAPPER_LOCATIONS_PATH));
    }
}

Hope this helps you to resolve your issue.

like image 174
Atul Nar Avatar answered Sep 20 '22 11:09

Atul Nar