目前做的项目有一个需求就是,可以动态地查数据,能够在前端页面配置添加数据源,然后将数据源与业务进行绑定,当查询数据的时候并不是固定拿取yml配置文件中配置死的数据库配置,而是根据与业务绑定存在数据库表中的数据源进行连接。

 虽然若依已经做过数据源切换的封装了,通过AOP的方式去指定数据源,但是若依原本的只能是切换配置文件中已有的数据源,意味着如果我要再加一个新的数据源就需要去配置文件里加上,修改也是如此,这样显然很麻烦。不符合我们的需求。

 

/**

* 自定义多数据源切换注解

*

* 优先级:先方法,后类,如果方法覆盖了类上的数据源类型,以方法的为准,否则以类上的为准

*

* @author ruoyi

*/

@Target({ ElementType.METHOD, ElementType.TYPE })

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

public @interface DataSource

{

/**

* 切换数据源名称

*/

public DataSourceType value() default DataSourceType.MASTER;

}

然后我的思路是在若依原有的基础上再加一层处理,将原本若依编写的环绕通知注释掉,使用@Before()前置通知做处理

 在数据源枚举中加入一个新的枚举OTHER来标识切换数据源。

/**

* 数据源

*

* @author ruoyi

*/

public enum DataSourceType

{

/**

* 主库

*/

MASTER,

/**

* 从库

*/

SLAVE,

/**

* 其他

*/

OTHER

}

 在切面前置通知中对指定的类型进行判断,如果是master则使用默认的数据源,slave则使用配置文件中配置的从库,other则表示使用存在数据库表中的数据源,随后会根据请求方法的参数获取业务的ID然后去数据库查询与之绑定的数据源信息,然后将之设置成当前数据源,使用完后通过后置通知@After将数据源清除掉。

/**

* 多数据源处理

*

* @author ruoyi

*/

@Log4j2

@Aspect

@Order(1)

@Component

public class DataSourceAspect

{

protected Logger logger = LoggerFactory.getLogger(getClass());

@Resource

private ISysDataSourceService sysDataSourceService;

@Pointcut("@annotation(com.ruoyi.common.annotation.DataSource)"

+ "|| @within(com.ruoyi.common.annotation.DataSource)")

public void dsPointCut()

{

}

@Before("dsPointCut()")

public void doBefore(JoinPoint joinPoint) {

MethodSignature signature = (MethodSignature) joinPoint.getSignature();

Method method = signature.getMethod();

logger.info("方法名称: " + method.getName());

DataSource dataSource = method.getAnnotation(DataSource.class);

DruidConfig dynamicDataSourceConfig = SpringContextUtils.getBean(DruidConfig.class);

Map map = dynamicDataSourceConfig.getTargetDataSources();

log.info("TargetDataSources==="+map.toString());

// 通过判断 DataSource 中的值来判断当前方法应用哪个数据源

String value = String.valueOf(dataSource.value());

boolean flag;

String name = "";

switch (value) {

case "MASTER":

flag = true;

name = DataSourceType.MASTER.name();

break;

case "SLAVE":

flag = true;

name = DataSourceType.SLAVE.name();

break;

case "OTHER":

flag = true;

name = "OTHER";

if (map.get(name) != null) {

break;

} else {

//获取传入参数

Object[] args = joinPoint.getArgs();

JSONObject json = (JSONObject) args[0];

Long dataSourceId = json.getLong("dataSourceId");

log.info("获取的数据源ID=="+dataSourceId);

//从传入参数获取业务ID查找数据源信息,设置数据源信息

SysDataSource source = sysDataSourceService.getById(dataSourceId);

String url = source.getDbUrl();

String username = source.getDbUsername();

//密码解密

String password = SecurityUtil.jiemi(source.getDbPwd());

log.info("解密后密码=="+password);

log.info("数据源切换:" + url);

DruidDataSource s = dynamicDataSourceConfig.createDataSource(name, url, username,

password, source.getDbDriver());

}

break;

default:

flag = false;

break;

}

if (!flag) {

logger.error("************注意************");

name = DataSourceType.MASTER.name();

logger.info("加载到未知数据源,系统自动设置数据源为默认数据源!");

}

DynamicDataSource.setDataSource(name);

//设置成数据源

DynamicDataSourceContextHolder.setDataSourceType(name);

logger.info("当前数据源: " + name);

logger.info("当前数据源: " + ((DruidDataSource) map.get(name)).getUrl());

logger.info("set datasource is " + name);

}

@After("dsPointCut()")

public void doAfter() {

logger.info("*********准备清除数据源*********");

DynamicDataSource.clearDataSource();

DynamicDataSourceContextHolder.clearDataSourceType();

logger.info("*********数据源清除成功*********");

}

需要注意的是在druidConfig的配置文件中加上新添的枚举类型

 当需要切换数据源时,只需在类上或者方法上加上注解

@DataSource(value = DataSourceType.OTHER)

推荐文章

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。