微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在多模块多数据源项目中指示哪种数据源注入我的DAO的正确方法是什么?

如何解决在多模块多数据源项目中指示哪种数据源注入我的DAO的正确方法是什么?

我有一个项目(到目前为止)分为3个模块-核心(模型1),用户管理(模型2)和Web(视图和控制器)。我的项目结构(为了达到重点而简化为仅相关的类)如下:

Project  
|-- core  
|  |-- src.main.java.com.romco.example  
|  |  |-- config.CoreDataSourceConfiguration  
|  |  |-- persistence.daoimpl.someCoreDaoImpl  
|-- user-management  
|  |-- src.main.kotlin.com.romco.example  
|  |  |-- config.UserManagementConfiguration  
|  |  |-- persistence.daoimpl.someUserManagementDaoImpl  
|-- web  
| // not important right Now

我的类如下(调试上一个问题时,我不得不将一些值初始化直接移到代码中,而不是使用Todo指出的application.properties,因此出于手头的问题,请忽略它)

  • CoreDataSourceConfiguration:

    @Configuration
    public class CoreDataSourceConfiguration {
    
        @Bean
        @Primary
        public DataSourceProperties coreDataSourceProperties() {
            return new DataSourceProperties();
        }
    
        //Todo values should be retrieved from application.properties
    
        @Bean(name = "coreDataSource")
        @Primary
        public DataSource coreDataSource() {
            DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
            dataSourceBuilder.driverClassName("com.MysqL.cj.jdbc.Driver");
            dataSourceBuilder.url("...");
            dataSourceBuilder.username("...");
            dataSourceBuilder.password("...");
            return dataSourceBuilder.build();
        }
    
        @Bean(name = "coreTransactionManager")
        @Autowired
        DataSourceTransactionManager coreTransactionManager(@Qualifier("coreDataSource") DataSource dataSource) {
            return new DataSourceTransactionManager(dataSource);
        }
    }

  • SomeCoreDaoImpl:

    @Repository
    public class SomeCoreDaoImpl implements SomeCoreDao {
        
        // some constants here
    
        private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
        
        @Autowired
        @Override
        public void setDataSource(DataSource dataSource) {
            namedParameterJdbcTemplate = NamedParameterJdbcTemplateHolder.get(dataSource);
        }
    
        // DB code here - create,update,etc.
        
    }

  • UserManagementConfiguration:

    @Configuration
    open class UserManagementDataSourceConfiguration {
    
        @Bean
        open fun userManagementDataSourceProperties(): DataSourceProperties {
            return DataSourceProperties()
        }
    
        @Bean(name = ["userManagementDataSource"])
        open fun userManagementDataSource(): DataSource {
            val dataSourceBuilder = DataSourceBuilder.create()
            dataSourceBuilder
                    .driverClassName("com.MysqL.cj.jdbc.Driver")
                    .url("...")
                    .username("...")
                    .password("...")
            return dataSourceBuilder.build()
        }
    
        @Bean(name = ["userManagementTransactionManager"])
        @Autowired
        open fun userManagementTransactionManager(@Qualifier("userManagementDataSource") dataSource: DataSource): DataSourceTransactionManager {
            return DataSourceTransactionManager(dataSource)
        }
      }

  • SomeUserManagementDaoImpl:

    @Repository
    open class SomeUserManagementDaoImpl: SomeUserManagementDao{
    
        // constants are here
    
        private lateinit var namedParameterJdbcTemplate: NamedParameterJdbcTemplate
    
        @Autowired
        fun setDataSource(@Qualifier("userManagementDataSource") dataSource: DataSource) {
            namedParameterJdbcTemplate = NamedParameterJdbcTemplate(dataSource)
        }
    
        // DB code here
    
    }

如您所见,实现它的方法是通过在SomeUserManagementDaoImpl类中的自动装配setDataSource方法中指定要使用的bean。

我显然希望避免在每个daoImpl类中都这样做,尽管我可以考虑将其提取到单个类中,但这似乎并不是“ spring”预期的解决方案。

现在(再次,很明显)-数据源是特定于模块的,并且最初,我什至假设spring会以某种方式在后台找出它,而不是使用@Primary数据源,而是使用在a中定义的数据源。给定的模块(除非该模块没有任何模块,在这种情况下,我认为它将回落到@Primary模块)。
但是,事实并非如此,我想知道是否有某种方法可以告诉spring在整个模块中使用给定的数据源配置...

我一直在研究处理多数据源项目的许多类似线程和指南,但实际上却找不到答案。实际上,我在实施多数据源解决方案时所参考的指南根本没有提到这一点(除非我错过了它),例如。
https://www.baeldung.com/spring-boot-failed-to-configure-data-source
https://www.baeldung.com/spring-data-jpa-multiple-databases

