栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

自定义注解实现多数据源切换

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

自定义注解实现多数据源切换

自定义注解实现多数据源切换 定义注解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSourceTarget {
	 String value() default DataSourceTarget.PAY;
	 public static String PAY = "payDataSource";
	 public static String BUZ = "buzDataSource";
     public static String ACCOUNT = "accountDataSource";
}
application.properties配置数据源
dataSource.driverClassName = com.mysql.jdbc.Driver
# 初始化连接
dataSource.initialSize = 10
# 最大连接数量
dataSource.maxActive = 100
# 最大空闲连接
dataSource.maxIdle = 10
# 最小空闲连接
dataSource.minIdle = 2
# 连接有效性检查
dataSource.testOnBorrow = false
dataSource.testWhileIdle = true
dataSource.validationQuery = select 1

#pay数据源--finance_pay_v2
pay.dataSource.url = jdbc:mysql://r1.fdb.local/finance_pay_v2?useUnicode=true&characterEncoding=utf-8
pay.dataSource.username = fin_pay_v2
pay.dataSource.password = ******

#buz数据源--finance_buz_v2
buz.dataSource.url = jdbc:mysql://r1.fdb.local/finance_buz_v2?useUnicode=true&characterEncoding=utf-8
buz.dataSource.username = fin_buz_v2
buz.dataSource.password = ******

#account数据源--finance_account_v2
account.dataSource.url = jdbc:mysql://r1.fdb.local/finance_account_v2?useUnicode=true&characterEncoding=utf-8
account.dataSource.username = fin_account_v2
account.dataSource.password = ******
继承AbstractRoutingDataSource

SpringBoot提供AbstractRoutingDataSource类让用户根据自己定义的规则选取当前数据源,实现可动态切换的数据源。它的抽象方法 determineCurrentLookupKey() 决定使用哪个数据源。AbstractRoutingDataSource的getConnection() 方法根据查找 lookup key 键对不同目标数据源的调用,通常是通过(但不一定)某些线程绑定的事物上下文来实现。

public class DynamicDataSource extends AbstractRoutingDataSource
{
	
	@Override
	protected Object determineCurrentLookupKey()
	{
		//DynamicDataSourceHolder有获取和设置当前数据库的方法get & put
		return DynamicDataSourceHolder.getDataSource();
	}

}
使用当前线程操作数据源对应名称
public class DynamicDataSourceHolder {
	public static final ThreadLocal HOLDER = new ThreadLocal();

    // 将数据源对应的名称放入当前线程
	public static void putDataSource(String name) {
		HOLDER.set(name);
	}
    // 将数据源对应的名称从当前线程取出
	public static String getDataSource() {
		return HOLDER.get();
	}
	// 清除
	public static void clearCustomerType() {
		HOLDER.remove();
	}
}
读取数据源配置

实现EnvironmentAware接口,重写setEnvironment方法,在工程启动的时候可以获得application.properties配置文件中配置的属性值

@Component
public class DataBaseConfig implements EnvironmentAware{
    
    private Environment environment;
    
    @Override
	public void setEnvironment(Environment environment){
		this.environment = environment;
	}
   
    
    private DataSource payDataSource() throws Exception {

		Properties p =new Properties();
	    p.put("driverClassName",environment.getRequiredProperty("dataSource.driverClassName"));
	    p.put("url",environment.getRequiredProperty("pay.dataSource.url"));
	    p.put("username",environment.getRequiredProperty("pay.dataSource.username"));
	    p.put("password",environment.getRequiredProperty("pay.dataSource.password"));
	    p.put("initialSize",environment.getRequiredProperty("dataSource.initialSize"));
	    p.put("maxActive",environment.getRequiredProperty("dataSource.maxActive"));
	    p.put("maxIdle",environment.getRequiredProperty("dataSource.maxIdle"));
	    p.put("minIdle",environment.getRequiredProperty("dataSource.minIdle"));
	    p.put("testOnBorrow",environment.getRequiredProperty("dataSource.testOnBorrow"));
	    p.put("testWhileIdle",environment.getRequiredProperty("dataSource.testWhileIdle"));
	    p.put("validationQuery",environment.getRequiredProperty("dataSource.validationQuery"));
	    DataSource dataSource  =  DruidDataSourceFactory.createDataSource(p);
		return dataSource;
	}
	
	private DataSource buzDataSource() throws Exception{
        Properties p =new Properties();
	    p.put("driverClassName",environment.getRequiredProperty("dataSource.driverClassName"));
	    p.put("url",environment.getRequiredProperty("buz.dataSource.url"));
	    p.put("username",environment.getRequiredProperty("buz.dataSource.username"));
	    p.put("password",environment.getRequiredProperty("buz.dataSource.password"));
	    p.put("initialSize",environment.getRequiredProperty("dataSource.initialSize"));
	    p.put("maxActive",environment.getRequiredProperty("dataSource.maxActive"));
	    p.put("maxIdle",environment.getRequiredProperty("dataSource.maxIdle"));
	    p.put("minIdle",environment.getRequiredProperty("dataSource.minIdle"));
	    p.put("testOnBorrow",environment.getRequiredProperty("dataSource.testOnBorrow"));
	    p.put("testWhileIdle",environment.getRequiredProperty("dataSource.testWhileIdle"));
	    p.put("validationQuery",environment.getRequiredProperty("dataSource.validationQuery"));
	    DataSource dataSource  =  DruidDataSourceFactory.createDataSource(p);
		return dataSource;
    }
    
