自定义注解多数据源

发布时间 2023-10-31 15:34:37作者: Ideaway

使用案例

//添加到方法上面即可
@TargetDatasource("oh")
public int addDataConfigCatalog(DiitResourceCatalog dataCatalog) {
    
    return insertNumber;
}

@TargetDatasource("oh")
public int deleteDataConfigCatalog(String catalogIds) {
    
    return deleteNumber;
}

@TargetDatasource("oh")
public List<Map<String, String>> getLastYearUpdateCount(String catalogId) {
    List<Map<String, String>> lastYearUpdateCount = dataConfigCatalogMapper.getLastYearUpdateCount(catalogId);
    return lastYearUpdateCount;
}

TargetDatasource 注解

package diit.platform.bussiness.datasource;

import java.lang.annotation.*;

/*
 * 在方法上使用,表示使用哪个数据源,数据源注入注释
 * @author hm
 * */
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TargetDatasource {
	String value();
}

动态数据源注册 DynamicDataSourceRegister

package diit.platform.bussiness.datasource;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.boot.bind.RelaxedDataBinder;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * 动态数据源注册
 * @author hm
 */
public class DynamicDataSourceRegister implements ImportBeanDefinitionRegistrar, EnvironmentAware{
    private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceRegister.class);

    // 数据源配置信息
    private PropertyValues dataSourcePropertyValues;
    // 默认数据源
    private DataSource defaultDataSource;
    // 动态数据源
    private Map<String, DataSource> dynamicDataSources = new HashMap<>();
    /**
     * 加载多数据源配置
     */
    @Override
    public void setEnvironment(Environment env) {
        RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "jdbc.");
        String dsPrefixs = propertyResolver.getProperty("datasources");
        for (String dsPrefix : dsPrefixs.split(",")) {// 多个数据源
            Map<String, Object> map = propertyResolver.getSubProperties(dsPrefix + ".");
            DataSource ds = initDataSource(map);
            // 设置默认数据源
            if ("xjhjpt".equals(dsPrefix)) {
                defaultDataSource = ds;
            } else {
                dynamicDataSources.put(dsPrefix, ds);
            }
            dataBinder(ds, env);
        }
    }
    
    /*
     * 初始化数据源
     * @param map
     * @reurn
     */
    @SuppressWarnings("unchecked")
    public DataSource initDataSource(Map<String, Object> map) {
        DruidDataSource dataSource = null;
        try {
            dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(map);
            dataSource.setInitialSize(3);
            dataSource.setMaxActive(15);
            dataSource.setMinIdle(3);
            dataSource.setMaxWait(60000L);
            dataSource.setTimeBetweenEvictionRunsMillis(60000L);
            dataSource.setTimeBetweenLogStatsMillis(300000L);
            dataSource.setMinEvictableIdleTimeMillis(300000L);
            dataSource.setTestWhileIdle(true);
            dataSource.setTestOnBorrow(false);
            dataSource.setTestOnReturn(false);
            dataSource.setTimeBetweenConnectErrorMillis(60000L);    //连接出错过60秒重新尝试
        } catch (Exception e) {
            e.printStackTrace();
        }
        return dataSource;
    }
    
    /**
     * 加载数据源配置信息
     * @param dataSource
     * @param env
     */
    private void dataBinder(DataSource dataSource, Environment env) {
        RelaxedDataBinder dataBinder = new RelaxedDataBinder(dataSource);
        dataBinder.setIgnoreNestedProperties(false);// false
        dataBinder.setIgnoreInvalidFields(false);// false
        dataBinder.setIgnoreUnknownFields(true);// true
        if (dataSourcePropertyValues == null) {
            Map<String, Object> values = new RelaxedPropertyResolver(env, "datasource").getSubProperties(".");
            dataSourcePropertyValues = new MutablePropertyValues(values);
        }
        dataBinder.bind(dataSourcePropertyValues);
    }
    
    /**
     * 注册数据源been
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        Map<Object, Object> targetDataSources = new HashMap<Object, Object>();
        // 将主数据源添加到更多数据源中
        targetDataSources.put("dataSource", defaultDataSource);
        // 添加更多数据源
        targetDataSources.putAll(dynamicDataSources);

        // 创建DynamicDataSource
        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClass(DynamicDataSource.class);
        beanDefinition.setSynthetic(true);
        MutablePropertyValues mpv = beanDefinition.getPropertyValues();
        mpv.addPropertyValue("defaultTargetDataSource", defaultDataSource);
        mpv.addPropertyValue("targetDataSources", targetDataSources);
        registry.registerBeanDefinition("dataSource", beanDefinition);

        logger.info("多数据源注册成功");
    }

}

切换数据源 DynamicDataSourceAspect

package diit.platform.bussiness.datasource;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

/*
 * 切换数据源
 * @author hm
 * */
@Aspect
@Component
public class DynamicDataSourceAspect {
	@Before("@annotation(ds)")
	public void changeDataSource(JoinPoint point,TargetDatasource ds) {
		DynamicDataSource.setDataSourceType(ds.value());
	}
	
	@After("@annotation(ds)")
	public void restoreDataSource(JoinPoint point,TargetDatasource ds) {
		DynamicDataSource.clearDataSourceType();
	}
}

动态设置数据源 DynamicDataSource

package diit.platform.bussiness.datasource;

import lombok.extern.log4j.Log4j;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

/*
 * 动态设置数据源
 * @author hm
 * */
@Slf4j
public class DynamicDataSource extends AbstractRoutingDataSource{
	
	private static final ThreadLocal<String>contextHolder=new ThreadLocal<String>();

	public static void setDataSourceType(String datasourceType) {
		contextHolder.set(datasourceType);
	}
	
	public static String  getDataSourceType() {
		// TODO Auto-generated method stub
		return contextHolder.get();

	}
	
	public static void clearDataSourceType() {
		contextHolder.remove();
	}

	@Override
	protected Object determineCurrentLookupKey() {
		// TODO Auto-generated method stub
		return getDataSourceType();
	}
}

application.properties

jdbc.datasources=xjhjpt,ssba,kjfx,oh

jdbc.xjhjpt.driverClassName=oracle.jdbc.OracleDriver
jdbc.xjhjpt.url=jdbc:oracle:thin:@test2.diit.cn:4215/orcl
jdbc.xjhjpt.username=USE_HXK_XJHJ
jdbc.xjhjpt.password=USE_HXK_XJHJ

jdbc.ssba.driverClassName=oracle.jdbc.OracleDriver
jdbc.ssba.url=jdbc:oracle:thin:@test2.diit.cn:4215/orcl
jdbc.ssba.username=USE_ZTK
jdbc.ssba.password=USE_ZTK

jdbc.kjfx.driverClassName=oracle.jdbc.OracleDriver
jdbc.kjfx.url=jdbc:oracle:thin:@test2.diit.cn:4215/orcl
jdbc.kjfx.username=USE_HXK_XJHJ_KJ
jdbc.kjfx.password=USE_HXK_XJHJ_KJ

jdbc.oh.driverClassName=org.postgresql.Driver
jdbc.oh.url=jdbc:postgresql://192.9.30.225:5432/xinjiang_huiju_data_overview
jdbc.oh.username=postgres
jdbc.oh.password=postgres