gpt4 book ai didi

java - Spring Boot - Tomcat JNDI 在服务 bean 中失败

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:12:10 27 4
gpt4 key购买 nike

我正在尝试在 Spring Boot 1.1.6 Web 项目中将数据源从 c3p0 切换到 Tomcat JNDI。我在 GitHub 中找到了示例应用程序,当从 @RestController 访问 DataSource 实例时工作正常注释类。

@RestController
public class TestController {

@Autowired
private DataSource dataSource;

@RequestMapping("/test")
@ResponseBody
public String test() {

// Gets object instance... everything is OK...
System.out.println(this.dataSource);
}

但是,当我尝试将相同的数据源注入(inject)到 @Service 时带注释的 bean,我得到 javax.naming.NameNotFoundException一旦在代码中使用实例。

@Service
public class TestService {

@Autowired
private DataSource dataSource;

@PostConstruct
private void init() {

// Throws exception...
System.out.println(this.dataSource);

}

堆栈跟踪:

Caused by: javax.naming.NameNotFoundException: Name [java:comp/env/jdbc/myDataSource] is not bound in this Context. Unable to find [java:comp].
at org.apache.naming.NamingContext.lookup(NamingContext.java:819)
at org.apache.naming.NamingContext.lookup(NamingContext.java:167)
at javax.naming.InitialContext.lookup(InitialContext.java:411)
at org.springframework.jndi.JndiTemplate$1.doInContext(JndiTemplate.java:155)
at org.springframework.jndi.JndiTemplate.execute(JndiTemplate.java:87)
at org.springframework.jndi.JndiTemplate.lookup(JndiTemplate.java:152)
at org.springframework.jndi.JndiTemplate.lookup(JndiTemplate.java:179)
at org.springframework.jndi.JndiLocatorSupport.lookup(JndiLocatorSupport.java:95)
at org.springframework.jndi.JndiObjectLocator.lookup(JndiObjectLocator.java:106)
at org.springframework.jndi.JndiObjectTargetSource.getTarget(JndiObjectTargetSource.java:135)
... 11 more

我想知道为什么不能从@Service 类访问JNDI 数据源bean?有什么想法吗?

最佳答案

实际问题是您试图在 PostConstruct 中获取数据源,而不是它在服务 bean 中失败。

默认情况下,Tomcat 使用线程上下文类加载器来确定应该针对哪个 JNDI 上下文执行查找。因此,当您将资源绑定(bind)到 Web 应用程序的 JNDI 上下文时,您需要确保在 Web 应用程序的类加载器(即 org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedWebappClassLoader) 是线程上下文类加载器。

以下是执行上述检查的 org.apache.naming.ContextBindings.getClassLoader 的代码片段:

/**
* Retrieves the naming context bound to a class loader.
*/
public static Context getClassLoader()
throws NamingException {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Context context = null;
do {
context = clBindings.get(cl);
if (context != null) {
return context;
}
} while ((cl = cl.getParent()) != null);
throw new NamingException
(sm.getString("contextBindings.noContextBoundToCL"));
}

因此,当代码在 PostConstruct 中并且您执行 JNDI 查找(这是在您访问对象时隐式完成的)时,线程上下文类加载器仍然是应用程序类加载器(即 sun.misc.Launcher$AppClassLoader).这就是 JNDI 无法找到对象的原因,因为它试图找到 java:comp/env/jdbc/myDataSource 命名上下文(即 javax.naming.Context) 来自 sun.misc.Launcher$AppClassLoader

您可以从 PostConstruct 移动代码,它应该可以正常工作。

交联另一个 related问题,这也提供了对该问题的更多见解。

我希望这能回答您的问题。

关于java - Spring Boot - Tomcat JNDI 在服务 bean 中失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26277985/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com