当前位置: 首页 > 知识库问答 >
问题:

如何用嵌入式Tomcat容器在Spring Boot中创建JNDI上下文

邵麒
2023-03-14
import org.apache.catalina.Context;
import org.apache.catalina.deploy.ContextResource;
import org.apache.catalina.startup.Tomcat;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.context.embedded.tomcat.TomcatContextCustomizer;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;

@Configuration
@EnableAutoConfiguration
@ComponentScan
@ImportResource("classpath:applicationContext.xml")
public class Application {

    public static void main(String[] args) throws Exception {
        new SpringApplicationBuilder()
                .showBanner(false)
                .sources(Application.class)
                .run(args);
}

@Bean
public TomcatEmbeddedServletContainerFactory tomcatFactory() {
    return new TomcatEmbeddedServletContainerFactory() {
        @Override
        protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(
                Tomcat tomcat) {
            tomcat.enableNaming();
            return super.getTomcatEmbeddedServletContainer(tomcat);
        }
    };
}

@Bean
public EmbeddedServletContainerCustomizer embeddedServletContainerCustomizer() {
    return new EmbeddedServletContainerCustomizer() {
        @Override
        public void customize(ConfigurableEmbeddedServletContainer container) {
            if (container instanceof TomcatEmbeddedServletContainerFactory) {
                TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory = (TomcatEmbeddedServletContainerFactory) container;
                tomcatEmbeddedServletContainerFactory.addContextCustomizers(new TomcatContextCustomizer() {
                    @Override
                    public void customize(Context context) {
                        ContextResource mydatasource = new ContextResource();
                        mydatasource.setName("jdbc/mydatasource");
                        mydatasource.setAuth("Container");
                        mydatasource.setType("javax.sql.DataSource");
                        mydatasource.setScope("Sharable");
                        mydatasource.setProperty("driverClassName", "oracle.jdbc.driver.OracleDriver");
                        mydatasource.setProperty("url", "jdbc:oracle:thin:@mydomain.com:1522:myid");
                        mydatasource.setProperty("username", "myusername");
                        mydatasource.setProperty("password", "mypassword");

                        context.getNamingResources().addResource(mydatasource);

                    }
                });
            }
        }
    };
}

}

我正在使用spring boot,并尝试用一个为数据源创建JNDI上下文的嵌入式tomcat启动:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
        <version>1.1.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
        <version>1.1.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-oracle</artifactId>
        <version>1.0.0.RELEASE</version>
    </dependency>

如果删除@ImportResource,我的应用程序就可以正常启动。我可以连接到tomcat实例。我可以检查我所有的执行器endpoint。使用JConsole,我可以连接到应用程序,我可以在MBeans中看到我的数据源(Catalina->Resource->Context->“/”->LocalHost->javax.sql.datasource->jdbc/myDataSource)

我还通过JConsole在这里显示了MBeans(tomcat->datasource->/->localhost->javax.sql.datasource->jdbc/mydatasource)

但是,当我@ImportResource通过JNDI查找mydatasource时,它并没有找到mydatasource。

<bean id="myDS" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName" value="java:comp/env/jdbc/mydatasource"/>
</bean>

我导入的xml文件的相关部分

我在上面配置的ContextResource的参数与在将应用程序部署到tomcat容器时部署的context.xml中使用的参数完全相同。导入的bean和应用程序在部署到tomcat容器时工作正常。

所以我现在似乎有了上下文,但命名似乎不对。我尝试了资源名称的各种组合,但似乎无法生成在此上下文中绑定的“comp”。

Caused by: javax.naming.NameNotFoundException: Name [comp/env/jdbc/mydatasource] is not bound in this Context. Unable to find [comp].
    at org.apache.naming.NamingContext.lookup(NamingContext.java:819)
    at org.apache.naming.NamingContext.lookup(NamingContext.java:167)
    at org.apache.naming.SelectorContext.lookup(SelectorContext.java:156)
    at javax.naming.InitialContext.lookup(InitialContext.java:392)
    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.JndiObjectFactoryBean.lookupWithFallback(JndiObjectFactoryBean.java:231)
    at org.springframework.jndi.JndiObjectFactoryBean.afterPropertiesSet(JndiObjectFactoryBean.java:217)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1612)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1549)
    ... 30 more

