Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/324.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用JNDI在Spring Boot中配置多个数据源_Java_Spring_Spring Boot_Spring Data_Jndi - Fatal编程技术网

Java 使用JNDI在Spring Boot中配置多个数据源

Java 使用JNDI在Spring Boot中配置多个数据源,java,spring,spring-boot,spring-data,jndi,Java,Spring,Spring Boot,Spring Data,Jndi,我想使用应用服务器的内置功能管理多个数据源,并使用JNDI访问它。我使用SpringBoot和SpringJPA数据 我能够为单个数据源配置application.properties: spring.datasource.jndi-name=jdbc/customers 以及我在context.xml文件中的配置,如下所示: <Resource name="jdbc/customer" auth="Container" type="javax.sql.DataSource"

我想使用应用服务器的内置功能管理多个数据源,并使用JNDI访问它。我使用SpringBoot和SpringJPA数据

我能够为单个数据源配置application.properties:

spring.datasource.jndi-name=jdbc/customers
以及我在context.xml文件中的配置,如下所示:

<Resource name="jdbc/customer" auth="Container" type="javax.sql.DataSource"
               maxTotal="100" maxIdle="30" maxWaitMillis="10000"
               username="root" password="root" driverClassName="com.mysql.jdbc.Driver"
               url="jdbc:mysql://localhost:3306/customer"/>
请让我知道关于使用JNDI进行多数据源Spring引导的任何详细信息。我已经找了好几天了

根据

配置类

@Bean
@Primary
@ConfigurationProperties(prefix="datasource.primary")
public DataSource primaryDataSource() {
    return DataSourceBuilder.create().build();
}

@Bean
@ConfigurationProperties(prefix="datasource.secondary")
public DataSource secondaryDataSource() {
    return DataSourceBuilder.create().build();
}
应用程序无法启动。尽管tomcat服务器正在启动。日志中不会打印任何错误

第三次试验:使用JndiObjectFactoryBean

我有下面的application.properties

spring.datasource.primary.expected-type=javax.sql.DataSource
spring.datasource.primary.jndi-name=jdbc/customer
spring.datasource.primary.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
spring.datasource.primary.jpa.show-sql=false
spring.datasource.primary.jpa.hibernate.ddl-auto=validate

spring.datasource.secondary.jndi-name=jdbc/employee
spring.datasource.secondary.expected-type=javax.sql.DataSource
spring.datasource.secondary.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
spring.datasource.secondary.jpa.show-sql=false
spring.datasource.secondary.jpa.hibernate.ddl-auto=validate
以及以下java配置:

@Bean(destroyMethod="")
@Primary
@ConfigurationProperties(prefix="spring.datasource.primary")
public FactoryBean primaryDataSource() {
    return new JndiObjectFactoryBean();
}

@Bean(destroyMethod="")
@ConfigurationProperties(prefix="spring.datasource.secondary")
public FactoryBean secondaryDataSource() {
    return new JndiObjectFactoryBean();
}
@Configuration@ EnableConfigurationProperties
public class AppConfig {

    @Bean@ ConfigurationProperties(prefix = "spring.datasource.primary")
    public JndiPropertyHolder primary() {
        return new JndiPropertyHolder();
    }

    @Bean@ Primary
    public DataSource primaryDataSource() {
        JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
        DataSource dataSource = dataSourceLookup.getDataSource(primary().getJndiName());
        return dataSource;
    }

    @Bean@ ConfigurationProperties(prefix = "spring.datasource.secondary")
    public JndiPropertyHolder secondary() {
        return new JndiPropertyHolder();
    }

    @Bean
    public DataSource secondaryDataSource() {
        JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
        DataSource dataSource = dataSourceLookup.getDataSource(secondary().getJndiName());
        return dataSource;
    }

    private static class JndiPropertyHolder {
        private String jndiName;

        public String getJndiName() {
            return jndiName;
        }

        public void setJndiName(String jndiName) {
            this.jndiName = jndiName;
        }
    }
}
但仍然会出现错误:

