【问题标题】:Spring JPA: External database configuration from property file does not workSpring JPA:属性文件中的外部数据库配置不起作用
【发布时间】:2019-10-04 19:34:07
【问题描述】:

我想使用外部属性文件来加载数据库和 REST 端点信息。我试图避免使用 XML 配置并支持基于注释的配置。

我创建了 2 个类,这两个类都使用 @Configuration 注释,并在其构造函数中使用 @Value 注释来加载属性:

RestConfiguration.java

@Configuration
public class RestConfiguration {
  private final String grantType;
  private final AuthenticationScheme authenticationScheme;
  private final String clientId;
  private final String clientSecret;
  private final String accessTokenUri;

  private final boolean useProxy;
  private final String proxyHost;
  private final int proxyPort;

  @Autowired
  public RestConfiguration(
      @Value("${api.oauth2.grant-type}") String grantType,
      @Value("${api.oauth2.authentication-scheme}") AuthenticationScheme authenticationScheme,
      @Value("${api.oauth2.client-id}") String clientId,
      @Value("${api.oauth2.client-secret}") String clientSecret,
      @Value("${api.oauth2.url}") String accessTokenUri,
      @Value("${net.proxy}") boolean useProxy,
      @Value("${net.proxy.host}") String proxyHost,
      @Value("${net.proxy.port}") int proxyPort) {
    this.grantType = grantType;
    this.authenticationScheme = authenticationScheme;
    this.clientId = clientId;
    this.clientSecret = clientSecret;
    this.accessTokenUri = accessTokenUri;
    this.useProxy = useProxy;
    this.proxyHost = proxyHost;
    this.proxyPort = proxyPort;
  } 
}

PersistenceConfiguration.java

@Configuration
public class PersistenceConfiguration {
  private final String host;
  private final String port;
  private final String database;
  private final String schema;
  private final String user;
  private final String password;

  @Autowired
  public PersistenceConfiguration(
      @Value("${db.host}") String host,
      @Value("${db.port}") String port,
      @Value("${db.database}") String database,
      @Value("${db.schema}") String schema,
      @Value("${db.user}") String user,
      @Value("${db.password}") String password) {
    this.host = host;
    this.port = port;
    this.database = database;
    this.schema = schema;
    this.user = user;
    this.password = password;
  }

  @Bean
  public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
    LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
    em.setDataSource(dataSource);
    em.setPackagesToScan("ch.example.rest.entities");

    JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
    em.setJpaVendorAdapter(vendorAdapter);
    em.setJpaProperties(additionalProperties());

    return em;
  }

  @Bean
  public DataSource dataSource() {
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
    dataSource.setDriverClassName("org.postgresql.Driver");
    dataSource.setUrl("jdbc:postgresql://" + host + ":" + port + "/" + database);
    dataSource.setUsername(user);
    dataSource.setPassword(password);
    dataSource.setSchema(schema);
    return dataSource;
  }

  @Bean
  public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
    JpaTransactionManager transactionManager = new JpaTransactionManager();
    transactionManager.setEntityManagerFactory(emf);

    return transactionManager;
  }

  @Bean
  public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
    return new PersistenceExceptionTranslationPostProcessor();
  }

  Properties additionalProperties() {
    Properties properties = new Properties();
    properties.setProperty("hibernate.hbm2ddl.auto", "none");
    properties.setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQL95Dialect");
    properties.setProperty(
        "hibernate.physical_naming_strategy",
        "ch.example.rest.configurations.SnakeCaseNamingStrategy");
    properties.setProperty(
        "spring.datasource.hikari.data-source-properties", "stringtype=unspecified");

    return properties;
  }
}

两个配置文件位于同一个包中(子包configurations)。

初始化 Spring 上下文的类如下所示:

@Configuration
@ComponentScan(basePackages = "ch.example.rest")
@EnableJpaRepositories("ch.example.rest.repositories")
@PropertySource("classpath:application.properties")
public class RestClient {
    private CommandLineController commandLineController;

    @Autowired
    public RestClient(CommandLineController commandLineController) {
        this.commandLineController = commandLineController;
    }

    private static void main(String[] args) {
        // ... some parsing of command line arguments

        // Initialize context
        ApplicationContext ctx = new AnnotationConfigApplicationContext(RestClient.class);
        RestClient restClient = ctx.getBean(RestClient.class, uploadCommand);
        restClient.runCommand(parsedCommand, uploadCommand);
    }

    public void runCommand(String command, UploadBillsCommand uploadCommand) {
        // Some calls to a controller
        commandLineController....;
    }
}

有趣的是RestConfiguration 类接收属性,但PersistenceConfiguration 没有。在调试过程中,我注意到 PersistenceConfiguration 类几乎是立即构建的,而 RestConfiguration 是在稍后第一次调用 RestTemplate 时加载的。

我怀疑这可能与 Spring JPA 尝试连接存储库并因此需要在启动时建立 SQL 连接这一事实有关。

我发现this 问题似乎表明,如果没有额外的样板代码,就无法从外部提供数据库配置。由于这个问题已经有 5 年的历史了,我想知道是否有另一种优雅的解决方案来解决这个问题,而无需创建第二个上下文。

【问题讨论】:

    标签: java spring properties spring-data-jpa spring-data


    【解决方案1】:

    好的,所以答案似乎很简单。我不必让 Spring 使用带有 @Value 注释的表达式语言加载属性,而是只需注入 Environment 的实例,然后直接从中获取属性:

    @Configuration
    public class PersistenceConfiguration {
      private String host;
      private String port;
      private String database;
      private String schema;
      private String user;
      private String password;
    
      @Autowired
      public PersistenceConfiguration(Environment environment) {
        this.host = environment.getProperty("db.host");
        this.port = environment.getProperty("db.port");
        this.database = environment.getProperty("db.database");
        this.schema = environment.getProperty("db.schema");
        this.user = environment.getProperty("db.user");
        this.password = environment.getProperty("db.password");
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-09-23
      • 2018-10-25
      • 2017-08-18
      • 1970-01-01
      • 1970-01-01
      • 2018-09-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多