共有1个答案

戚鸿福
2023-03-14

默认情况下,在嵌入式Tomcat中禁用JNDI,这会导致NoInitialContextException。您需要调用tomcat.enableNaming()来启用它。最简单的方法是使用TomcatEmbeddedServletContainer子类:

@Bean
public TomcatEmbeddedServletContainerFactory tomcatFactory() {
    return new TomcatEmbeddedServletContainerFactory() {

        @Override
        protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(
                Tomcat tomcat) {
            tomcat.enableNaming();
            return super.getTomcatEmbeddedServletContainer(tomcat);
        }
    };
}

如果采用这种方法,还可以通过在TomcatEmbeddedServletContainerFactory子类中重写PostProcessContext方法,在JNDI中注册DataSource

context.getnamingresources().addresource将资源添加到java:comp/env上下文中,因此资源的名称应该是jdbc/mydatasource,而不是java:comp/env/mydatasource

Tomcat使用线程上下文类加载器来确定应该对哪个JNDI上下文执行查找。您将资源绑定到web应用程序的JNDI上下文中,因此需要确保在web应用程序的类加载器是线程上下文类加载器时执行查找。通过在JNDIObjectFactoryBean上将LookuponStartup设置为False,您应该能够实现这一点。您还需要将ExpectedType设置为javax.sql.datasource:

<bean class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName" value="java:comp/env/jdbc/mydatasource"/>
    <property name="expectedType" value="javax.sql.DataSource"/>
    <property name="lookupOnStartup" value="false"/>
</bean>

这将为数据源创建一个代理,实际的JNDI查找在第一次使用时执行,而不是在应用程序上下文启动期间执行。

上面描述的方法在这个Spring Boot示例中进行了说明。

 类似资料:
  • 我有时会在pom中看到以下声明。xml。。。 如您所见,sping-boo-starter-web被声明为tomcat-embed-jasper。 是不是sping-boo-starter-web已经有一个嵌入式tomcat了?为什么一些开发人员仍然声明tomcat-embed-jasper以及boot-starter-web?还是有什么原因?

  • 我正在尝试部署一个java api,它基本上带有。docker容器中的war fie inside/tomcat/webapps/directory。我能够复制这本书。位于其中的Artifactory中的war文件。现在docker容器中的tomcat结构是:tomcat/webapps/api。war 问题是,在我将war文件复制到那里之后,我不知道java和tomcat是如何工作的,以便war

  • 我正试图在我的Grails3应用程序中结合一个JNDI配置,它使用嵌入式TomcatServlet容器以及独立的Tomcat容器(由我们的系统团队设置)。 我已经用这个SO问题让我的JNDI配置与嵌入式Tomcat容器一起工作(用于本地主机开发,例如grails run app)。 当我在Tomcat独立服务器上运行我的应用程序时(在构建war文件之后),在Tomcat服务器中使用JNDI配置,我

  • 关于我的问题的一些背景情况是,我们有一个tomcat应用程序在独立的tomcat中的“/context”下运行。我们让apache坐在前面,加密tomcat服务器上的通信量,并将“/”请求映射到“/context”。我刚刚对tomcat应用程序进行了重做,以便在spring Boot中运行。我们正在做的是使用spring boot构建一个包含原始war的可执行war文件。当我们执行新的war文件时

  • 我正在使用NetBeans IDE和带有Spring Boot的Maven。每当我运行我的应用程序不止一次,我就会得到这个错误: O.A.Coyote.http11.http11nioprotocol:无法启动与ProtocolHandler关联的终结点[“http-nio-8080”] spring boot java.lang.IllegalStateException:Tomcat连接器处于

  • 问题内容: 我讨厌问这样一个模糊的问题,但是我很难找到一个简单的例子。这是我到目前为止的内容: 我可以找到的嵌入式Jetty示例始终显示如下内容,以启动运行的Server实例,但我不知道如何实例化WebSocketServlet。 如何创建可以处理WebSocket连接请求的嵌入式服务器? 问题答案: 更新:2013年12月2日 有关带有WebSocket的嵌入式码头的最新示例,请参见: http