Related cause: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'primaryDataSource' defined in class path resource [com/web/initializer/MvcConfig.class]: Invocation of init method failed; nested exception is javax.naming.NameNotFoundException: Name [jdbc/customer] is not bound in this Context. Unable to find [jdbc].
Related cause: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'secondaryDataSource' defined in class path resource [com/web/initializer/MvcConfig.class]: Invocation of init method failed; nested exception is javax.naming.NameNotFoundException: Name [jdbc/employee] is not bound in this Context. Unable to find [jdbc].
        at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:133)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:474)
        at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118)
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:686)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
        at org.springframework.boot.context.web.SpringBootServletInitializer.run(SpringBootServletInitializer.java:117)
        at org.springframework.boot.context.web.SpringBootServletInitializer.createRootApplicationContext(SpringBootServletInitializer.java:108)
        at org.springframework.boot.context.web.SpringBootServletInitializer.onStartup(SpringBootServletInitializer.java:68)
        at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:175)
更新: 使用以下属性文件进行试用:

  spring.datasource.primary.expected-type=javax.sql.DataSource
   spring.datasource.primary.jndi-name=java:comp/env/jdbc/customer

   spring.datasource.secondary.jndi-name=java:comp/env/jdbc/employee
   spring.datasource.secondary.expected-type=javax.sql.DataSource

   spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
   spring.jpa.show-sql=false
   spring.jpa.hibernate.ddl-auto=validate
spring.datasource.primary.jndi-name=java:/comp/env/jdbc/SecurityDS
spring.datasource.primary.driver-class-name=org.postgresql.Driver

spring.datasource.secondary.jndi-name=java:/comp/env/jdbc/TmsDS
spring.datasource.secondary.driver-class-name=org.postgresql.Driver

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL9Dialect
spring.jpa.show-sql=false

它在客户模式中创建所有表,但也无法找到其他表。(从第二个模式中)

您可以使用普通的
JndiObjectFactoryBean
。只需将
DataSourceBuilder
替换为
jndObjectFactoryBean
即可

Java配置

@Bean(destroyMethod="")
@Primary
@ConfigurationProperties(prefix="datasource.primary")
public FactoryBean primaryDataSource() {
    return new JndiObjectFactoryBean();
}

@Bean(destroyMethod="")
@ConfigurationProperties(prefix="datasource.secondary")
public FactoryBean secondaryDataSource() {
    return new JndiObjectFactoryBean();
}
性质

datasource.primary.jndi-name=jdbc/customer
datasource.primary.expected-type=javax.sql.DataSource
datasource.secondary.jndi-name=jdbc/project
datasource.secondary.expected-type=javax.sql.DataSource
您可以使用
@ConfigurationProperties
注释设置的每个属性。(请参阅我添加的
预期类型
,但您也可以设置
缓存
启动时查找
等)


注意:在执行JNDI查找时,请将
销毁方法设置为
,否则您可能会遇到这样的情况:当应用程序关闭时,JNDI资源也会关闭/关闭。这不是您在共享环境中想要的东西。

这是您第三次试用的解决方案,稍作修改。 考虑这个解决方案(Spring Boo1.3.2):

application.properties文件:

  spring.datasource.primary.expected-type=javax.sql.DataSource
   spring.datasource.primary.jndi-name=java:comp/env/jdbc/customer

   spring.datasource.secondary.jndi-name=java:comp/env/jdbc/employee
   spring.datasource.secondary.expected-type=javax.sql.DataSource

   spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
   spring.jpa.show-sql=false
   spring.jpa.hibernate.ddl-auto=validate
spring.datasource.primary.jndi-name=java:/comp/env/jdbc/SecurityDS
spring.datasource.primary.driver-class-name=org.postgresql.Driver

spring.datasource.secondary.jndi-name=java:/comp/env/jdbc/TmsDS
spring.datasource.secondary.driver-class-name=org.postgresql.Driver

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL9Dialect
spring.jpa.show-sql=false
配置:

@Bean(destroyMethod="")
@Primary
@ConfigurationProperties(prefix="spring.datasource.primary")
public FactoryBean primaryDataSource() {
    return new JndiObjectFactoryBean();
}

@Bean(destroyMethod="")
@ConfigurationProperties(prefix="spring.datasource.secondary")
public FactoryBean secondaryDataSource() {
    return new JndiObjectFactoryBean();
}
@Configuration@ EnableConfigurationProperties
public class AppConfig {

    @Bean@ ConfigurationProperties(prefix = "spring.datasource.primary")
    public JndiPropertyHolder primary() {
        return new JndiPropertyHolder();
    }

