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

来源:互联网 发布:java项目遇到的难题 编辑:程序博客网 时间:2024/05/22 12:13

背景:

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

项目基础框架:

SpringBoot+Mybatis

解决方案:

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

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

实现方式如下:

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

@Target({ElementType.METHOD,ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @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/ORCldataSource2015.username=username1dataSource2015.password=passwd1dataSource2015.driver-class-name=oracle.jdbc.driver.OracleDriverdataSource2016.url=jdbc:oracle:thin:@111.111.111.112:1521/ORCldataSource2016.username=username2dataSource2016.password=passwd2dataSource2016.driver-class-name=oracle.jdbc.driver.OracleDriver

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


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

3 0
原创粉丝点击