我完全有可能在做其他非常错误的事情,这是根本原因,在这种情况下,请帮我。

解决方法

因此,如果有人偶然发现了同一问题,那么到目前为止,这就是我解决的方法。将来我可能会想出一个更优雅的解决方案,或者更可能找到与此相关的问题,但是目前看来它是可行的(尽管还没有做很多测试):

在用户管理模块(一个不使用@Primary数据源的模块)中,我创建了以下抽象类,将dataSource注入(使用限定符指定数据源)提取到一个位置:

    abstract class WithDataSource {
    
        protected lateinit var namedParameterJdbcTemplate: NamedParameterJdbcTemplate
    
        @Autowired
        fun setDataSource(@Qualifier(USER_MANAGEMENT_DATA_SOURCE_BEAN_NAME) dataSource: DataSource) {
            namedParameterJdbcTemplate = NamedParameterJdbcTemplate(dataSource)
        }
    
    }

然后,我的每个用户管理DaoImpl类都会扩展该类,因此隐式实现了GenericDao接口的setDataSource()方法。

为完整起见,用户管理模块现在看起来像这样(我包括一些以前省略的界面,但仍然保留了“ example”命名,并省略了一些特定的实用程序代码):

    Project  
    |-- core  
    |  |-- src.main.java.com.romco.example  
    |  |  |-- config.CoreDataSourceConfiguration  
    |  |  |-- persistence.daoimpl.SomeCoreDaoImpl  
    |-- user-management  
    |  |-- src.main.kotlin.com.romco.example  
    |  |  |-- config.UserManagementConfiguration  
    |  |  |-- persistence.dao.GenericDao  
    |  |  |-- persistence.daoimpl.SomeUserManagementDaoImpl  
    |  |  |-- persistence.util.DaoUtil.kt  
    |-- web  
    | // not important right now

  • UserManagementConfiguration(将bean名称添加为常量USER_MANAGEMENT_DATA_SOURCE_BEAN_NAME):

    @Configuration
    open class UserManagementDataSourceConfiguration {

        companion object {
            const val USER_MANAGEMENT_DATA_SOURCE_BEAN_NAME = "userManagementDataSource"
        }

        @Bean
        open fun userManagementDataSourceProperties(): DataSourceProperties {
            return DataSourceProperties()
        }
    
        @Bean(name = ["userManagementDataSource"])
        open fun userManagementDataSource(): DataSource {
            val dataSourceBuilder = DataSourceBuilder.create()
            dataSourceBuilder
                    .driverClassName("com.mysql.cj.jdbc.Driver")
                    .url("...")
                    .username("...")
                    .password("...")
            return dataSourceBuilder.build()
        }
    
        @Bean(name = ["userManagementTransactionManager"])
        @Autowired
        open fun userManagementTransactionManager(@Qualifier("userManagementDataSource") dataSource: DataSource): DataSourceTransactionManager {
            return DataSourceTransactionManager(dataSource)
        }
      }

  • GenericDao(原始问题中未提及,因为它不太相关,包括解决方案的完整性)
    interface GenericDao<T> {
        fun setDataSource(dataSource: DataSource)
        // retrieves all
        fun retrieveAll(): Collection<T>
        // creates and returns id of the newly created record. In case of failure,returns -1.
        fun create(t: T): Long
        // updates by id,returns true if success.
        fun update(t: T): Boolean
        // deletes by id,returns true if success.
        fun delete(t: T): Boolean
        // performs cleanup,for example,might delete all test records (id < 0)
        fun cleanup()
    }

  • SomeUserManagementDao(在原始问题中未提及,因为它不太相关,包括解决方案的完整性)
    interface SomeUserManagementDao: GenericDao<SomeUserManagementClass> {
        fun retrieveBySpecificValue(specificValue: String): SomeUserManagementClass?
    }
  • SomeUserManagementDaoImpl(如评论中所述进行更新):

    @Repository
    open class SomeUserManagementDaoImpl: SomeUserManagementDao,WithDataSource() {
    
        // constants are here
    
        // namedParameterJdbcTemplate and setDataSource() are now inherited from the parent class - WithDataSource
    
        // DB code here
    
    }

  • DaoUtil.kt(包含最初提到的抽象类以及其他一些实用程序,在本例中为实用程序):
    abstract class WithDataSource {
    
        protected lateinit var namedParameterJdbcTemplate: NamedParameterJdbcTemplate
    
        @Autowired
        fun setDataSource(@Qualifier(USER_MANAGEMENT_DATA_SOURCE_BEAN_NAME) dataSource: DataSource) {
            namedParameterJdbcTemplate = NamedParameterJdbcTemplate(dataSource)
        }
    
    }

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。