Spring Boot 2 嵌入式 Tomcat Jndi 数据源配置

5

在我的时区早上好

我已经按照以下两个Stack Overflow问题进行了操作:

Spring Boot使用带有JNDI的嵌入式Tomcat

如何在Spring Boot和Spring Data中使用JNDI数据库连接,使用嵌入式Tomcat?

但是都没有起作用。 我正在使用Spring Boot 2。 我想配置嵌入式Tomcat服务器以与JNDI一起工作。 我已经尝试了两种方法:

代码片段:

@SpringBootApplication
public class MyApplication {

    public static void main(String... args) { }

    @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;
    }
}

然后使用application.properties

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

错误日志:
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

如果我不使用应用程序属性,而是直接在Spring Boot应用程序中配置数据源bean,就像这样:

@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();
    } 

错误日志如下:
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

在我的pom文件中,我有以下依赖项

<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>  

我已经没有办法了。 提前感谢。 最好的祝福。
1个回答

6

我曾经遇到同样的问题,互联网上的大多数示例都使用TomcatEmbeddedServletContainerFactory,但是经过尝试几件事情,最终我能够在我的应用程序中获得JNDI连接。

我仍在找出问题的确切根本原因,但以下是您参考的代码。

@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));
    }
}

希望这能帮助你解决问题。

1
通常情况下,我们使用JNDI配置来避免在一般的源代码中暴露数据库配置细节。您建议只在应用程序启动文件中进行配置。在这种情况下,在application.properties文件中配置DB连接信息会有什么区别? - Nallamachu
我们需要添加任何依赖项来解决 SqlSessionFactorySqlSessionFactoryBean 吗? - Ayush Kumar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接