001/* 002 * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package com.mybatisflex.spring.boot; 017 018import com.mybatisflex.core.datasource.DataSourceBuilder; 019import com.mybatisflex.core.datasource.DataSourceDecipher; 020import com.mybatisflex.core.datasource.DataSourceManager; 021import com.mybatisflex.core.datasource.FlexDataSource; 022import com.mybatisflex.spring.boot.MybatisFlexProperties.SeataConfig; 023import com.mybatisflex.spring.datasource.DataSourceAdvice; 024import io.seata.rm.datasource.DataSourceProxy; 025import io.seata.rm.datasource.xa.DataSourceProxyXA; 026import org.apache.ibatis.session.SqlSessionFactory; 027import org.mybatis.spring.SqlSessionFactoryBean; 028import org.springframework.beans.factory.ObjectProvider; 029import org.springframework.beans.factory.config.BeanDefinition; 030import org.springframework.boot.autoconfigure.AutoConfigureBefore; 031import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 032import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 033import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; 034import org.springframework.boot.context.properties.EnableConfigurationProperties; 035import org.springframework.context.annotation.Bean; 036import org.springframework.context.annotation.Configuration; 037import org.springframework.context.annotation.Role; 038 039import javax.sql.DataSource; 040import java.util.Map; 041 042 043/** 044 * MyBatis-Flex 多数据源的配置支持。 045 * 046 * @author michael 047 */ 048@ConditionalOnMybatisFlexDatasource() 049@Configuration(proxyBeanMethods = false) 050@EnableConfigurationProperties(MybatisFlexProperties.class) 051@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class}) 052@AutoConfigureBefore(value = DataSourceAutoConfiguration.class 053 , name = "com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure") 054public class MultiDataSourceAutoConfiguration { 055 056 057 private final Map<String, Map<String, String>> dataSourceProperties; 058 059 private final SeataConfig seataConfig; 060 061 //数据源解密器 062 protected final DataSourceDecipher dataSourceDecipher; 063 064 065 public MultiDataSourceAutoConfiguration(MybatisFlexProperties properties 066 , ObjectProvider<DataSourceDecipher> dataSourceDecipherProvider 067 ) { 068 dataSourceProperties = properties.getDatasource(); 069 dataSourceDecipher = dataSourceDecipherProvider.getIfAvailable(); 070 seataConfig = properties.getSeataConfig(); 071 } 072 073 @Bean 074 @ConditionalOnMissingBean 075 public DataSource dataSource() { 076 077 FlexDataSource flexDataSource = null; 078 079 if (dataSourceProperties != null && !dataSourceProperties.isEmpty()) { 080 081 if (dataSourceDecipher != null) { 082 DataSourceManager.setDecipher(dataSourceDecipher); 083 } 084 085 for (Map.Entry<String, Map<String, String>> entry : dataSourceProperties.entrySet()) { 086 087 DataSource dataSource = new DataSourceBuilder(entry.getValue()).build(); 088 DataSourceManager.decryptDataSource(dataSource); 089 090 if (seataConfig != null && seataConfig.isEnable()) { 091 if (seataConfig.getSeataMode() == MybatisFlexProperties.SeataMode.XA) { 092 dataSource = new DataSourceProxyXA(dataSource); 093 } else { 094 dataSource = new DataSourceProxy(dataSource); 095 } 096 } 097 098 if (flexDataSource == null) { 099 flexDataSource = new FlexDataSource(entry.getKey(), dataSource, false); 100 } else { 101 flexDataSource.addDataSource(entry.getKey(), dataSource, false); 102 } 103 } 104 } 105 106 return flexDataSource; 107 } 108 109 110 /** 111 * {@link com.mybatisflex.annotation.UseDataSource} 注解切换数据源切面。 112 */ 113 @Bean 114 @ConditionalOnMissingBean 115 @Role(BeanDefinition.ROLE_INFRASTRUCTURE) 116 public DataSourceAdvice dataSourceAdvice() { 117 return new DataSourceAdvice(); 118 } 119 120}