    private DataSource accountDataSource() throws Exception{
        Properties p =new Properties();
	    p.put("driverClassName",environment.getRequiredProperty("dataSource.driverClassName"));
	    p.put("url",environment.getRequiredProperty("account.dataSource.url"));
	    p.put("username",environment.getRequiredProperty("account.dataSource.username"));
	    p.put("password",environment.getRequiredProperty("account.dataSource.password"));
	    p.put("initialSize",environment.getRequiredProperty("dataSource.initialSize"));
	    p.put("maxActive",environment.getRequiredProperty("dataSource.maxActive"));
	    p.put("maxIdle",environment.getRequiredProperty("dataSource.maxIdle"));
	    p.put("minIdle",environment.getRequiredProperty("dataSource.minIdle"));
	    p.put("testOnBorrow",environment.getRequiredProperty("dataSource.testOnBorrow"));
	    p.put("testWhileIdle",environment.getRequiredProperty("dataSource.testWhileIdle"));
	    p.put("validationQuery",environment.getRequiredProperty("dataSource.validationQuery"));
	    DataSource dataSource  =  DruidDataSourceFactory.createDataSource(p);
		return dataSource;
    }
    
    
    @Bean(name = "dataSource")
	public DynamicDataSource dataSource() throws Exception
	{

		DataSource pay = payDataSource();
		DataSource buz = buzDataSource();
		DataSource account = accountDataSource();
	
		
		Map targetDataSources = new HashMap<>();
		targetDataSources.put(DataSourceTarget.PAY, pay);
		targetDataSources.put(DataSourceTarget.BUZ, buz);
		targetDataSources.put(DataSourceTarget.ACCOUNT, account);
	

		
		DynamicDataSource dataSource = new DynamicDataSource();
		dataSource.setTargetDataSources(targetDataSources);
		dataSource.setDefaultTargetDataSource(pay);

		return dataSource;
	}
    
    @Bean(name = "sessionFactory")
	public SqlSessionFactory sqlSessionFactory(AbstractRoutingDataSource dynamicDataSource) throws Exception
	{
		SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
		Properties configurationProperties = new Properties();
		configurationProperties.put("cacheEnabled", true);
		configurationProperties.put("lazyLoadingEnabled", true);
		configurationProperties.put("aggressiveLazyLoading", false);
		configurationProperties.put("multipleResultSetsEnabled", true);
		configurationProperties.put("useColumnLabel", true);
		configurationProperties.put("useGeneratedKeys", true);
		configurationProperties.put("autoMappingBehavior", "FULL");
		configurationProperties.put("defaultExecutorType", "BATCH");
		configurationProperties.put("defaultStatementTimeout", 25000);
		sqlSessionFactoryBean.setConfigurationProperties(configurationProperties);

		// 设置动态数据源
		sqlSessionFactoryBean.setDataSource(dynamicDataSource);
		// 设置mybatis的配置文件路径
		sqlSessionFactoryBean.setConfigLocation(new ClassPathResource("mybatis/mybatis-config.xml"));
		// 设置mapper文件路径
		PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
		sqlSessionFactoryBean.setMapperLocations(pathMatchingResourcePatternResolver
				.getResources("classpath*:mybatis/mapper/*-mapper.xml"));

		return sqlSessionFactoryBean.getObject();
	}
    
    @Bean(name = "sessionTemplate")
	public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sessionFactory)
	{
		SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(sessionFactory);
		return sqlSessionTemplate;
	}
    
    @Bean
	public DataSourceTransactionManager dataSourceTransactionManager(AbstractRoutingDataSource dynamicDataSource)
	{
		DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(dynamicDataSource);
		return dataSourceTransactionManager;
	}
}
切面
@Aspect
@Component
public class DataSourceAspect {
    private static final Logger logger = LoggerFactory.getLogger(DataSourceAspect.class);

    @Pointcut("execution(* com.*.*.multi.base.*.*.*(..))")
	private void aspectPoint() {
		// 定义一个切入点
	}
    
    @Before("aspectPoint()")
	public void doBefore(JoinPoint point) {
		Object target = point.getTarget();
		String method = point.getSignature().getName();
		Class[] classz = target.getClass().getInterfaces();
		Class[] parameterTypes = ((MethodSignature) point.getSignature())
				.getMethod().getParameterTypes();

		Method m = null;
		try {
			m = classz[0].getMethod(method, parameterTypes);
			logger.info("当前方法:" + m.getName() + "类名称:" + classz[0].getName());
		} catch (Exception e) {
			logger.error(e.getMessage());
			return;
		}

		if (m != null && m.isAnnotationPresent(DataSourceTarget.class)) {
			DataSourceTarget data = m.getAnnotation(DataSourceTarget.class);// 获取访问mapper中的注释
			DynamicDataSourceHolder.putDataSource(data.value());// 获取注释中的value值,确定访问的数据源
			logger.info("当前数据源---" + data.value());
		} else {
			logger.info("当前数据源---主数据源");
		}
	}
    
    @After("aspectPoint()")
	public void doAfter(JoinPoint point) {
		// 清除数据源配置
		DynamicDataSourceHolder.clearCustomerType();
	}
}
总结

总体流程就是,工程启动时,将所有使用的数据源以map形式加载到AbstractRoutingDataSource的子类targetDataSources属性中,在方法执行前,由切面检查当前类或者方法上有无自定义注解,如果有,则将注解对应名设置到当前线程中,由AbstractRoutingDataSource切换当前线程中数据源名称对应数据源。在方法执行后,再将该数据源清除,恢复默认数据源

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/831556.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号