创建工程目录

mkdir SpringBootIntergrationDemo
cd SpringBootIntergrationDemo
gradle init    # 初始化为gradle工程,选择application -> Kotlin -> only one application project -> groovy

或直接通过Spring Initializr创建工程。

添加依赖

编辑build.gradle,添加依赖:

/*
 * This file was generated by the Gradle 'init' task.
 *
 * This generated file contains a sample Kotlin application project to get you started.
 * For more details take a look at the 'Building Java & JVM projects' chapter in the Gradle
 * User Manual available at https://docs.gradle.org/6.7/userguide/building_java_projects.html
 */
plugins {
    // Apply the org.jetbrains.kotlin.jvm Plugin to add support for Kotlin.
    id 'org.jetbrains.kotlin.jvm' version '1.3.72'

    // SpringBoot依赖
    id 'org.springframework.boot' version '2.3.4.RELEASE'
    id 'io.spring.dependency-management' version '1.0.10.RELEASE'

    // Apply the application plugin to add support for building a CLI application in Java.
    // id 'application'
}

group = "top.wteng"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_11  // jdk11

repositories {
    // Use JCenter for resolving dependencies.
    // jcenter()
    // 使用阿里镜像
    repositories {
        maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/' }
        mavenCentral()
    }
}

dependencies {
    // Align versions of all Kotlin components
    implementation platform('org.jetbrains.kotlin:kotlin-bom')

    // Use the Kotlin JDK 8 standard library.
    implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
    //反射
    implementation 'org.jetbrains.kotlin:kotlin-reflect'

    // This dependency is used by the application.
    implementation 'com.google.guava:guava:29.0-jre'

    // spintboot相关
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'com.fasterxml.jackson.module:jackson-module-kotlin'

    //jpa
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

    // h2
    implementation 'com.h2database:h2:1.4.200'

    // spingboot集成测试
    testImplementation ('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }

}

tasks.withType(Test).all {
    useJUnitPlatform()
}

tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
    kotlinOptions {
        jvmTarget = "11"  // kotlin编译版本
    }
}

配置数据源

这里配置两个数据源,为测试方便,直接使用h2数据库。

配置yaml

