koe*_*koe 2 spring-boot embedded-tomcat-8
当我尝试使用Spring Boot和Spring Data JPA使用嵌入式Tomcat服务器的JNDI数据源时,在使用SpringApplication.run运行应用程序时出现以下错误消息:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.class]: Instantiation of bean failed;
nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration.entityManagerFactory(org.springframework.boot.autoconfigure.orm.jpa.EntityManagerFactoryBuilder)] threw exception;
nested exception is org.springframework.jndi.JndiLookupFailureException: JndiObjectTargetSource failed to obtain new target object;
nested exception is javax.naming.NameNotFoundException: Name [comp/env/jdbc/myDataSource] is not bound in this Context. Unable to find [comp].
Run Code Online (Sandbox Code Playgroud)
我使用如何在Spring Boot with Embedded Tomcat Container中创建JNDI上下文的解决方案中描述的配置
唯一的区别是对org.springframework.boot的额外Maven依赖:spring-boot-starter-data-jpa
这是一个示例项目:https://github.com/derkoe/spring-boot-sample-tomcat-jndi(这是解决方案中示例的修改版本).只需签出,构建并运行SampleTomcatJndiApplication.
看起来用于查找数据库连接的JNDI上下文不是来自webapp的上下文.这似乎是Spring上下文和Tomcat服务器初始化中的排序问题.
任何想法如何解决?
Tomcat使用线程的上下文类加载器来确定要执行查找的JNDI上下文.如果线程上下文类加载器不是Web应用程序类加载器,则JNDI上下文为空,因此查找失败.
问题是DataSource
在启动期间执行的JNDI查找正在主线程上执行,主线程的TCCL不是Tomcat的Web应用程序类加载器.您可以通过更新TomcatEmbeddedServletContainerFactory
bean来设置线程上下文类加载器来解决此问题.我还没有说服自己这不是一个可怕的黑客,但它的确有效......
这是更新的bean:
@Bean
public TomcatEmbeddedServletContainerFactory tomcatFactory() {
return new TomcatEmbeddedServletContainerFactory() {
@Override
protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(
Tomcat tomcat) {
tomcat.enableNaming();
TomcatEmbeddedServletContainer container =
super.getTomcatEmbeddedServletContainer(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;
}
@Override
protected void postProcessContext(Context context) {
ContextResource resource = new ContextResource();
resource.setName("jdbc/myDataSource");
resource.setType(DataSource.class.getName());
resource.setProperty("driverClassName", "your.db.Driver");
resource.setProperty("url", "jdbc:yourDb");
context.getNamingResources().addResource(resource);
}
};
}
Run Code Online (Sandbox Code Playgroud)
getEmbeddedServletContainer
提取上下文的类加载器并将其设置为当前线程的上下文类加载器.这在调用super方法后发生.这种排序很重要,因为对super方法的调用创建并启动容器,并且作为该创建的一部分,创建上下文的类加载器.
归档时间: |
|
查看次数: |
6836 次 |
最近记录: |