配置使用外部Tomcat 9服务器的JNDI数据源:Spring Boot

huangapple go评论78阅读模式
英文:

Configure DataSource Using JNDI Using external Tomcat 9 Server: Spring Boot

问题

我有一个打包为WAR文件的SpringBootApplication:

@SpringBootApplication(exclude = {SecurityAutoConfiguration.class})
public class Application extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
    
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }

}

application.properties文件中:

spring.datasource.jndi-name=java:comp/env/jdbc/bonanza

但是当我在Tomcat 9中部署WAR文件时,日志中出现以下消息:

名称[spring.datasource.jndi-name]未绑定到此上下文。无法找到[spring.datasource.jndi-name]。返回null。

日志:

12:37:53.989 [main] DEBUG o.springframework.jndi.JndiTemplate - 使用名称[java:comp/env/spring.datasource.jndi-name]查找JNDI对象
12:37:53.989 [main] DEBUG o.s.jndi.JndiLocatorDelegate - 转换后的JNDI名称[java:comp/env/spring.datasource.jndi-name]未找到 - 尝试原始名称[spring.datasource.jndi-name]。javax.naming.NameNotFoundException: 名称[spring.datasource.jndi-name]未在此上下文中绑定。无法找到[spring.datasource.jndi-name]。
12:37:53.990 [main] DEBUG o.springframework.jndi.JndiTemplate - 使用名称[spring.datasource.jndi-name]查找JNDI对象
12:37:53.991 [main] DEBUG o.s.jndi.JndiPropertySource - 对名称[spring.datasource.jndi-name]进行JNDI查找,抛出带有消息的NamingException:名称[spring.datasource.jndi-name]未在此上下文中绑定。无法找到[spring.datasource.jndi-name]。返回null。
12:37:53.995 [main] DEBUG o.springframework.jndi.JndiTemplate - 使用名称[java:comp/env/spring.datasource.jndi-name]查找JNDI对象
12:37:53.996 [main] DEBUG o.s.jndi.JndiLocatorDelegate - 转换后的JNDI名称[java:comp/env/spring.datasource.jndi-name]未找到 - 尝试原始名称[spring.datasource.jndi-name]。javax.naming.NameNotFoundException: 名称[spring.datasource.jndi-name]未在此上下文中绑定。无法找到[spring.datasource.jndi-name]。
12:37:53.996 [main] DEBUG o.springframework.jndi.JndiTemplate - 使用名称[spring.datasource.jndi-name]查找JNDI对象
12:37:53.997 [main] DEBUG o.s.jndi.JndiPropertySource - 对名称[spring.datasource.jndi-name]进行JNDI查找,抛出带有消息的NamingException:名称[spring.datasource.jndi-name]未在此上下文中绑定。无法找到[spring.datasource.jndi-name]。返回null。
12:37:53.998 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - 在PropertySource“configurationProperties”中找到键'spring.datasource.jndi-name',其值为String类型

在我的tomcat9/conf/context.xml文件中:

<Resource  name="jdbc/bonanza" 
            auth="Container" 
            type="javax.sql.DataSource"
            maxTotal="100" 
            maxIdle="30" 
            maxWaitMillis="10000"
            username="a_usr" 
            password="Mu*7gydlcdstg100@" 
            driverClassName="com.mysql.jdbc.Driver"
            url="jdbc:mysql://172.175.77.55:3306/a_db"
/>
英文:

I have a SpringBootApplication, packaged as war file:

@SpringBootApplication(exclude = {SecurityAutoConfiguration.class})
public class Application extends SpringBootServletInitializer {

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}
	
	@Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }

}

on the application.properties:

spring.datasource.jndi-name=java:comp/env/jdbc/bonanza

but on the logs I see those messages when I deploy the war in the Tomcat 9:

Name [spring.datasource.jndi-name] is not bound in this Context. Unable to find [spring.datasource.jndi-name].. Returning null.

the logs:

12:37:53.989 [main] DEBUG o.springframework.jndi.JndiTemplate - Looking up JNDI object with name [java:comp/env/spring.datasource.jndi-name]
12:37:53.989 [main] DEBUG o.s.jndi.JndiLocatorDelegate - Converted JNDI name [java:comp/env/spring.datasource.jndi-name] not found - trying original name [spring.datasource.jndi-name]. javax.naming.NameNotFoundException: Name [spring.datasource.jndi-name] is not bound in this Context. Unable to find [spring.datasource.jndi-name].
12:37:53.990 [main] DEBUG o.springframework.jndi.JndiTemplate - Looking up JNDI object with name [spring.datasource.jndi-name]
12:37:53.991 [main] DEBUG o.s.jndi.JndiPropertySource - JNDI lookup for name [spring.datasource.jndi-name] threw NamingException with message: Name [spring.datasource.jndi-name] is not bound in this Context. Unable to find [spring.datasource.jndi-name].. Returning null.
12:37:53.995 [main] DEBUG o.springframework.jndi.JndiTemplate - Looking up JNDI object with name [java:comp/env/spring.datasource.jndi-name]
12:37:53.996 [main] DEBUG o.s.jndi.JndiLocatorDelegate - Converted JNDI name [java:comp/env/spring.datasource.jndi-name] not found - trying original name [spring.datasource.jndi-name]. javax.naming.NameNotFoundException: Name [spring.datasource.jndi-name] is not bound in this Context. Unable to find [spring.datasource.jndi-name].
12:37:53.996 [main] DEBUG o.springframework.jndi.JndiTemplate - Looking up JNDI object with name [spring.datasource.jndi-name]
12:37:53.997 [main] DEBUG o.s.jndi.JndiPropertySource - JNDI lookup for name [spring.datasource.jndi-name] threw NamingException with message: Name [spring.datasource.jndi-name] is not bound in this Context. Unable to find [spring.datasource.jndi-name].. Returning null.
12:37:53.998 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Found key &#39;spring.datasource.jndi-name&#39; in PropertySource &#39;configurationProperties&#39; with value of type String

on my tomcat9/conf/context.xml:

 &lt;Resource 	name=&quot;jdbc/bonanza&quot; 
				auth=&quot;Container&quot; 
				type=&quot;javax.sql.DataSource&quot;
				maxTotal=&quot;100&quot; 
				maxIdle=&quot;30&quot; 
				maxWaitMillis=&quot;10000&quot;
				username=&quot;a_usr&quot; 
				password=&quot;Mu*7gydlcdstg100@&quot; 
				driverClassName=&quot;com.mysql.jdbc.Driver&quot;
				url=&quot;jdbc:mysql://172.175.77.55:3306/a_db&quot;
		/&gt;

答案1

得分: 1

根据错误提示,Spring Boot 无法在 JNDI 查找中找到密钥。在 Spring Boot 的嵌入式 Tomcat 中禁用了 JNDI,所以您需要使用 Tomcat#enableNaming 启用它,一旦启用后,您需要在 JNDI 中创建一个查找条目。您可以参考下面的代码,这些代码是我从一个 Spring Boot 项目维护者的存储库 GitHub repo JNDI-Tomcat 复制来的:

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

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

        @Override
        protected void postProcessContext(Context context) {
            ContextResource resource = new ContextResource();
            resource.setName("jdbc/bonanza");
            resource.setType(DataSource.class.getName());
            resource.setProperty("driverClassName", "your.db.Driver");
            resource.setProperty("url", "jdbc:yourDb");

            context.getNamingResources().addResource(resource);
        }
    };
}

[编辑]

如果您没有使用嵌入式 Tomcat 服务器,可以通过配置 Tomcat 配置文件来配置 JNDI:

server.xml 中,在 &lt;GlobalNamingResources&gt; 下创建一个资源:

<Resource auth="Container" driverClassName="..."
           maxActive="..." 
           maxIdle="..." 
           maxWait="..." 
           name="jdbc/bonanza"  
           username="..."
           password="..."
           type="..."
           url="..."/>

context.xml 中,您可以链接资源:

<context>
    <ResourceLink auth="Container" name="jdbc/bonanza" global="jdbc/bonanza" type="javax.sql.DataSource" />
</context>

此外,请确保您不是使用 Spring Boot 的 main 方法启动应用程序。您需要使用 Maven/Gradle 构建 WAR 文件,然后将其部署到 Tomcat 并进行测试。

英文:

As the error suggests, spring boot cannot find the key in the JNDI lookup. JNDI is disabled in Spring boot's embedded Tomcat so you would need to enable it using Tomcat#enableNaming and once that is done you would need to create a lookup entry in JNDI. You can refer to the below code which I copied from one of the spring boot project maintainers repository GitHub repo JNDI-Tomcat

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

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

		@Override
		protected void postProcessContext(Context context) {
			ContextResource resource = new ContextResource();
			resource.setName(&quot;jdbc/bonanza&quot;);
			resource.setType(DataSource.class.getName());
			resource.setProperty(&quot;driverClassName&quot;, &quot;your.db.Driver&quot;);
			resource.setProperty(&quot;url&quot;, &quot;jdbc:yourDb&quot;);

			context.getNamingResources().addResource(resource);
		}
	};
}

[Edit]

As you are not using embedded tomcat server, you can configure JNDI by configuring it using tomcat config files:

In server.xml, create a Resource under &lt;GlobalNamingResources&gt;

&lt;Resource auth=&quot;Container&quot; driverClassName=&quot;...&quot; 
                           maxActive=&quot;...&quot; 
                           maxIdle=&quot;...&quot; 
                           maxWait=&quot;...&quot; 
                           name=&quot;jdbc/bonanza&quot;  
                           username=&quot;...&quot;
                           password=&quot;...&quot;
                           type=&quot;...&quot;
                           url=&quot;...&quot;/&gt;

In Context.xml, you can link the resource

&lt;context&gt;
	&lt;ResourceLink auth=&quot;Container&quot; name=&quot;jdbc/bonanza&quot; global=&quot;jdbc/bonanza&quot; type=&quot;javax.sql.DataSource&quot; /&gt;
&lt;/context&gt;

Also, make sure you are not starting the application using the spring-boot main method. You need to build the war file using maven/gradle and then deploy it to the tomcat and test it.

huangapple
  • 本文由 发表于 2020年9月26日 18:43:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/64076682.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定