首页 > 解决方案 > Spring Boot 2 MultiProject Build 忽略子项目中的 application.yml

问题描述

我正在使用 Spring Boot 2.1.5.RELEASE 进行多项目构建。

我在https://github.com/MBurchard/ACME分享了一个例子

从 storage 子项目运行测试用例时,会找到并使用 storage 项目内部的所有 YAML 配置。

当使用配置文件 dev 从 Web 项目运行 SpringBootApplication 时,它会显示错误。

spring:
  # PROFILES
  profiles:
    active: ${profile:dev}

错误原因

Caused by: java.lang.IllegalArgumentException: Not a managed type: class de.mbur.acme.User
at org.hibernate.metamodel.internal.MetamodelImpl.managedType(MetamodelImpl.java:552) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
at org.springframework.data.jpa.repository.support.JpaMetamodelEntityInformation.<init>(JpaMetamodelEntityInformation.java:74) ~[spring-data-jpa-2.1.8.RELEASE.jar:2.1.8.RELEASE]
at org.springframework.data.jpa.repository.support.JpaEntityInformationSupport.getEntityInformation(JpaEntityInformationSupport.java:66) ~[spring-data-jpa-2.1.8.RELEASE.jar:2.1.8.RELEASE]

原因很清楚。它不使用存储项目中的 application.yml。

切换到 dev-full-config 时,everythink 工作正常

spring:
  # PROFILES
  profiles:
    active: ${profile:dev-full-config}

但我不想为或多或少内部的数据库重复完整的配置。

在不重复内部数据库配置的情况下,我能做些什么来完成这项工作?

标签: javaspring-bootspring-data-jpa

解决方案


我通过编写一个增强的存储配置来解决这个问题,以便能够查找和使用 Hibernate 映射文件,而且在测试或运行时也尊重属性的外部配置......

详情可见:https ://github.com/MBurchard/ACME/commit/499dbb128efb08614145754dc54e2ae8d4fc5d00

package de.mbur.acme.storage;

import java.util.Collections;
import java.util.Map;
import java.util.Properties;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.sql.DataSource;

import org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl;
import org.slf4j.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;

import static org.slf4j.LoggerFactory.getLogger;

@Configuration
class MySQLConfig {
    private static final Map<String, String> HIBERNATE_MAPPINGS = Stream.of(new String[][]{
            {"hibernate.format_sql", "spring.jpa.properties.hibernate.format_sql"},
            {"hibernate.show_sql", "spring.jpa.show-sql"},
    }).collect(Collectors.collectingAndThen(
            Collectors.toMap(data -> data[0], data -> data[1]),
            Collections::<String, String>unmodifiableMap));
    private static final Logger LOG = getLogger(MySQLConfig.class);

    static {
        LOG.debug("Hier bin ich");
    }

    private final Environment env;

    MySQLConfig(final Environment env) {
        this.env = env;
    }

    private Properties additionalProperties() {
        final Properties properties = new Properties();
        HIBERNATE_MAPPINGS.entrySet().forEach(entry -> {
            final String property = env.getProperty(entry.getValue());
            if (property != null) {
                LOG.debug("{}: {}", entry.getValue(), property);
                properties.setProperty(entry.getKey(), property);
            }
        });
        return properties;
    }

    @Bean
    LocalContainerEntityManagerFactoryBean entityManagerFactory(final DataSource dataSource,
            final JpaVendorAdapter jpaVendorAdapter) {
        final LocalContainerEntityManagerFactoryBean factoryBean =
                new LocalContainerEntityManagerFactoryBean();
        factoryBean.setDataSource(dataSource);
        factoryBean.setMappingResources("hbm/user.xml");
        factoryBean.setJpaVendorAdapter(jpaVendorAdapter);
        factoryBean.setJpaProperties(additionalProperties());
        return factoryBean;
    }

}

可以看到,DataSource 和 JpaVendorAdapter 都简单地取自 Spring Boot 自动配置。


推荐阅读