运行 Spring 带有嵌入式容器和 JNDI 的引导应用程序

Run a Spring Boot app with embedded container and JNDI

我有一个带有 spring.datasource.jndi-name=java:/foo 属性 的 Spring 启动应用程序,它在 WildFly 下运行良好。

我想 运行 具有嵌入式容器的同一个应用程序,即 mvn spring-boot:run,但是虽然 WildFly 在其配置中配置了 JNDI 数据源,但嵌入式容器没有,即我'得到:

org.springframework.jdbc.datasource.lookup.DataSourceLookupFailureException:
Failed to look up JNDI DataSource with name 'java:/foo'

我想我必须在某处包含一个 XML 文件来为嵌入式容器配置 JNDI 数据源,但我找不到关于此的文档。我刚刚在 Java 源代码中找到了关于如何创建 JNDI 数据源的教程,但我想避免这种情况,以便同一个应用程序可以 运行 在外部和嵌入式容器中。

我怎样才能做到这一点?

EDIT This answer 展示了如何在 Tomcat 中创建 JNDI 上下文,这种方式会破坏 运行 在其他容器(例如 WildFly)。我正在寻找一个答案,让应用 运行 在不同的容器中具有相同的来源,例如只需使用在 WildFly 中配置的相同 JNDI 资源配置嵌入式容器。

要使该应用程序也可部署在其他启用 jndi 的容器中,请执行以下操作;

  1. 扩展TomcatEmbeddedServletContainerFactory并启用jndi命名并添加资源
  2. 创建一个配置class,配置文件注解公开扩展的TomcatEmbeddedServletContainerFactory bean

见下面的代码;

扩展 TomcatEmbeddedServletContainerFactory

class EmbeddedServletContainerFactory extends TomcatEmbeddedServletContainerFactory {
    @Override
    protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(Tomcat tomcat) {
        tomcat.enableNaming(); // This is essential. Naming is disabled by default which needs enabling
        return super.getTomcatEmbeddedServletContainer(tomcat);
    }

    @Override
    protected void postProcessContext(Context context) {
        ContextResource resource = new ContextResource();
        // All the below properties you can retrieve via preferred method
        resource.setName("jdbc/test");
        resource.setAuth("Container");
        resource.setType(DataSource.class.getName());
        resource.setProperty("driverClassName", driverClass);
        resource.setProperty("factory", "org.apache.commons.dbcp2.BasicDataSourceFactory");
        resource.setProperty("url", dbUrl);
        resource.setProperty("username", username);
        resource.setProperty("password", password);
        context.getNamingResources().addResource(resource);
    }
}

配置class暴露bean

@Profile("embedded")
@Configuration
public class EmbeddedConfig {

    @Bean
    public TomcatEmbeddedServletContainerFactory tomcatFactory() {
        return new EmbeddedServletContainerFactory();
    }
}

如果你不喜欢 java 配置中的这个,你可以在 xml 中做同样的事情

<beans profile="embedded">
    <bean id="TomcatEmbeddedServletContainerFactory" class="EmbeddedServletContainerFactory" />
</bean>

现在您可以在 pom 中硬编码配置文件名称或通过 jvm 参数添加它;

mvn spring-boot:run -Drun.profiles=embedded

您的其他代码保持不变,并且在其他容器中的行为也相同。通过 jndi 查找数据源也保持不变。此代码确保实际上有一个数据源绑定到嵌入式容器中的那个 jndi。

@Setu 的回答对我不起作用,因为 TomcatEmbeddedServletContainerFactory 是在 ApplicationContext 刷新后创建的,但我需要 JNDI 在 ApplicationContext 刷新期间可用。

相反,我在启动 Spring 引导应用程序之前设置了以下系统属性以启用 Tomcat 命名:

System.setProperty(Context.URL_PKG_PREFIXES, "org.apache.naming");
System.setProperty(Context.INITIAL_CONTEXT_FACTORY,
                   "org.apache.naming.java.javaURLContextFactory");