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}