编写程序的时候,随着需求和业务的增加,代码的维护会越来越困难,如何做到可扩展,易维护呢?一个比较好的方案就是提高代码的复用率,抽取易变的部分统一维护,以降耦。
代码框架一般可以分为两类,一类是业务逻辑的抽象,主要用于提高业务逻辑代码的复用率,比如不同业务对某个规则的验证。另外一类是处理流程的抽象,主要用于降耦,即对修改关闭,对扩展开放。新增的业务不影响原来的业务。当然,更多的是将两者的合理糅合。
先从第一类开始。
无论是webservice还是http请求形式的服务,我们的程序的提供服务的时候,都是有一个入口,一个出口,通过一个请求获取到一个响应,在这个请求和响应中间,程序处理业务逻辑,提供一定的功能(服务)。那么在这个过程中程序会做什么?
一般分为四个阶段,
一是参数的转换,就是把请求转换为系统内部的请求实体。对webservice来说,可能是这样,其他系统调用我们的系统是通过一个BizRequest,那么在这个阶段,我们把bizRequest转换为我们系统的内部实体类,bizRequestEntity。这样做的好处就是隔离外部系统和系统内部的变化,我们的业务的变化,不需要影响到外围系统。
二是参数的校验,对参数格式和是否必需的校验。一个比较好的建议是对一些必需的参数统一返回一个非法参数的错误码。但是在系统内的日志里面需要打印具体那个参数的问题,方便查询问题。、
三是主要业务逻辑的处理。主要逻辑建议使用逻辑处理框架(process framwork)。如果业务涉及数据库事务,建议在处理框架中使用spring的事务模板TransactionTemplate.
四是对主要业务逻辑处理后返回结果的解析和处理。通过主要业务逻辑返回的错误码构建返回给调用方的响应,或者做一些其他操作,比如通知第三方结果(比如下发短信通知用户)。
在一个控制器中处理的这四个阶段应该做到很好的封装,在这个控制器中应该看到很少的代码逻辑(逻辑几乎都在第三阶段),比较明显的一个效果是,你会发现你记录日志的代码跟这四个阶段的代码行数相差不多,甚至有超过。一个比较好的日志记录建议是,在一个单独的日志文件中,记录整个流程的一个简要日志,即通过一个重要参数,比如用户的ID,可以很容易的追踪到用户到达了那个阶段,那个阶段有什么问题。在另外一个日志中记录一些比较重要的信息和参数。方便更加细致的寻找问题。
对主要逻辑的处理,可以细化成三个阶段,初始化,校验,处理。
初始化主要是构建主要参数对象,比如一笔订单构建一个Order对象,或者咨询其他系统对某些参数赋值,针对某个需求,可以增加一个初始化处理类。校验主要是对初始化后的各个参数做业务校验,比如说用户的状态不能是已注销。针对某个需求,可以很方便的增加校验。处理,则是对其他系统的调用或者数据的落地。在这三个阶段,可以把每一个需求或者每一个校验都区分开,这样每个原子性的校验就可以被其他业务逻辑复用。从而实现程序的易扩展,高复用,易维护。
public abstract class AbstractPreBizProcessTemplate implements BizPreProcessTemplate { private List<PreBizProcessInitializer> initList = new ArrayList<PreBizProcessInitializer>(); private List<PreBizProcessValidator> validatorList = new ArrayList<PreBizProcessValidator>(); private List<PreBizProcessorHandler> handlerList = new ArrayList<PreBizProcessorHandler>(); public Result process(PreBizContext preBizContext) { Result result = new Result(false); String methodName = "process"; try { for (PreBizProcessInitializer initProcessor : initList) { initProcessor.init(preBizContext); } for (PreBizProcessValidator validator : validatorList) { validator.validate(preBizContext); } for (PreBizProcessorHandler handler : handlerList) { handler.handler(preBizContext); } result.setSuccess(true);} catch (PreBizProcessException e) { ErrorEnum errorEnum = ((PreBizProcessException) e).getErrorEnum(); if (errorEnum == null) { errorEnum = ErrorEnum.BIZ_PROC_ERROR; } result.setErrorEnum(errorEnum); } catch (Exception e) { result.setErrorEnum(ErrorEnum.SYSTEM_ERROR); } finally { } return result; }
可以使用XML配置或者标注:
<bean id="testTemplate" class="com.TestTemplate">
<property name="initList"> <list merge="true"> <ref local="testInitializer"/> </list> </property> <property name="validatorList"> <list merge="true"> <ref local="testValidator"/> </list> </property> <property name="handlerList"> <list merge="true"> <ref local="testHandler"/> </list> </property> </bean>
标注: @Target( { ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface TemplateMethod { String[] value() default {}; String[] inits() default {}; String[] valis() default {}; String[] handlers() default {}; } public class TestTemplate extends AbstractProcessTemplate implements InitializingBean, BeanFactoryAware { private DefaultListableBeanFactory factory; @TemplateMethod(inits = { "inits1", "inits2" }, valis = { "vali1", "vali2" }) public void processBiz1() { Context txt = new Context(); ChargeResult re = this.process(txt); // System.out.println(re); } public void afterPropertiesSet() throws Exception { System.out.println("InitializingBean-->" + this.getClass().getName() + "::" + this.getInits().size()); TemplateUtil.initProcessTemlates(factory); } public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.factory = (DefaultListableBeanFactory) beanFactory; } } public final class TemplateUtil { public static void initProcessTemlates(ListableBeanFactory factory) { System.out.println("initTemplate"); processInit(factory); } @SuppressWarnings("unchecked") private static void processInit(ListableBeanFactory factory) { Map<Object, Object> allTemplateClasses = BeanFactoryUtils.beansOfTypeIncludingAncestors( factory, AbstractProcessTemplate.class); Map<Object, Object> allInitClasses = BeanFactoryUtils.beansOfTypeIncludingAncestors( factory, Initor.class); Map<Object, Object> allValiClasses = BeanFactoryUtils.beansOfTypeIncludingAncestors( factory, Validator.class); Map<Object, Object> allHandlerClasses = BeanFactoryUtils.beansOfTypeIncludingAncestors( factory, Handler.class); for (Object key : allTemplateClasses.keySet()) { Object value = allTemplateClasses.get(key); if (AnnotationUtils.findAnnotation(value.getClass(), TemplateClass.class) != null) { AbstractProcessTemplate templateClass = (AbstractProcessTemplate) value; if (!templateClass.getInits().isEmpty() || !templateClass.getValis().isEmpty() || !templateClass.getHandlers().isEmpty()) { return; } Method[] methods = templateClass.getClass().getDeclaredMethods(); for (Method method : methods) { TemplateMethod temMethod = AnnotationUtils.findAnnotation(method, TemplateMethod.class); if (temMethod != null) { String[] values = temMethod.value(); String[] inits = temMethod.inits(); String[] valis = temMethod.valis(); String[] handlers = temMethod.handlers(); if (values != null && values.length > 0) { findBizBeans(allInitClasses, templateClass, values); findBizBeans(allValiClasses, templateClass, values); findBizBeans(allHandlerClasses, templateClass, values); } if (inits != null && inits.length > 0) { findBizBeans(allInitClasses, templateClass, inits); } if (valis != null && valis.length > 0) { findBizBeans(allValiClasses, templateClass, valis); } if (handlers != null && handlers.length > 0) { findBizBeans(allHandlerClasses, templateClass, handlers); } } } System.out.println("注册完成后:" + templateClass + ":" + templateClass.getInits().size() + ":" + templateClass.getValis().size() + ":" + templateClass.getHandlers().size()); } } } private static void findBizBeans(Map<Object, Object> allClasses, AbstractProcessTemplate templateClass, String[] annotiedBeanNames) { for (String beanName : annotiedBeanNames) { Object bizBean = allClasses.get(beanName); if (bizBean instanceof Initor) { Initor realInitor = (Initor) bizBean; templateClass.getInits().add(realInitor); } else if (bizBean instanceof Validator) { Validator realVali = (Validator) bizBean; templateClass.getValis().add(realVali); } else if (bizBean instanceof Handler) { Handler realhander = (Handler) bizBean; templateClass.getHandlers().add(realhander); } } } }
对新扩展的每一个业务,只需要新增一个模板类继承抽象模板类即可。几乎对每一个单独的初始化器,验证器和处理器都可以被很好的复用。
每一个业务都新增一个模板,每个模板实际上都没有做什么东西,是不是有点多余?如果我使用一个标志来区分不同的业务,那么在一个模板里面是不是就可以只用一个模板了?确实可以,但是那样框架会变得相当重量级,这个框架后面会讲到。
比较轻量级的解决方案可以是这样:新增一个工厂类,并使用spring配置简化bean的管理,将每个不用业务的模板注入到工厂类的map中,通过业务传入key值寻找到对应的处理模板。
<bean id="testFactory" class="TestProcessorFactory"> <property name="processorTemplates"> <map> <entry key="test"> <ref local="testProcessTemplate"/> </entry> </map> </property> </bean> public class PayProcessorFactory { private Map<String, PayProcessor> processors = new HashMap<String, PayProcessor>(); /** * 根据业务场景获取对应的处理器 * @param bizType 业务场景 * @return */ public PayProcessor getProcessor(String bizType) { return processors.get(StringUtil.trim(bizType)); } public void setProcessors(Map<String, PayProcessor> processors) { this.processors = processors; } }
或者这么做
public class TestTemplate extends AbstractProcessTemplate implements InitializingBean, BeanFactoryAware { private DefaultListableBeanFactory factory; @TemplateMethod(inits = { "inits1", "inits2" }, valis = { "vali1", "vali2" }) public void processBiz1() { } public void afterPropertiesSet() throws Exception { System.out.println("InitializingBean-->" + this.getClass().getName() + "::" + this.getInits().size()); TemplateUtil.initProcessTemlates(factory); } public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.factory = (DefaultListableBeanFactory) beanFactory; } public String getSupportedBizType() { return "test"; } } public class TemplateFactory { private static Set<BizProcessTemplate> templates = new HashSet<BizProcessTemplate>(); public static BizProcessTemplate getPerperTemplate(String bizType) { for (BizProcessTemplate template : templates) { if (StringUtils.equals(bizType, template.getSupportedBizType())) { return template; } } return null; } }
如果你想使用多个模板,可以这么做:
public interface BizProcessTemplate2 { ChargeResult process(Context txt); boolean canProcess(List<Class<BizProcessTemplate2>> supportedTemplateClasses); } public class TemplateProcessor { private static Set<BizProcessTemplate2> templates = new HashSet<BizProcessTemplate2>(); public static void getProperTemplates(List<Class<BizProcessTemplate2>> supportedTemplates) { for (BizProcessTemplate2 template : templates) { if (template.canProcess(supportedTemplates)) { template.process(new Context()); } } } }
这个框架同时也是另外一种轻量级框架,结合你的业务,可以考虑下。
如果你的业务足够简单,懒的使用这么繁琐的框架,那么可以尝试下这种处理方式,以一个web请求为例:
public class WebBizProcessHelper { private static Logger LOGGER = LoggerFactory.getLogger(WebBizProcessHelper.class); /** * 处理业务逻辑,注意:<font color=red>WebBizCallBack的泛型类需要与第一个参数所表示的类一致,且能够被实例化</font> * <br>比如:<br> * <code> * new WebBizProcessHelper().process(<font color=red>TbSignatoryParameterBean.class</font>, new WebBizCallBack<<font color=red>TbSignatoryParameterBean</font>>() { //... }; * </code> * @param paramBeanRequestClass * @param webBizCallBack * @return */ @SuppressWarnings("unchecked") public String process(Class<?> paramBeanRequestClass, WebBizCallBack webBizCallBack) { Object request = null; try { request = BeanUtils.instantiateClass(paramBeanRequestClass); processInitialize(webBizCallBack, request); processValidate(webBizCallBack, request); return processHande(webBizCallBack, request); } catch (WebBizException e) { try { return webBizCallBack.processWebBizException(request, e); } catch (Exception e1) { LOGGER.error("WebBizProcessHelper#processWebBizException出现异常!phase:" + e.getPhase() + ",request:" + request + ",errorMsg:" + e1.getMessage()); } } catch (Exception e) { LOGGER.error("WebBizProcessHelper#process出现异常!" + ",request:" + request + ",errorMsg:" + e.getMessage()); } return VelocityTemplateNameConstants.ERROR_VM; } /** * * @param webBizCallBack * @param request * @throws WebBizException */ @SuppressWarnings("unchecked") private String processHande(WebBizCallBack webBizCallBack, Object request) throws WebBizException { try { return webBizCallBack.handle(request); } catch (Exception e) { convetAllException2WebBizExceptoin(WebBizPhaseEnum.HANDLE_PHASE, e); } return VelocityTemplateNameConstants.ERROR_VM; } /** * * @param webBizCallBack * @param request * @throws WebBizException */ @SuppressWarnings("unchecked") private void processValidate(WebBizCallBack webBizCallBack, Object request) throws WebBizException { try { webBizCallBack.validate(request); } catch (Exception e) { convetAllException2WebBizExceptoin(WebBizPhaseEnum.VALIDATE_PHASE, e); } } /** * * @param webBizCallBack * @param request * @throws WebBizException */ @SuppressWarnings("unchecked") private void processInitialize(WebBizCallBack webBizCallBack, Object request) throws WebBizException { try { webBizCallBack.initialize(request); } catch (Exception e) { convetAllException2WebBizExceptoin(WebBizPhaseEnum.INITIALIZE_PHASE, e); } } /** * 转换后默认是系统异常 * @param e * @throws WebBizException * @throws Exception */ private void convetAllException2WebBizExceptoin(WebBizPhaseEnum phase, Exception e) throws WebBizException { if (e instanceof WebBizException) { throw (WebBizException) e; } throw new WebBizException(phase, e, ErrorEnum.SYSTEM_ERROR.getErrorMessage()); } /** * 业务处理回调接口 * @author jiatao * @version $Id: WebBizProcessHelper.java, v 0.1 2012-12-12 上午09:03:00 wb-jiatao Exp $ */ public interface WebBizCallBack<K> { /** * 业务逻辑初始化 * @param paramBean * @throws WebBizException */ void initialize(K paramBean) throws WebBizException; /** * 业务逻辑验证 * @param paramBean * @throws WebBizException */ void validate(K paramBean) throws WebBizException; /** * 业务逻辑处理 * @param paramBean * @return * @throws WebBizException */ String handle(K paramBean) throws WebBizException; /** * 处理各阶段抛出的异常 * @param paramBean * @param WebBizException * @return */ String processWebBizException(K paramBean, WebBizException WebBizException); } /** * 业务处理阶段 * @author jiatao * @version $Id: WebBizProcessHelper.java, v 0.1 2012-12-12 上午09:02:45 wb-jiatao Exp $ */ public enum WebBizPhaseEnum { INITIALIZE_PHASE, VALIDATE_PHASE, HANDLE_PHASE, PROCESS_EXCEPTION_PHASE; } /** * 显示错误页面 * @param modelMap * @param webBizexception * @return */ public static String showErrorVM(final ModelMap modelMap, WebBizException webBizexception) { return showErrorVM(modelMap, webBizexception.getMessage()); } /** * 显示错误页面 * @param modelMap * @param webBizexception * @return */ public static String showErrorVM(final ModelMap modelMap, String errorMsg) { modelMap.addAttribute(ModelMapKeyConstants.ERROR_MESSAGE, errorMsg); return VelocityTemplateNameConstants.ERROR_VM; } }
在你的Controller里面,可以这么做:
@RequestMapping(method = RequestMethod.GET) public String testBizProcess(final ModelMap modelMap, final HttpServletRequest request) { LogManageUtil.processLog(test, "enter", request.getParameter("s"), "", ""); LogManageUtil.monitorLog(request.getParameter("s"), "test", "arrive", "Y", request.getParameter("t"), "", "t", "t"); return new WebBizProcessHelper().process(ParameterBean.class, new WebBizCallBack<ParameterBean>() { public void initialize(ParameterBean paramBean) throws WebBizException { initParameterBean(paramBean, request); if (LOGGER.isInfoEnabled()) { LOGGER.info("t:" + t); } } public void validate(ParameterBean paramBean) throws WebBizException { ValiResult valiResult = validateManagr.validate(paramBean); if (LOGGER.isInfoEnabled()) { LOGGER.info("能否签约结果:" + signatoryPayResult + paramBean.getSign_alipay_user_id()); } if (!valiResult.isSuccess()) { throw new WebBizException(WebBizPhaseEnum.VALIDATE_PHASE, "errorMsg"); } } public String handle(TbSignatoryParameterBean paramBean) throws WebBizException { LogManageUtil.processLog(t, "success", paramBean .getT(), "", ""); LogManageUtil.monitorLog(request.getParameter("t"), "t", "finished", "Y", request.getParameter("t"), "", "t", "t"); return VelocityTemplateNameConstants.T_VM; } public String processWebBizException(tParameterBean paramBean, WebBizException WebBizException) { if (LOGGER.isInfoEnabled()) { LOGGER.info("处理失败:" + WebBizException.getPhase() + WebBizException.getMessage() + paramBean.getT()); } LogManageUtil.failLog(T, "failture:webBizException", paramBean .T(), "", WebBizException.getPhase() + WebBizException.getMessage()); return WebBizProcessHelper.showErrorVM(modelMap, WebBizException); } }); }
相关推荐
本书不再介绍struts 1.x相关内容,如果读者希望获取《轻量级j2ee企业应用实战》第一版中关于struts 1.x的知识,请登录http://www.crazyit.org下载。当读者阅读此书时如果遇到技术难题,也可登录...
2、mybatis:轻量级,基于xml的模式感觉不利于封装,代码量不小,基于xml维护也麻烦(个人观点, 现在注解模式貌似也挺不错),感觉mybatis更适合存在dba角色的年代,可以远离代码进行sql调优,复杂的查询拼装起来...
轻量级智能快速开发平台,可以帮助您解决项目中90%的重复工作,让您更多关注业务逻辑。由于本身轻量级特性,可根据自身需求二次开发想要的功能。使用 Spring boot,主流趋势,开箱即用 。 使用 Maven 多模块 构建...
一款使用 C 语言写成的、现代的高性能轻量级PHP web框架。 特性 1. 高性能、轻量级 在各PHP框架的基准压力测试中,air framework 在并发请求数、CPU及内存资源占用等各方面指标上均以显著优势大幅领先于其他框架 更...
Spring是一个开放源代码的设计层面框架,他解决的是业务逻辑层...Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson创建。简单来说,Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。
《轻量级Java EE企业应用实战:Struts2+Spring3+Hibernate整合开发(第3版)》介绍了Java EE领域的三个开源框架:Struts 2、Spring和Hibernate。其中Struts 2升级到2.2.1,Spring升级到3.0.5,Hibernate升级到了...
一个简单的面向对象的轻量级数据库框架,简化了Android开发中操作数据库的繁琐过程,将面向过程的业务逻辑封装,完全的零Sql语句。
本书是《轻量级J2EE企业应用实战》的第二版,同时还融合了《整合Struts+Hibernate+Spring应用开发详解》理论部分。实际上,本书凝结了前两本书的精华部分。 本书介绍了Java EE领域的三个开源框架:Struts 2、Spring...
LiteFlow是一个轻量级的流程引擎,用于实现业务逻辑的编排和执行。它支持基于配置文件的流程定义,允许开发者通过简单的配置实现复杂的业务流程。LiteFlow的核心特点是轻量级、易扩展、高性能,非常适合在Spring ...
《轻量级java ee企业应用实战(第3版)—struts 2+spring 3+hibernate整合开发》介绍了java ee领域的三个开源框架:struts 2、spring和hibernate。其中struts 2升级到2.2.1,spring升级到3.0.5,hibernate升级到了...
《轻量级java ee企业应用实战(第3版)—struts 2+spring 3+hibernate整合开发》介绍了java ee领域的三个开源框架:struts 2、spring和hibernate。其中struts 2升级到2.2.1,spring升级到3.0.5,hibernate升级到了...
本书是《轻量级Java EE企业应用实战》的第3版,第3版保持了第2版内容全面、深入的特点,主要完成全部知识的升级。 本书介绍了Java EE领域的三个开源框架:Struts 2、Spring和Hibernate。其中Struts 2升级到2.2.1,...
本书是《轻量级Java EE企业应用实战》的第3版,第3版保持了第2版内容全面、深入的特点,主要完成全部知识的升级。 本书介绍了Java EE领域的三个开源框架:Struts 2、Spring和Hibernate。其中Struts 2升级到2.2.1,...
狙击手['snaɪpər]轻量级业务框架有兴趣的同学也可以加我的微信haitaotao我拉大家进群讨论。系统要求类UNIX系统前往v1.12 +目录结构├── cmd # 服务子命令├── dao # 数据访问层├── main.go # 项目总入口├...
一个基于VIPER架构理念的轻量级框架,使用模块化编程,目标是构建健壮可维护的大型项目和业务逻辑复杂的项目。 XFLegoVIPER特点 1、快速建立模块与模块之间的关联,实现了模块间事件通信。 2、视图自动绑定事件处理...
silly 是一个以 Lua 语言开发为主的高并发服务器框架,也是一个轻量的、极简的服务器程序框架。 silly 底层采用 C 和 Lua 语言混合开发,而上层业务逻辑开发则以 Lua 语言开发
这是一个轻量级分库分表框架&读写分离框架,无需搭建中间层代理服务,开发者只需要引入本框架的jar包,并进行相应的配置即可实现分库分表&读写分离逻辑 读写分离 读写分离的实现依然是继承了spring提供的...
一款轻量级的微信消息处理框架,可以让业务代码与微信微信处理框架代码解耦,并且你根本不需要关心消息是如何发送的,你只需要关注你的业务即可. 项目介绍 封装了微信消息接收与发送,可以使用注解驱动开发,方便的进行...
NFine 是基于 C# 语言的极速 WEB + ORM 框架,其核心设计目标是开发迅速、代码量少、学习简单、功能强大、轻量级、易扩展,让Web开发更迅速、简单。使用 Apache License 2.0 协议,采用主流框架,容易上手,简单易学...
《轻量级Java EE企业应用实战:Struts2+Spring3+Hibernate整合开发(第3版)》介绍了Java EE领域的三个开源框架:Struts 2、Spring和Hibernate。其中Struts 2升级到2.2.1,Spring升级到3.0.5,Hibernate升级到了...