java - Spring boot JNDI不工作,tomcat无法启动

标签 java spring spring-boot jndi

我正在开发 Spring Boot 应用程序,我尝试使用 JNDI 连接数据源,但它不起作用,并给出以下错误,如果有人知道原因,请帮助:

这是它显示的错误:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'i': Invocation of init method failed; 
nested exception is org.springframework.jndi.JndiLookupFailureException: JndiObjectTargetSource failed to obtain new target object; 
nested exception is javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, 
or in an application resource file:  java.naming.factory.initial

对于 pom.xml 依赖项文件,我包含了以下依赖项:

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jdbc</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
        <scope>provided</scope>
    </dependency>

    <!-- Added from here -->
    <dependency>
        <groupId>org.apache.tomcat.embed</groupId>
        <artifactId>tomcat-embed-jasper</artifactId>
        <scope>provided</scope>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
    </dependency>

    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <version>42.2.25</version>
    </dependency>

当我使用 postgresql 数据库时,我使用了它的依赖项,并且在 application.properties 文件中我提到如下:

## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
# Datasource settings
spring.datasource.initialize=true
spring.datasource.jndi-name=jdbc/IDB

spring.jmx.enabled: false
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.username=postgres
spring.datasource.password=ROOT
spring.datasource.type=javax.sql.DataSource
spring.datasource.separator=;

对于 tomcat 上下文命名初始化,我定义了 bean,如下所示:

@Bean
public TomcatServletWebServerFactory tomcatFactory() {
    return new TomcatServletWebServerFactory() {
        @Override
        protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
            tomcat.enableNaming();
            try {
                tomcat.addContext("/aiv/appimages", imgLoc);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return super.getTomcatWebServer(tomcat);
        }

        @Override
        protected void postProcessContext(org.apache.catalina.Context context) {
            ContextResource resource = new ContextResource();
            resource.setName("jdbc/ActiveIDB");
            resource.setType(DataSource.class.getName());

            resource.setProperty("driverClassName", "org.postgresql.Driver");
            resource.setProperty("url", "jdbc:postgresql://localhost:5432/postgres");
            resource.setProperty("username", "postgres");
            resource.setProperty("password", "ROOT");

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


@Bean(destroyMethod="")
public DataSource dataSource() throws IllegalArgumentException, NamingException {
    JndiObjectFactoryBean bean = new JndiObjectFactoryBean();
    bean.setJndiName("java:comp/env/jdbc/IDB");
    bean.setProxyInterface(DataSource.class);
    bean.setLookupOnStartup(false);
    bean.afterPropertiesSet();
    return (DataSource)bean.getObject();
}

请任何人都可以让我知道我做错了什么,为什么它会给我这个错误。已获得帮助。

最佳答案

你必须做 5 件事:

  1. tomcat.enableNaming();
  2. 将 ContextResource 添加到 NamingResources(使用相同的名称:jdbc/IDBjdbc/ActiveIDB 具有不同的哈希代码:))
  3. spring.datasource.jndi-名称:jdbc/DS_NAME
  4. 将 org.springframework:spring-jdbc(EmbeddedDatabaseType 类)添加到类路径(它将激活 JndiDataSourceAutoConfiguration)

此时,spring将尝试创建数据源但失败,因为org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory类不在类路径中(它是javax的默认工厂.sql.DataSource资源)

  • 添加依赖项org.apache.tomcat:tomcat-dbcp:8.5.4 [或更高版本](它包含org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory)

  •  package com.example;
    
     import org.apache.catalina.Context;
     import org.apache.catalina.startup.Tomcat;
     import org.apache.tomcat.util.descriptor.web.ContextResource;
     import org.springframework.boot.SpringApplication;
     import org.springframework.boot.autoconfigure.SpringBootApplication;
     import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
     import org.springframework.boot.web.embedded.tomcat.TomcatWebServer;
     import org.springframework.context.annotation.Bean;
    
     import javax.servlet.ServletException;
     import javax.sql.DataSource;
     import java.io.IOException;
     import java.sql.SQLException;
    
     @SpringBootApplication
     public class Application {
    
         /**
          * Or you can copy full implementation from
          * org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration.EmbeddedTomcat
          * override only getTomcatWebServer(Tomcat)
          * and provide TomcatContextCustomizer instead of overriding 'postProcessContext(Context)'
          */
         @Bean
         public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
             return new TomcatServletWebServerFactory() {
    
                 @Override
                 protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
                     //1 enable naming
                     tomcat.enableNaming();
                     return super.getTomcatWebServer(tomcat);
                 }
    
                 @Override
                 protected void postProcessContext(Context context) {
                     //2 create resource
                     ContextResource resource = new ContextResource();
                     resource.setName("jdbc/h2DS");
                     resource.setType(DataSource.class.getName());
                     resource.setProperty("driverClassName", "org.h2.Driver");
                     resource.setProperty("url", "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE");
                     resource.setProperty("username", "sa");
                     resource.setProperty("password","");
                     context.getNamingResources().addResource(resource);
                 }
             };
         }
    
         public static void main(String[] args) throws ServletException, IOException, SQLException {
             //3 JndiDataSourceAutoConfiguration will provide that bean if
             // a) spring.datasource.jndi-name: jdbc/h2DS
             // b) org.springframework:spring-jdbc (class EmbeddedDatabaseType) is in classpath
             SpringApplication.run(Application.class, args)
                 .getBean(DataSource.class)
                 .getConnection();
         }
     }
     
    

    依赖关系

    1. org.springframework.boot:spring-boot-starter-web
    2. org.springframework:spring-jdbc
    3. com.h2database:h2:2.1.214(运行时)
    4. org.apache.tomcat:tomcat-dbcp:8.5.4 [或更高版本](运行时)

    应用程序属性

    spring.datasource.jndi-name=jdbc/h2DS
    

    关于java - Spring boot JNDI不工作,tomcat无法启动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72729120/

    相关文章:

    java - 如何禁用 PDFBox 警告日志记录

    java - 使用 mvn liquibase :diff? 时如何禁用删除表和列

    java - 如何在 Spring MVC 和 Hibernate 中将对象列表转换为 JSON?

    java - Spring boot - 从外部类路径加载文件

    java - 无法在 Rest Controller 中使用 Postmapping 接收参数

    java - 从一组代码中解析可用消息的简单方法

    java - 如何禁用 Spring Boot 安全性

    java - 将数据输出到Java中另一个类中的String

    java - 将 ArrayList 从一个类传递到另一个类

    IntelliJ 中的 Java 项目没有错误,但通过 Maven 编译失败