将项目跑起来,有一些个人建议,仅供作者与使用者参考~
iBase4J从技术选型来看,是没问题的,流程都一样。
我将源码debug,通读了一下,发现一些问题。
1.作者可能还没从单体应用转换为SOA服务化的思维。
文件:iBase4J-Biz-Web/src/main/resources/Spring-config.xml 中 <!-- dubbo --> <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; } ``` 高并发情况下的锁与无限循环
其他的我后面再补充
(adsbygoogle = window.adsbygoogle || []).push({});