springBoot学习---从SSM的动态数据源到SpringBoot的动态数据源的实现方案一

一共有俩中实现方案,最近方案一已经调通,记录如下:

难点:如何将动态数据源的注入到sqlSessionFactory中。

方案一的实现数据源的注入,依赖于注解@MapperScan,在这个注解中有下面的属性值,我们人为生成,然后注入进去。

sqlSessionFactoryRef

方案二的实现方式,学习我们的通用Mapper插件,采用实现接口

ImportBeanDefinitionRegistrar

的方式,直接注入一个数据源到IOC容器中,其他都无需修改。 

代码如下:

// 实现动态数据源,都需要继承该接口,应用模板方法设计模式,
//由子类实现 路由数据源 的具体实现
package com.itw.learn.config;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
	protected Object determineCurrentLookupKey() {
		return DataSourceContextHandler.getDataSourceType();
	}
}

package com.itw.learn.config;
public class DataSourceContextHandler {

	private static final ThreadLocal<String> context = new ThreadLocal();
	
	public static  void setDataSourceType(String type){
		
		   context.set(type);
	}
	public static Object getDataSourceType() {
		//给默认值,如果取出来为null,则走主库,可以抽取到配置信息中,从配置文件查
		return context.get()==null ? "primary" : context.get();
	}

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

接下来就是定义切面,我们在目标方法执行前进行数据源的切换操作,方法执行完后,清除数据源类型。

package com.itw.learn.config;

import java.lang.annotation.*;

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TargetDatasource {
   String value() default "primary";

}

package com.itw.learn.config;

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.core.annotation.Order;
import org.springframework.stereotype.Component;
// 该切面优先级高于事务,必须保证事务开启前,已确定数据源
@Aspect
@Order(-1)
@Component
public class DynamicDataSourceAspect {

	@Before("@annotation(dataSource)")
	public void setTargetDatasource(JoinPoint point, TargetDatasource dataSource){
		String value = dataSource.value();
		if ("primary".equals(value)){
			DataSourceContextHandler.setDataSourceType("primary");
		}else if ("slave1".equals(value)){
			DataSourceContextHandler.setDataSourceType("slave1");
		}else {//如果是其他值,默认走写库
			DataSourceContextHandler.setDataSourceType("primary");
		}
	}

	/**
	 * 重置数据源
	 * @param point
	 * @param dataSource
	 */
	@After("@annotation(dataSource))")
	public void restoreDataSource(JoinPoint point, TargetDatasource dataSource) {
		DataSourceContextHandler.clearDataSourceType();
		System.out.println("Restore DataSource to [" + DataSourceContextHandler.getDataSourceType()
				+ "] in Method [" + point.getSignature() + "]");
	}
}

 接下来,就是注册我们的数据源和seqSessionFactory的操作:

package com.itw.learn.config;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

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

//重要的是这个将我们的sqlSessionFactory注入进去。
@Configuration
@MapperScan(basePackages = "com.itw.learn.dao", sqlSessionFactoryRef = "SqlSessionFactory") //basePackages 我们接口文件的地址
public class DynamicDataSourceConfig implements EnvironmentAware {

	private Environment env;
    //由于我使用的是yml文件的方式,在DataSourceBuilder中的properties属性没有赋值
	//需要手动赋值
	// 将这个对象放入Spring容器中
	@Bean(name = "PrimaryDataSource")
	public DataSource getDateSource1() {
		return DataSourceBuilder
				.create()
				.driverClassName(env.getProperty("spring.datasource.primary.driver-class-name"))
				.url(env.getProperty("spring.datasource.primary.url"))
				.username( env.getProperty("spring.datasource.primary.username"))
				.password(env.getProperty("spring.datasource.primary.password"))
				.build();
	}


	@Bean(name = "SecondaryDataSource")
	@ConfigurationProperties(prefix = "spring.datasource.slave1")
	public DataSource getDateSource2() {
		return DataSourceBuilder
				.create()
				.driverClassName(env.getProperty("spring.datasource.slave1.driver-class-name"))
				.url(env.getProperty("spring.datasource.slave1.url"))
				.username( env.getProperty("spring.datasource.slave1.username"))
				.password(env.getProperty("spring.datasource.slave1.password"))
				.build();
	}

	@Bean(name = "dynamicDataSource")
	public DynamicDataSource DataSource(@Qualifier("PrimaryDataSource") DataSource primaryDataSource,
										@Qualifier("SecondaryDataSource") DataSource secondaryDataSource) {

		//这个地方是比较核心的targetDataSource 集合是我们数据库和名字之间的映射
		Map<Object, Object> targetDataSource = new HashMap<>();
		targetDataSource.put("primary", primaryDataSource);
		targetDataSource.put("slave1", secondaryDataSource);
		DynamicDataSource dataSource = new DynamicDataSource();
		dataSource.setTargetDataSources(targetDataSource);
		dataSource.setDefaultTargetDataSource(primaryDataSource);//设置默认对象
		return dataSource;
	}


	@Bean(name = "SqlSessionFactory")
	public SqlSessionFactory SqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dynamicDataSource)
			throws Exception {
		SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
		bean.setDataSource(dynamicDataSource);
		bean.setMapperLocations(
				new PathMatchingResourcePatternResolver()
						.getResources("classpath*:mapping/*/*.xml"));//设置我们的xml文件路径
		return bean.getObject();
	}

	@Override
	public void setEnvironment(Environment environment) {
		this.env = environment ;
	}
}

目录结构:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值