【问题标题】:@Primary on the fly@Primary 即时
【发布时间】:2018-05-21 18:40:10
【问题描述】:

我需要一个建议。

我有基础 Maven 项目,我在其中声明了所有存储库、实体和持久性类。它们都是无 XML 配置的。每个数据库及其所有相关类都按包划分。在这个项目上所有的东西都被注释了,比如:@Entity、@Repository、@Configuration、@Primary 等等……看起来像这样:

现在,radiusfttx.domain 包中的 bean 被注释为 @Primary。这个项目基本上就是它,它自己什么都不做。

然后,当我创建一个需要访问任何数据库的新项目时,我只需使用 Maven 导入第一个项目,然后在新项目初始化时,我像这样更改它(它是 Kotlin,但我很确定你可以理解):

@SpringBootApplication
@ComponentScan(basePackages = [
    "com.entre.rest.boot", <-- my main class is here
    "com.entre.databases.mailserver.domain", <-- repos from the other project
    "com.entre.databases.integrator.domain" ])

由于所有内容都已注释,因此 Spring-boot 的自动配置会毫无问题地选择类并创建 bean。好吧,至少在我尝试向数据库提交某些内容之前。

因为只有一个持久性可以具有 @Primary 注释,如果我不将该持久性添加到 @ComponentScan 一切都不起作用。正如您在上面的示例中看到的那样,我没有将“radiusfttx.domain”添加到@ComponentScan,而@Primary 就在那里。

所以我的问题是:有没有办法可以即时设置@Primary?被注释和硬编码不适用于我在这里尝试做的事情。有什么想法吗?

提前致谢。

编辑 1

作为一种解决方法,我创建了一个“虚拟”H2 持久性,我将其标记为 @Primary 并添加到我的所有项目中。这样,我所有的“真实”数据源都不需要设置@Primary。这远不是解决这种情况的方法,但它确实有效。如果有人能想出更好的东西,这个问题仍然悬而未决。

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "emfDummy", transactionManagerRef = "tmDummy",
        basePackages = ["com.entre.databases.dummy.domain"])
class DummyPersistence {
    @Primary
    @Bean("dsDummy")
    fun dataSource() = HikariDataSource().apply {
        username = "sa"
        password = "sa"
        jdbcUrl = "jdbc:h2:mem:db;DB_CLOSE_DELAY=-1"
        driverClassName = "org.h2.Driver"
    }

    fun hibernateJpaVendorAdapter() = HibernateJpaVendorAdapter().apply {
        setDatabasePlatform("org.hibernate.dialect.H2Dialect")
        setShowSql(false)
        setGenerateDdl(true)
    }

    @Primary
    @Bean("emfDummy")
    fun entityManagerFactory() = LocalContainerEntityManagerFactoryBean().apply {
        setPackagesToScan("com.entre.databases.dummy.domain")
        jpaVendorAdapter = hibernateJpaVendorAdapter()
        dataSource = dataSource()
        persistenceUnitName = "puDummy"
        afterPropertiesSet()
    }

    @Primary
    @Bean("tmDummy")
    fun transactionManager() = JpaTransactionManager().apply {
        entityManagerFactory = entityManagerFactory().`object`
    }
}

【问题讨论】:

  • 如果您需要更好的控制,请不要使用@Primary。考虑使用Profile
  • 当我想在开发和生产中更改数据源时,我会使用配置文件。但是在这种情况下,我想不出一种对我有帮助的方法。如果应用程序有超过 1 个数据源,还需要设置一个 @Primary。
  • 或者试试@Qualifier 来确定你想使用哪一个?
  • 我不知道那个,它看起来很有希望。我会尽快回复你。

标签: spring kotlin spring-data-jpa


【解决方案1】:

您可以使用@Qualifier,或者根本不将您的组件标记为@Component,而是将它们作为简单的类保留在您的库中,并在客户端应用程序中将任何您想要的设置为@Bean

这样您可以拥有单个数据源,或者,如果您需要更多数据源,您可以在所需的 @Bean 上添加 @Primary

关于配置文件,您可以设置除 prod/dev/test 之外的其他配置文件,例如prod,ds1prod,ds2test,tds1等……

【讨论】:

    【解决方案2】:

    感谢所有的答案,你让我找到了正确的方向。

    虽然我了解 @Qualifier 的使用,但这对于我的特定项目来说还不够,因为据我所知,注释必须在导入的“库”项目上。我的问题确实出在事务上,因为在导入持久性配置尚未标记为@Primary 的特定包后,我无法指定@Primary。

    这就是我解决它的方法。

    我不仅在“库”项目上创建了存储库,还在那里创建了@Service 层。这些@Services 我也可以用@Transactional 注释并命名事务管理器Spring 需要用于该特定服务。因此,例如,在“ServiceDummy”中,我可以添加 @Transactional("tmDummy") 并仅在其他应用程序上自动装配 @Service。这样一来,Spring 就不会争论有 2、3 或更多的 transactionManager 可供选择。

    简单示例:

    package com.entre.databases.dummy.service
    
    @Service
    @Transactional("tmDummy")
    class DummyService(
        val dummyRepository: DummyRepository)
    {
    
        fun findDummy(id: Int): Optional<Dummy> {
            return dummyRepository.findById(id)
        }
    
    }
    

    在另一个正在导入“库”的应用程序上:

    @SpringBootApplication
    @ComponentScan(basePackages = [
        "com.entre.rest.boot",
        "com.entre.databases.dummy.service",
        "com.entre.rest.web"
    ])
    class Application
    
    fun main(args: Array<String>) {
        runApplication<Application>(*args)
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-21
      • 1970-01-01
      • 2017-07-07
      • 2017-09-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多