    @Bean@ Primary
    public DataSource primaryDataSource() {
        JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
        DataSource dataSource = dataSourceLookup.getDataSource(primary().getJndiName());
        return dataSource;
    }

    @Bean@ ConfigurationProperties(prefix = "spring.datasource.secondary")
    public JndiPropertyHolder secondary() {
        return new JndiPropertyHolder();
    }

    @Bean
    public DataSource secondaryDataSource() {
        JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
        DataSource dataSource = dataSourceLookup.getDataSource(secondary().getJndiName());
        return dataSource;
    }

    private static class JndiPropertyHolder {
        private String jndiName;

        public String getJndiName() {
            return jndiName;
        }

        public void setJndiName(String jndiName) {
            this.jndiName = jndiName;
        }
    }
}

然后,您可以按照指南将数据源与jpa存储库一起使用。

它对我有效,包含的代码更少

@Configuration
public class Config {
    @Value("${spring.datasource.primary.jndi-name}")
    private String primaryJndiName;

    @Value("${spring.datasource.secondary.jndi-name}")
    private String secondaryJndiName;

    private JndiDataSourceLookup lookup = new JndiDataSourceLookup();

    @Primary
    @Bean(destroyMethod = "") // destroy method is disabled for Weblogic update app ability
    public DataSource primaryDs() {
        return lookup.getDataSource(primaryJndiName);
    }

    @Bean(destroyMethod = "") // destroy method is disabled for Weblogic update app ability
    public DataSource secondaryDs() {
        return lookup.getDataSource(secondaryJndiName);
    }
}

