运行 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 的容器中,请执行以下操作;
- 扩展
TomcatEmbeddedServletContainerFactory
并启用jndi命名并添加资源
- 创建一个配置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");
我有一个带有 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 的容器中,请执行以下操作;
- 扩展
TomcatEmbeddedServletContainerFactory
并启用jndi命名并添加资源 - 创建一个配置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");