多租户适配、多租户隔离

多租户适配

很多产品只有专属化版本,需要从产品底层进行尽量少的改造,满足上云之后多租户的数据、缓存、定时任务等隔离

多租户适配条目

条目名称 适配方案
持久层适配 支持schema和字段隔离两种方案
quartz定时任务 上下文无法获取租户信息,通过JobGroup识别
reids缓存 缓存key体现租户id即可
websocket场景 从cookie获取、前端调用diwork的api获取租户信息塞到cookie,后端websocket握手后从cookie获取
1. 持久层适配

考虑到本身业务的实际情况,要求数据源同时支持schema隔离和字段隔离,持久层的多租户适配业务代码需要零感知、无侵入,适配实现过程如下:

STEP-1. 表结构改造,追加租户字段、有预置脚本的表,需要跟租户字段建立联合主键;
STEP-2. 引入动态数据源,动态数据源查询租户信息,切换schema实现租户按schema隔离;
STEP-3. 改造dao,采用cglib加入Interceptor,在dao层方法的执> 行前加入拦截;
STEP-4. 用jsqlParser编写sql解析类,第3步拦截到的sql追加租户ID的条件;

动态数据源关键代码

获取租户信息中的schema信息,根据schema信息切换,租户信息通过rest接口获取,考虑了到性能已加ThreadLocal和redis两重缓存

protected Connection changeCatalog(Connection con) throws SQLException {
        String tenantId = InvocationInfoProxy.getTenantid();
        if (StringUtils.isBlank(tenantId)) {
            tenantId = "tenant";
        }
        String catalog = this.getCatalog(tenantId);
        if (StringUtils.isNotBlank(catalog)) {
            try {
                con.setCatalog(catalog);
            } catch (SQLException e) {
                logger.error("Error occurred when setting catalog for connection, Tenant ID is {}", tenantId);
                con.close();
                throw e;
            }
        } else {
//            logger.error("Switching catalog failed, check tenant ID -> {}!", tenantId);
            String defaultCatalog = PropertyUtil.getPropertyByKey("jdbc.catalog");
            if (StringUtils.isNotBlank(defaultCatalog) && !defaultCatalog.equals(con.getCatalog())) {
                con.setCatalog(defaultCatalog);
                logger.info("reset catalog for connection success!");
            }
        }
        return con;
    }
dao层改造关键代码

你可能感兴趣的:(技术资料,公有云,多租户,java,websocket,混合云)