我获得成功和探索更多的简洁方式

  • 在外部tomcat中设置许多jndi资源,您可以在eclipse中启动/停止。注意-双击eclipse中的tomcat并选择use workspace metedata,这意味着不要将应用部署到tomcat webapp文件夹。在相应的eclipse服务器文件(context.xml-ResourceLink、server.xml-Resource、web.xml-Resource-ref)中添加jndi资源

  • 无需在application.properties中设置spring.datasource.*。由于数据源类型(即
    type=“javax.sql.datasource”
    )的jndi竞赛被导出到外部服务器

  • 在SpringBootApplication注释类中,通过jndi查找从所有jndi资源(按照#1设置的资源)创建数据源bean

    @Bean(name = "abcDataSource")
    
    public DataSource getAbcDataSource() {
    
        JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
        DataSource dataSource = dataSourceLookup.getDataSource("java:comp/env/jdbc/abcDataSource");
        return dataSource; 
    }
    
    @Bean(name = "dsName")
    @ConfigurationProperties("ds.datasource.configuration")
    public DataSource dataSource(@Qualifier("dsProperties") DataSourceProperties db1DataSourceProperties)
    {
    
        if(Arrays.asList(environment.getActiveProfiles()).contains("prod"))
        {
            final JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
            return dataSourceLookup.getDataSource("java:comp/env/jdbc/DS1");
        }
        else
        {
            return db1DataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
        }
    }
    
  • 如果您的项目中使用了SpringJDBC,那么提供上述数据源来创建JDBCTemplatebean

    @Bean(name = "jdbcAbcTemplate")
    
    public JdbcTemplate abcJdbcTemplate(@Lazy @Qualifier("abcDataSource")
    
    DataSource refDS) 
    {        
      return new JdbcTemplate(refDS);
    }
    
  • 只需自动连接DataSource类型的属性,并获取systemout的详细信息以了解更多信息


  • 虽然上面的答案很好,但我将再添加一个来说明混合jndi和完整数据连接配置的致命问题。在典型的开发环境中,您可以在本地开发环境中完全限定数据库连接,然后在推送到qa时使用jndi,等等。。你的 application.properties看起来是这样的:

    spring.datasource.url=jdbc:sqlserver://server.domain.org:1433;databaseName=dbxx
    spring.datasource.username=userxxyyzz
    spring.datasource.password=passxxyyzz
    spring.datasource.platform=mssql
    spring.datasource.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
    
    spring.datasource.jndi-name=java:jboss/datasources/dbxx
    
    spring.custom.datasource.jndi-name=java:jboss/datasources/dbxx
    
    和application-qa.properties,如:

    spring.datasource.url=jdbc:sqlserver://server.domain.org:1433;databaseName=dbxx
    spring.datasource.username=userxxyyzz
    spring.datasource.password=passxxyyzz
    spring.datasource.platform=mssql
    spring.datasource.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
    
    spring.datasource.jndi-name=java:jboss/datasources/dbxx
    
    spring.custom.datasource.jndi-name=java:jboss/datasources/dbxx
    
    当您必须定义自己的bean以拥有多个数据源时,就会出现问题。如果您使用默认的Spring托管数据源,那么它会自动检测jndi与完全限定连接,并返回一个不需要更改应用程序代码的数据源。如果您定义自己的数据源,它将不再这样做。如果您有类似的application.properties:

    spring.custom.datasource.url=jdbc:sqlserver://server.domain.org:1433;databaseName=dbxx
        spring.custom.datasource.username=userxxyyzz
        spring.custom.datasource.password=passxxyyzz
        spring.custom.datasource.platform=mssql
        spring.custom.datasource.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
    
    和application-qa.properties,如:

    spring.datasource.url=jdbc:sqlserver://server.domain.org:1433;databaseName=dbxx
    spring.datasource.username=userxxyyzz
    spring.datasource.password=passxxyyzz
    spring.datasource.platform=mssql
    spring.datasource.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
    
    spring.datasource.jndi-name=java:jboss/datasources/dbxx
    
    spring.custom.datasource.jndi-name=java:jboss/datasources/dbxx
    
    像Spring文档中建议的那样,使用这样的数据源bean

    此数据源生成器不尝试读取application-qa.properties中的jndi配置,并自动故障返回到application.properties,返回错误的数据库连接。解析相当简单—测试您所处的环境并自定义创建的数据库连接类型。调试这是个麻烦,因为症状是应用程序似乎忽略了application-qa.properties。我与他人分享,以减轻他人的痛苦。将spring.profiles.active=qa等添加到属性文件中,以了解您所处的环境,然后:

      @Value("${spring.profiles.active}")
      String profile;
    
      @Value("${spring.custom.jndi-name}")
      String jndi;
    
      @Primary
      @Bean(name="customDataSourcePropertiesBean")
      @ConfigurationProperties("spring.custom.datasource")
      public DataSourceProperties customDataSourceProperties() {
          return new DataSourceProperties();
      }
    
      @Primary
      @Bean(name="customDataSourceBean")
      @ConfigurationProperties("spring.custom.datasource") 
      public DataSource customDataSource(@Qualifier("customDataSourcePropertiesBean") DataSourceProperties properties) {
        if(profile.equals("localhost")) {
            return DataSourceBuilder
                .create()
                    .username(properties.getDataUsername())
                    .password(properties.getPassword())
                    .url(properties.getUrl())
                    .driverClassName(properties.getDriverClassName())
                    .build();
        }else {
            JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
            return dataSourceLookup.getDataSource(jndi);
        }
      }
    

    在我的例子中,当我使用Spring Boot App启动我的应用程序时,数据库配置是在application-dev.properties上读取的,当我在tomcat上发布时,需要使用数据源添加验证以检查我的配置文件是否为prod,在本例中,我执行jndi查找

    @Bean(name = "abcDataSource")
    
    public DataSource getAbcDataSource() {
    
        JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
        DataSource dataSource = dataSourceLookup.getDataSource("java:comp/env/jdbc/abcDataSource");
        return dataSource; 
    }
    
    @Bean(name = "dsName")
    @ConfigurationProperties("ds.datasource.configuration")
    public DataSource dataSource(@Qualifier("dsProperties") DataSourceProperties db1DataSourceProperties)
    {
    
        if(Arrays.asList(environment.getActiveProfiles()).contains("prod"))
        {
            final JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
            return dataSourceLookup.getDataSource("java:comp/env/jdbc/DS1");
        }
        else
        {
            return db1DataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
        }
    }
    

    DataSourceBuilder
    不用于JNDI。如果您有来自JNDI的多个数据源,您必须自己检索它们。仍然没有运气。A已将该选项添加到原始问题。您是否已阅读错误消息?将
    resource ref
    属性设置为
    true
    datasource.primary.resource ref=true
    或在名称前面加上
    java:comp/env/
    …尝试了这两个选项(resource ref属性设置为true和java:comp/env/)。它为主架构创建表,并抛出错误“找不到表”对于辅助架构中的表。我认为第二个数据源不是通过spring boot自动拾取的?是的,但初始化仅适用于
    @Primary
    一个。是否有办法同时使用这两个数据源。