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

我与影子孤独终老i 提交于 2019-11-27 23:23:04

Tomcat uses the thread's context class loader to determine the JNDI context to perform the lookup against. If the thread context class loader isn't the web app classloader then the JNDI context is empty, hence the lookup failure.

The problem is that the JNDI lookup of the DataSource that's performed during startup is being performed on the main thread and the main thread's TCCL isn't Tomcat's web app classloader. You can work around this by updating your TomcatEmbeddedServletContainerFactory bean to set the thread context class loader. I've yet to convince myself that this isn't a horrible hack, but it works…

Here's the updated 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);
        }
    };
}

getEmbeddedServletContainer extracts the context's classloader and set it as the current thread's context class loader. This happens` after the call to the super method. This ordering is important as the call to the super method creates and starts the container and, as a part of that creation, creates the context's class loader.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!