1.业务场景
当下主系统衍生子业务系统已经成为常态,像京东的物流和金融,阿里的支付宝和淘宝。
子业务系统需要对主系统的资源进行访问,这里的资源我具体化为数据库数据,但日常业务中可能不只是数据。
抽象服务给子业务系统进行调用访问? 各种各样子业务系统可能会出现千奇百怪的需求,主系统只有不断增加服务去拥抱变化。
创建多个数据库子账号给子业务系统?无法统一监控,而且很容易导致数据库瓶颈,到时候就需要加服务器资源。
权衡利弊和自己技术栈之后开始实践之路,大体目标:
a.通用方式获取主系统数据,且新增需求时主系统访问方式依然不变,在对应的子业务系统进行数据的处理;
b.进行统一监控,把控对外数据,收集日志并进行数据分析和挖掘;
2.技术细节
核心为 Hibernate DetachedCriteria 离线查询对象,对于 DetachedCriteria 我这里就不说了请自行百度。
当下 JavaEE 服务方式有很多,restful/soap/spring http invoker 等等,看你项目具体的服务框,这里我不赘述。
我将自身项目中抽取中该场景关键代码,剔除繁琐的业务代码,展示 hiber 通用查询带来的便利性和可扩展性。
实例中服务采用 cxf webservice,spring 做为托管容器,Base64 编码查询条件进行参数的传递。
主系统服务核心代码:
@Component @WebService @SOAPBinding(style = SOAPBinding.Style.RPC) public class CommonQueryWsImpl implements CommonQueryWs { @Resource private SessionFactory sessionFactory; @Override @Transactional(readOnly = true) public String getPo(String poName, List<String> andList) { DetachedCriteria detachedCriteria = getDetachedCriteria(poName, andList); Object result = detachedCriteria.getExecutableCriteria(sessionFactory.getCurrentSession()).setMaxResults(1).uniqueResult(); return ObjectUtil.isNull(result) ? "{}" : JSONUtil.toJsonStr(result); } @Override @Transactional(readOnly = true) public String listPo(String poName, List<String> andList) { DetachedCriteria detachedCriteria = getDetachedCriteria(poName, andList); List list = detachedCriteria.getExecutableCriteria(sessionFactory.getCurrentSession()).list(); return JSONUtil.toJsonStr(list); } /** * 获取 hiber 离线查询对象 * * @param poName biber 实体对象 * @param andList andSql 列表 * @return 离线查询对象 */ private DetachedCriteria getDetachedCriteria(String poName, List<String> andList) { DetachedCriteria detachedCriteria = DetachedCriteria.forEntityName(poName); String[] split; for (String andStr : andList) { split = Base64.decodeStr(andStr).split("#"); String andSql = split[0]; String andParam = split[1]; if (andParam.contains(",")) { String[] andParams = andParam.split(","); Type[] types = new Type[andParams.length]; for (int i = 0; i < types.length; i++) { types[i] = StringType.INSTANCE; } detachedCriteria.add(Restrictions.sqlRestriction(andSql, andParams, types)); } else { detachedCriteria.add(Restrictions.sqlRestriction(andSql, andParam, StringType.INSTANCE)); } } return detachedCriteria; } }