SpringBoot+Mybatis中使用动态代理方式动态切换datasource

背景:

项目原先只有一个数据库(开发工作已基本完成),后来又添加了一个库,两个库数据结构一致,查询逻辑基本一致,只是数据对应的年份不一样,客户提出的需求是根据可以自主选择查询不同年份的数据,而默认框架实现里没有多数据源的方法。

项目基础框架:

SpringBoot+Mybatis

解决方案:

有两套系统同时使用这两个库,另外一个系统的同学的解决方案是另开一个服务器,直接使用不同的数据库配置。

我觉得这样干不符合我的审美,考虑通过前台在用户选择年份后,固定传递年份参数,后台根据此参数动态切换数据源的方式实现。

实现方式如下:

1、定义一个注解TimeCare,对需要动态切换的controller或method进行标注(即带有此注解的controller或者方法在执行时需要根据年份动态切换数据源,其他的使用默认数据源)。

@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TimeCare { }

2、定义切面,对有TimeCare注解的执行过程进行拦截。

 @Around(value="@within(co.lewis.aspect.TimeCare)")
    public Object arround(ProceedingJoinPoint pjp) throws Throwable {
        HttpServletRequest request =((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
        String year=request.getParameter("year");
        if(year==null||year.trim().length()==0){
            year= ConstParameters.default_last_year;
        }
        DataSourceWrapper.resetDataSource(year);//设置年份,此处使用一个ThreadLocal对象存储年份数据
        Object ret=pjp.proceed();
        DataSourceWrapper.resetDataSource(null);//将年份信息重新置空
        return ret;
    }

3、定义一个动态代理类,代替默认的DataSource实现类

@Configuration
@EnableConfigurationProperties({DataSource2015.class.......})//注册数据源1、数据源2......
public class DataSourceWrapper implements InvocationHandler {

    public static void resetDataSource(String key){
        year.set(key);
    }

    private static ThreadLocal<String> year=new ThreadLocal<>();

    @Bean(name = "dataSource",destroyMethod = "close") //注册datasource bean
    public DataSource getDataSource(){
        return (DataSource) this.bind();//生成代理对象
    }

    public Object bind(){
        return Proxy.newProxyInstance(getClass().getClassLoader(),
                new Class[]{DataSource.class,AutoCloseable.class, CommonDataSource.class, Wrapper.class},this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return method.invoke(detemine(),args);//在调用数据源内部方法时动态决定使用哪一个数据源
    }

    DataSource detemine(){}
}

4、在application.properties文件中添加数据源配置

dataSource2015.url=jdbc:oracle:thin:@111.111.111.111:1521/ORCl
dataSource2015.username=username1
dataSource2015.password=passwd1
dataSource2015.driver-class-name=oracle.jdbc.driver.OracleDriver

dataSource2016.url=jdbc:oracle:thin:@111.111.111.112:1521/ORCl
dataSource2016.username=username2
dataSource2016.password=passwd2
dataSource2016.driver-class-name=oracle.jdbc.driver.OracleDriver

5、实现数据源注册类DataSource2015、DataSource2016等(略)


如此,便实现了在不做太大改动的情况下使用多个数据源。即使以后又添加新的数据库,也可以通过简单添加新的DataSource注册类的方式实现新数据库查询。

猜你喜欢

转载自blog.csdn.net/qq631431929/article/details/62889007
今日推荐