3.3K Star 9.9K Fork 4.5K

iBase4J / iBase4J

 / 详情

iBase4J 架构研究建议

已完成
创建于  
2017-05-10 12:19

将项目跑起来,有一些个人建议,仅供作者与使用者参考~

iBase4J从技术选型来看,是没问题的,流程都一样。

我将源码debug,通读了一下,发现一些问题。

1.作者可能还没从单体应用转换为SOA服务化的思维。

文件:iBase4J-Biz-Web/src/main/resources/Spring-config.xml 中

<dubbo:reference id="sysProvider" interface="org.ibase4j.provider.ISysProvider" check="false" />
<dubbo:reference id="bizProvider" interface="org.ibase4j.provider.IBizProvider" check="false" />

代码里dubbo的注册服务只有这两个,实际在 dubbo 里有多少个呢?只有一个。
输入图片说明

输入图片说明

输入图片说明

这就导致了,dubbo无法管理这些服务,无法对服务进行限流,负载均衡,权重调节等等。

代码里,作者是怎么实现的呢?

查看源代码LoginController.java可知,通过,Parameter对象,传入service参数,method方法名,再通过,BaseProvider接口执行execute方法,找到service对应的service实现类,再找到方法,根据Parameter对象传入的Map或Bean,并去执行此方法。

provider.execute(new Parameter("sysUserService", "update").setModel(sysUser));

严重性:极高
缺点:
客户端必须要知道接口名。
客户端必须要知道有哪些参数。
dubbo无法很好的进行服务治理,负载均衡等等。

建议:
1.将所有服务化暴露给duboo.
2.服务化可以在ctrl层直接调用.
3.封装api层,model层给客户端。

2.在service中,Map与Bean混用。

如SysUserService类中:

	@Cacheable
	public Long queryUserIdByThirdParty(ThirdPartyUser param) {
		return thirdpartyMapper.queryUserIdByThirdParty(param.getProvider(), param.getOpenid());
	}
public Page<SysUser> query(Map<String, Object> params) {
		Map<String, String> userTypeMap = sysDicService.queryDicByType("USERTYPE");
		Page<SysUser> pageInfo = super.query(params);
		for (SysUser userBean : pageInfo.getRecords()) {
			if (userBean.getUserType() != null) {
				userBean.setUserTypeText(userTypeMap.get(userBean.getUserType().toString()));
			}
			if (userBean.getDeptId() != null) {
				SysDept sysDept = sysDeptService.queryById(userBean.getDeptId());
				if (sysDept != null) {
					userBean.setDeptName(sysDept.getDeptName());
				}
			}
			List<String> permissions = sysAuthorizeService.queryUserPermission(userBean.getId());
			for (String permission : permissions) {
				if (StringUtils.isBlank(userBean.getPermission())) {
					userBean.setPermission(permission);
				} else {
					userBean.setPermission(userBean.getPermission() + ";" + permission);
				}
			}
		}
		return pageInfo;
	}

根据阿里巴巴 Java 开发手册1.1.1 来看,不建议这样做,2个以上的参数,最好封装成查询Bean。

3.对于Redis缓存使用有点原始,数据字典处理有点原始。

如SysUserService类中,对于字典的文本读取转换:

public Page<SysUser> query(Map<String, Object> params) {
		Map<String, String> userTypeMap = sysDicService.queryDicByType("USERTYPE");
		Page<SysUser> pageInfo = super.query(params);
		for (SysUser userBean : pageInfo.getRecords()) {
			if (userBean.getUserType() != null) {
				userBean.setUserTypeText(userTypeMap.get(userBean.getUserType().toString()));
			}
			if (userBean.getDeptId() != null) {
				SysDept sysDept = sysDeptService.queryById(userBean.getDeptId());
				if (sysDept != null) {
					userBean.setDeptName(sysDept.getDeptName());
				}
			}
			List<String> permissions = sysAuthorizeService.queryUserPermission(userBean.getId());
			for (String permission : permissions) {
				if (StringUtils.isBlank(userBean.getPermission())) {
					userBean.setPermission(permission);
				} else {
					userBean.setPermission(userBean.getPermission() + ";" + permission);
				}
			}
		}
		return pageInfo;
	}

