zl程序教程

您现在的位置是:首页 >  其他

当前栏目

一步一步实现若依框架--2.1实现多数据源

2023-04-18 15:21:05 时间
  在项目中使用到了若依,想从头实现一下。思路就是把项目中涉及到的知识内容单独拎出来理解和做测试,然后再合到系统里去,重点的地方会将涉及到的知识进行总结和扩展。顺序是由后端到前端。 代码地址:https://github.com/hunji/RYMirror
  common模块中的功能,大部分是通过自定义注解+AOP来实现通用功能。第2章节就会逐个实现各注解功能。本篇2.1是实现多数据源。代码中有打tag,跟着步骤来的,可以边看程序边看总结。
  
1)原理:
  mybatis在执行sql前通过数据源去找数据库连接-->determineCurrentLookupKey(AbstractRoutingDataSource);所以通过注解拦截方法,在调用之前动态切换数据源名称即可。切换数据源,就要先给spring注入这些定义好的数据源,也就是程序中自定义的类DynamicDataSource的实例。所以问题就转换成了怎么准备多个数据源。通过DruidConfig中注入数据源,其中共性的属性由DruidProperties设置,各个数据源的特有属性根据注解ConfigurationProperties设置。最后,由于不同的请求是在不同的线程中的,可能去请求不同的数据源,所以这里要使用ThreadLocal保证现场安全来切换数据源名称。
 
2)ThreadLocal它可以给当前线程关联一个数据(可以是普通变量,可以是对象,也可以是数组,集合)
   ThreadLocal 的特点:
  •   ThreadLocal可以为当前线程关联一个数据。(它可以像Map一样存取数据,key为当前线程)
  •   每一个 ThreadLocal对象,只能为当前线程关联一个数据,如果要为当前线程关联多个数据,就需要使用多个ThreadLocal对象实例。
  •   每个ThreadLocal对象实例定义的时候,一般都是static类型
  •   ThreadLocal中保存数据,在线程销毁后。会由JVM虚拟自动释放。这里销毁的是threadmap,如果说
这里有可能造成内存溢出,所以切点执行后手动清除一下。
 
3)@annotation 方法级别@within 对象级别
4)查找注解的方式:
public DataSource getDataSource(ProceedingJoinPoint point)
{
    MethodSignature signature = (MethodSignature) point.getSignature();
    // 查找方法上的注解
    DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class);
    if (Objects.nonNull(dataSource))
    {
        return dataSource;
    }
    // 查找类上的注解
    return AnnotationUtils.findAnnotation(signature.getDeclaringType(), DataSource.class);
}

  这个方法就是为什么DataSource注解优先级是先方法后类

5)关于ConfigurationProperties的使用

  有个问题就是各个数据源的name,password,url怎么设置到动态数据源中的。这里其实是ConfigurationProperties的用法。@Configuration注解的配置类中通过@Bean注解在某个方法上将方法返回的对象定义为一个Bean,并使用配置文件中相应的属性初始化该Bean的属性。

@Bean
@ConfigurationProperties("spring.datasource.druid.slave")
@ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")
public DataSource slaveDataSource(DruidProperties druidProperties)
{
    DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
    return druidProperties.dataSource(dataSource);
}
public DruidDataSource dataSource(DruidDataSource datasource)

  返回类型DruidDataSource是有这些属性的。

 

  这种方式提供了一个思路,就是解决怎么把既有共性,又有特殊属性的一些配置,读取到同一个类中。可以使用一个map来获取这些属性去处理,也可以像上面这种方式,需用自己去map中遍历,

 

6) system模块里的mybatis是从哪里引入依赖的?system 依赖 common,conmon中引入了pagehelper,pagehelper中依赖了mybatis
7)mybatis开启驼峰命名自动映射     mapUnderscoreToCamelCase
8)单元测试
复制一个数据库,重命名为ry-vue2,修改sysUser中的数据。在system模块中添加sysUser的相关代码,在admin的test中添加单元测试。
@Service
public class SysUserServiceImpl implements ISysUserService {
    @Autowired
    private SysUserMapper mapper;


    @Override
    @DataSource(DataSourceType.MASTER)
    public List<SysUser> getAllUsersMaster() {
        return mapper.getAllUsersMaster();
    }


    @Override
    @DataSource(DataSourceType.SLAVE)
    public List<SysUser> getAllUsersSlave() {
        return mapper.getAllUsersSlave();
    }
}

 

==》扩展点(可以扩展的内容):

1.多数据源在yml文件中加上后不需要改程序
2.可以通过前台界面配置指定数据源

 代码地址:

https://github.com/hunji/RYMirror/releases/tag/2.1%E5%A4%9A%E6%95%B0%E6%8D%AE%E6%BA%90