All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jn.sqlhelper.datasource.supports.spring.boot.DynamicDataSourceInfrastructureConfiguration Maven / Gradle / Ivy

/*
 * Copyright 2021 the original author or authors.
 *
 * Licensed under the Apache, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at  http://www.gnu.org/licenses/lgpl-2.0.html
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.jn.sqlhelper.datasource.supports.spring.boot;

import com.jn.langx.util.ClassLoaders;
import com.jn.langx.util.Strings;
import com.jn.sqlhelper.common.security.DriverPropertiesCipher;
import com.jn.sqlhelper.common.security.DriverPropertiesRsaCipher;
import com.jn.sqlhelper.datasource.DataSourceRegistry;
import com.jn.sqlhelper.datasource.DataSources;
import com.jn.sqlhelper.datasource.config.DataSourceProperties;
import com.jn.sqlhelper.datasource.config.DynamicDataSourcesProperties;
import com.jn.sqlhelper.datasource.factory.CentralizedDataSourceFactory;
import com.jn.sqlhelper.datasource.key.parser.DataSourceKeyDataSourceParser;
import com.jn.sqlhelper.datasource.supports.spring.config.DynamicDataSourcesPropertiesFactoryBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;

import java.util.List;

/**
 * @since 3.4.5
 */
@Configuration
@EnableConfigurationProperties(org.springframework.boot.autoconfigure.jdbc.DataSourceProperties.class)
@AutoConfigureBefore(DataSourceAutoConfiguration.class)
public class DynamicDataSourceInfrastructureConfiguration {
    private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceInfrastructureConfiguration.class);

    /**
     * @since 3.4.0
     */
    @Bean
    public CentralizedDataSourceFactory centralizedDataSourceFactory(DataSourceRegistry dataSourceRegistry) {
        CentralizedDataSourceFactory factory = new CentralizedDataSourceFactory();
        factory.setRegistry(dataSourceRegistry);
        return factory;
    }

    /**
     * @since 3.4.0
     */
    @Bean
    @ConditionalOnMissingBean
    @ConfigurationProperties(prefix = "sqlhelper.dynamic-datasource")
    public DynamicDataSourcesProperties namedDataSourcesProperties(
            ObjectProvider dataSourcesPropertiesFactoryBeanProvider,
            Environment environment) {

        String keyChoicesPointcutExpression = environment.getProperty("sqlhelper.dynamic-datasource.key-choices.expression");
        if (Strings.isNotBlank(keyChoicesPointcutExpression)) {
            String requiredClass = "com.jn.agileway.spring.aop.AspectJExpressionPointcutAdvisorBuilder";
            if (!ClassLoaders.hasClass(requiredClass, this.getClass().getClassLoader())) {
                StringBuilder log = new StringBuilder("The configuration property 'sqlhelper.dynamicDataSource.key-choices.expression' has specified, but can't find the class: '" + requiredClass + "', you should import the following jars to your classpath:\n")
                        .append("\t1) com.github.fangjinuo.agilway:agileway-spring:${agileway.version}.jar\n")
                        .append("\t2) org.springframework:spring-aop:${spring.version}.jar\n")
                        .append("\t3) org.aspectj:aspectjweaver:${aspectj.version}.jar\n")
                        .append("\t4) com.github.fangjinuo.langx:langx-java:${langx-java.version}.jar\n");
                logger.warn(log.toString());
            }
        }

        DynamicDataSourcesPropertiesFactoryBean factoryBean = dataSourcesPropertiesFactoryBeanProvider.getIfAvailable();
        if (factoryBean != null) {
            try {
                return factoryBean.getObject();
            } catch (Throwable ex) {
                logger.error(ex.getMessage(), ex);
            }
        }

        return new DynamicDataSourcesProperties();
    }


    /**
     * @since 3.4.0
     */
    @Bean
    public DataSourceRegistry dataSourceRegistry(ObjectProvider dataSourceKeyParserProvider, DynamicDataSourcesProperties dynamicDataSourcesProperties) {
        DataSourceRegistry dataSourceRegistry = new DataSourceRegistry();
        DataSourceKeyDataSourceParser dataSourceKeyParser = dataSourceKeyParserProvider.getIfAvailable();
        dataSourceRegistry.setKeyParser(dataSourceKeyParser);
        dataSourceRegistry.setHealthCheckTimeout(dynamicDataSourcesProperties.getHealthCheckTimeout());
        dataSourceRegistry.setHealthCheckCoreThreads(dynamicDataSourcesProperties.getHealthCheckCoreThreads());
        dataSourceRegistry.init();
        return dataSourceRegistry;
    }

    /**
     * 提供默认的基于 RSA 加解密工具,用于对数据加密
     *
     * @since 4.0.5
     */
    @Bean
    @ConditionalOnMissingBean
    public DriverPropertiesCipher driverPropertiesCipher(ObjectProvider dynamicDataSourcesPropertiesObjectProvider) {
        DynamicDataSourcesProperties dynamicDataSourcesProperties = dynamicDataSourcesPropertiesObjectProvider.getIfAvailable();
        DriverPropertiesRsaCipher cipher = new DriverPropertiesRsaCipher();
        if (dynamicDataSourcesProperties != null) {
            if (Strings.isNotBlank(dynamicDataSourcesProperties.getPublicKey())) {
                cipher.setPublicKey(dynamicDataSourcesProperties.getPublicKey());
            }
            if (Strings.isNotBlank(dynamicDataSourcesProperties.getPrivateKey())) {
                cipher.setPrivateKey(dynamicDataSourcesProperties.getPrivateKey());
            }
        }
        return cipher;
    }


    /**
     * @since 3.4.5
     */
    @Bean
    @ConditionalOnMissingBean
    public DriverPropertiesCipher dataSourcePropertiesCipherer(
            ObjectProvider dynamicDataSourcesPropertiesObjectProvider,
            // 由于 Spring 的构建顺序的原因,这里不能去直接使用 Spring Boot 里的DataSourceProperties, 用了也没有意义
            ObjectProvider dataSourcePropertiesObjectProvider,
            ObjectProvider cipherProvider
    ) {

        DriverPropertiesCipher cipher = cipherProvider.getIfAvailable();

        DynamicDataSourcesProperties dynamicDataSourcesProperties = dynamicDataSourcesPropertiesObjectProvider.getIfAvailable();
        if (dynamicDataSourcesProperties != null && cipher != null) {

            // 直接就开始进行 解密操作
            List dataSourcePropertiesList = dynamicDataSourcesProperties.getDatasources();
            if (dataSourcePropertiesList != null && !dataSourcePropertiesList.isEmpty()) {
                for (DataSourceProperties dataSourceProperties : dataSourcePropertiesList) {
                    String username = dataSourceProperties.getUsername();
                    if (Strings.isNotBlank(username)) {
                        username = DataSources.decrypt(cipher, username);
                        dataSourceProperties.setUsername(username);
                    }
                    String password = dataSourceProperties.getPassword();
                    if (Strings.isNotBlank(password)) {
                        password = DataSources.decrypt(cipher, password);
                        dataSourceProperties.setPassword(password);
                    }
                }
            }

        }

        // 对Spring内置属性进行解密操作
        org.springframework.boot.autoconfigure.jdbc.DataSourceProperties springBuiltinDataSourceProperties = dataSourcePropertiesObjectProvider.getIfAvailable();
        if (springBuiltinDataSourceProperties != null) {
            String username = springBuiltinDataSourceProperties.getUsername();
            if (Strings.isNotBlank(username)) {
                username = DataSources.decrypt(cipher, username);
                springBuiltinDataSourceProperties.setUsername(username);
            }
            String password = springBuiltinDataSourceProperties.getPassword();
            if (Strings.isNotBlank(password)) {
                password = DataSources.decrypt(cipher, password);
                springBuiltinDataSourceProperties.setPassword(password);
            }
        }

        return cipher;
    }


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy