将项目跑起来,有一些个人建议,仅供作者与使用者参考~
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
写了篇博客,一些改进建议会追更在博客里面~ 有问题去博客留言啊~ 这里也可以