美文网首页
JPA多数据源切换 基于 SpringBoot 2.0 分析

JPA多数据源切换 基于 SpringBoot 2.0 分析

作者: Gxgeek | 来源:发表于2018-06-28 20:27 被阅读0次

    JPA自动装载的秘密

    在SpringBoot的项目中 会有一个
    spring-boot-autoconfigure 的包 通过然后查看 data.jpa 下面的就是有关Spring JPA 自动装配相关的东西


    image
    image
    image
    image

    上图显示
    SpringBoot 自动装配

    JpaRepositoriesAutoConfiguration

    -->它导入了@Import(JpaRepositoriesAutoConfigureRegistrar.class)

    JpaRepositoriesAutoConfigureRegistrar

    -----> 中有个类被 EnableJpaRepositories 注解

    EnableJpaRepositories -------->

    中使用 entityManagerFactoryRef 和 transactionManagerRef 的默认值 分别为entityManagerFactory(entity管理)和transactionManager(事务管理)

    image
    image
    JpaRepositoriesAutoConfiguration ------->

    @AutoConfigureAfter(HibernateJpaAutoConfiguration.class)
    ------>

    HibernateJpaAutoConfiguration @Import -------> HibernateJpaConfiguration
    HibernateJpaConfiguration extends JpaBaseConfiguration ---->
    JpaBaseConfiguration
    entityManagerFactory 和 transactionManager 这个两个Bean 是通过这样注入进入的
    

    多数据源主要涉及的Bean

    Bean

    • DataSource 数据源
    • LocalContainerEntityManagerFactoryBean 管理Entity
    • PlatformTransactionManager 事物
    @Bean
    @Primary
    @ConfigurationProperties("spring.datasource.primary")
    public DataSourceProperties primaryDataSourceProperties() {
        return new DataSourceProperties();
    }
    读取  spring.datasource.primary 下的数据
    @Bean
    @Primary
    @ConfigurationProperties("spring.datasource.primary")
    public DataSource primaryDataSource() {
        return primaryDataSourceProperties().initializeDataSourceBuilder().build();
    }
    
    
    EntityManagerFactory  注入  @Qualifier 指定数据源
    @Bean
    @Primary
    public LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory(
            EntityManagerFactoryBuilder builder,@Qualifier("primaryDataSource") DataSource dataSource) {
        return builder
                .dataSource(dataSource)
                .packages(Order.class)
                .properties(getVendorProperties(dataSource))
      //   . properties(jpaProperties.getHibernateProperties(dataSource)) // 获取并注入hibernate vender相关配置
    
                .persistenceUnit("primary")
                .build();
    }
    
    //TransactionManager  Bean注入
    @Bean
    @Primary
    public PlatformTransactionManager primaryTransactionManager(@Qualifier("primaryEntityManagerFactory") LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory) {
        JpaTransactionManager transactionManager = new JpaTransactionManager(primaryEntityManagerFactory.getObject());
        return transactionManager;
    }
    
        // repository 扫描的时候,并不确定哪个先扫描,查看源代码
        @EnableJpaRepositories(basePackageClasses = OrderRepository.class,
                entityManagerFactoryRef = "primaryEntityManagerFactory",transactionManagerRef = "primaryTransactionManager")
        @Primary
        public class PrimaryConfiguration {
        }
    
    

    多数据源配置

    spring:datasource:
      primary:
        url: jdbc:mysql://localhost:3306/seller?user=wch&password=wch123&useUnicode=true&characterEncoding=utf-8
      backup:
        url: jdbc:mysql://localhost:3306/seller-backup?user=wch&password=wch123&useUnicode=true&characterEncoding=utf-8
    
    image
    • ● 为一个LocalContainerEntityManagerFactoryBeantransactionManager的bean增加@Primary, 这样如果后面有自动配置的情况,系统能知道默认使用哪个EntityManagerFactoryBean和哪个transactionManager。
    • ● @EnableJpaRepository会自动使用默认名字为entityManagerFactory的LocalContainerEntityManagerFactoryBean 和默认名字为transactionManager的TransactionManager。如果要指定多个EntityManager的情况, 需要在@EnableJpaRepositories上使用entityManagerFactoryRef和transactionManagerRef另外指定不同的LocalContainerEntityManagerFactoryBean和TransactionManager.
    • ● 另外,TransactionManager必须是JpaTransactionManager!必须是JpaTransactionManager! 必须是JpaTransactionManager!入过的坑必须要说3遍。
    image
    image

    主从JPA分别注入 Spring时 如果扫描同一个包下 两个主从只会有一个生效
    修改源码 或则 分别放入两个包

    修改源代码 黑科技
    在本地项目中 建立和要修改的类相同的包名 和相同的类名
    源码复制
    tips:(当工程中有相同的类的时候,优先使用工程中的类而不再使用依赖包中的类)

    在 registerRepositoriesIn 注册Bean的方法中 这段代码中加入

    AbstractBeanDefinition beanDefinition = definitionBuilder.getBeanDefinition();
    String beanName = configurationSource.generateBeanName(beanDefinition);
    
    
    
    AnnotationMetadata metadata = (AnnotationMetadata) configurationSource.getSource();
    //判断配置类是否使用primary进行了标注,如果有,就设为primary
    if(metadata.hasAnnotation(Primary.class.getName())){
        beanDefinition.setPrimary(true);
    }else  if(metadata.hasAnnotation(RepositoryBeanNamePrefix.class.getName())){
        // 再判断是否使用了RepositoryBeanNamePrefix进行了标注,如果有,添加名称前缀
        Map<String,Object> prefixData = metadata.getAnnotationAttributes(RepositoryBeanNamePrefix.class.getName());
        String prefix = (String) prefixData.get("value");
        beanName = prefix + beanName;
    }
    
    
    
    if (LOGGER.isDebugEnabled()) {
        LOGGER.debug(REPOSITORY_REGISTRATION, extension.getModuleName(), beanName,
                configuration.getRepositoryInterface(), configuration.getRepositoryFactoryBeanClassName());
    }
    
    
    image

    相关文章

      网友评论

          本文标题:JPA多数据源切换 基于 SpringBoot 2.0 分析

          本文链接:https://www.haomeiwen.com/subject/opdgyftx.html