编辑`application.yaml:

spring:
  datasource:
    primary: # 主数据源
      platform: h2
      url: jdbc:h2:mem:primary
      username: sa
      password:
      schema: classpath:schema.sql
      data: classpath:data.sql
    second: # 第二数据源
      platform: h2
      url: jdbc:h2:mem:second
      username: sa
      password:
      schema: classpath:schema.sql
      data: classpath:data.sql
  jpa: # jpa配置
    primary:  # 主数据源jpa
      generate-ddl: false
      show-sql: false
      hibernate: none
    second:  # 第二数据源jpa
      generate-ddl: false
      show-sql: false
      hibernate: none
  h2:  # h2数据库配置
    console:
      path: /h2-console
      enabled: true
      settings:
        web-allow-others: true  # 允许web登录控制台

配置数据源

编写数据源配置,要注意的是必须有一个应用@Primary注解的主数据源

package top.wteng.springboot.intergration.configuration

import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Primary
import javax.sql.DataSource

@Configuration
open class DataSourceConfiguration {
    @Primary
    @Bean(name = ["primaryDataSourceProperties"])
    @ConfigurationProperties(prefix = "spring.datasource.primary") // 数据源的配置前缀
    open fun primaryDataSourceProperties(): DataSourceProperties {
        return DataSourceProperties()
    }

    @Primary
    @Bean(name = ["primaryDataSource"])
    open fun primaryDataSource(@Qualifier("primaryDataSourceProperties") properties: DataSourceProperties): DataSource {
        return properties.initializeDataSourceBuilder().build()
    }

    @Bean(name = ["secondDataSourceProperties"])
    @ConfigurationProperties(prefix = "spring.datasource.second")
    open fun secondDataSourceProperties(): DataSourceProperties {
        return DataSourceProperties()
    }

    @Bean(name = ["secondDataSource"])
    open fun secondDataSource(@Qualifier("secondDataSourceProperties") properties: DataSourceProperties): DataSource {
        return properties.initializeDataSourceBuilder().build()
    }
}

配置JPA

编写jpa配置,因为有两个数据源,所以编写两个配置,配置目的是要指定每个数据源扫描实体的包路径,每个数据源扫描特定包目录下的实体,生成相应的bean

第一个数据源配置:

package top.wteng.springboot.intergration.configuration

import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Primary
import org.springframework.data.jpa.repository.config.EnableJpaRepositories
import org.springframework.orm.jpa.JpaTransactionManager
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean
import org.springframework.transaction.annotation.EnableTransactionManagement
import javax.persistence.EntityManager
import javax.persistence.EntityManagerFactory
import javax.sql.DataSource

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        basePackages = ["top.wteng.springboot.intergration.repository.primary"], // 扫描的包名称,只扫描该包下的repository定义
        entityManagerFactoryRef = "primaryEntityManagerFactory", // 实体管理bean名称
        transactionManagerRef = "primaryTransactionManager"  // 事务bean名称
)
open class PrimaryJpaConfiguration {
    @Primary // 指定为主数据源
    @Bean(name = ["primaryJpaProperties"])
    @ConfigurationProperties(prefix = "spring.jpa.primary") // 配置前缀
    open fun primaryJpaProperties(): JpaProperties {
        return JpaProperties()
    }

    @Primary
    @Bean(name = ["primaryEntityManagerFactory"])
    open fun primaryEntityManagerFactory(
            @Qualifier("primaryDataSource") primaryDataSource: DataSource, // 使用主数据源
            @Qualifier("primaryJpaProperties") jpaProperties: JpaProperties, // JPA配置属性
            builder: EntityManagerFactoryBuilder): LocalContainerEntityManagerFactoryBean {
        return builder.dataSource(primaryDataSource)
                .properties(jpaProperties.properties)
                .packages("top.wteng.springboot.intergration.entity.primary")  // 实体包路径,只扫描该包下的实体定义
                .persistenceUnit("primaryPersistenceUnit")
                .build()
    }

    @Primary
    @Bean(name = ["primaryEntityManager"])
    open fun primaryEntityManager(@Qualifier("primaryEntityManagerFactory") managerFactory: EntityManagerFactory): EntityManager {
        return managerFactory.createEntityManager()
    }

    @Primary
    @Bean(name = ["primaryTransactionManager"])
    open fun primaryTransactionManager(@Qualifier("primaryEntityManagerFactory") factory: EntityManagerFactory): JpaTransactionManager {
        return JpaTransactionManager(factory)
    }
}

第二个数据源配置如下,配置方式同主数据源一致,只是不必应用primary注解:

package top.wteng.springboot.intergration.configuration

import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.data.jpa.repository.config.EnableJpaRepositories
import org.springframework.orm.jpa.JpaTransactionManager
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean
import org.springframework.transaction.annotation.EnableTransactionManagement
import javax.persistence.EntityManager
import javax.persistence.EntityManagerFactory
import javax.sql.DataSource

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        basePackages = ["top.wteng.springboot.intergration.repository.second"], // 扫描的包名称
        entityManagerFactoryRef = "secondEntityManagerFactory", // 实体管理bean名称
        transactionManagerRef = "secondTransactionManager"  // 事务bean名称
)
open class SecondJpaConfiguration {
    @Bean(name = ["secondJpaProperties"])
    @ConfigurationProperties(prefix = "spring.jpa.second")
    open fun secondJpaProperties(): JpaProperties {
        return JpaProperties()
    }

    @Bean(name = ["secondEntityManagerFactory"])
    open fun secondEntityManagerFactory(
            @Qualifier("secondDataSource") secondDataSource: DataSource,
            @Qualifier("secondJpaProperties") jpaProperties: JpaProperties,
            builder: EntityManagerFactoryBuilder): LocalContainerEntityManagerFactoryBean {
        return builder.dataSource(secondDataSource)
                .properties(jpaProperties.properties)
                .packages("top.wteng.springboot.intergration.entity.second")  // 实体包路径
                .persistenceUnit("secondPersistenceUnit")
                .build()
    }

    @Bean(name = ["secondEntityManager"])
    open fun secondEntityManager(@Qualifier("secondEntityManagerFactory") managerFactory: EntityManagerFactory): EntityManager {
        return managerFactory.createEntityManager()
    }

    @Bean(name = ["secondTransactionManager"])
    open fun secondTransactionManager(@Qualifier("secondEntityManagerFactory") factory: EntityManagerFactory): JpaTransactionManager {
        return JpaTransactionManager(factory)
    }
}

经过以上数据源配置,数据源primary会扫描op.wteng.springboot.intergration.entity.primary下的实体定义与top.wteng.springboot.intergration.repository.primary下的repository定义,操作相关实体会应用主数据源,而第二数据源会扫描top.wteng.springboot.intergration.entity.second下的实体与top.wteng.springboot.intergration.repository.second下的repository定义,操作相关实体会应用第二数据源。

根据具体业务存储需求将不同的实体及repository定义到相应的包下即可,定义及使用同单数据源一致。