如LoginController类中,对于缓存:

String password = (String)CacheUtil.getCache().get("LOGIN_" + user.getAccount());
        if (StringUtils.isNotBlank(password)) {
            if (user.getPassword().equals(password)) {
                WebUtil.saveCurrentUser(request, user.getAccount());
                success = true;
            }
        }

如BaseService类中,对于缓存:

@Transactional
    @SuppressWarnings("unchecked")
    public T queryById(Long id) {
        String key = getCacheKey(id);
        T record = (T) CacheUtil.getCache().get(key);
        if (record == null) {
            String lockKey = getLockKey(id);
            if (CacheUtil.getLock(lockKey)) {
                try {
                    record = mapper.selectById(id);
                    CacheUtil.getCache().set(key, record);
                } finally {
                    CacheUtil.unlock(lockKey);
                }
            } else {
                logger.debug(getClass().getSimpleName() + ":" + id + " retry queryById.");
                sleep(20);
                return queryById(id);
            }
        }
        return record;
    }

4.手动事务控制与Service的异常处理
如BaseService中:

大量出现 @Transactional
 @Transactional
    public void delete(Long id) {
        try {
            mapper.deleteById(id);
            CacheUtil.getCache().del(getCacheKey(id));
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }
    @Transactional
    public void del(Long id, Long userId) {
        try {
            T record = this.queryById(id);
            record.setEnable(0);
            record.setUpdateTime(new Date());
            record.setUpdateBy(userId);
            mapper.updateById(record);
            CacheUtil.getCache().set(getCacheKey(id), record);
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

5.一不小心就被坑的机制

如BaseService中:

  @Transactional
    public T update(T record) {
        try {
            record.setUpdateTime(new Date());
            if (record.getId() == null) {
                record.setCreateTime(new Date());
                mapper.insert(record);
            } else {
                T org = this.queryById(record.getId());
                String lockKey = getLockKey(record.getId());
                if (CacheUtil.getLock(lockKey)) {
                    try {
                        T update = InstanceUtil.getDiff(org, record);
                        update.setId(record.getId());
                        mapper.updateById(update);
                        record = mapper.selectById(record.getId());
                        CacheUtil.getCache().set(getCacheKey(record.getId()), record);
                    } finally {
                        CacheUtil.unlock(lockKey);
                    }
                } else {
                    sleep(20);
                    return update(record);
                }
            }
        } catch (DuplicateKeyException e) {
            String msg = ExceptionUtil.getStackTraceAsString(e);
            logger.error(Constants.Exception_Head + msg, e);
            throw new RuntimeException("已经存在相同的配置.");
        } catch (Exception e) {
            String msg = ExceptionUtil.getStackTraceAsString(e);
            logger.error(Constants.Exception_Head + msg, e);
            throw new RuntimeException(msg);
        }
        return record;
    }

高并发情况下的锁与无限循环

https://my.oschina.net/linapex/blog/896623
写了篇博客,一些改进建议会追更在博客里面~ 有问题去博客留言啊~ 这里也可以

评论 (1)

linapex 创建了任务
A圣翔 关闭了任务

登录 后才可以发表评论

状态
负责人
里程碑
Pull Requests
关联的 Pull Requests 被合并后可能会关闭此 issue
分支
开始日期   -   截止日期
-
置顶选项
优先级
参与者(2)
728904 ite 1578931590 57753 linapex 1578915759
Java
1
https://gitee.com/iBase4J/iBase4J.git
git@gitee.com:iBase4J/iBase4J.git
iBase4J
iBase4J
iBase4J

搜索帮助