俄罗斯VS沙特直播

④设定合理的批处理参数。动态↓脸型下巴和平时不大一样这样↓看起来是有一丢丢像王艺。DetachedCriteria不需要Session就可以创建(使用DetachedCriteria.forClass()方法创建),所以通常也称其为离线的Criteria,在需要进行查询操作的时候再和Session绑定(调用其getExecutableCriteria(Session)方法),这也就意味着一个DetachedCriteria可以在需要的时候和不同的Session进行绑定。)Cobar事务,Cobar在单库的情况下保持事务的强一致性,分库的情况下保持事务的弱一致性,分库事务采用2PC协议,包括执行阶段和提交阶段。
返回首页

J2EE 核心模式学习理解和记录

时间:2014-05-08 23:33来源:知行网www.youyuan-chem.com 编辑:麦田守望者

第1章:导论

模式能够:

  • 利用一个经过验证可行的解决方案;
  • 提供一套通用词汇;
  • 约束解决方案的空间。

第2章:表现层设计考虑和不佳实践

客户端验证:基于表单的验证、基于抽象类型的验证。

曾经在JSP中滥用过的助手类,通过助手类在页面和业务逻辑之间传递数据,有点类似于如今Struts中的Action作为传值模型时的情况。

表现层不佳实践:

  • 多个视图中都包含控制代码;
  • 表现层数据结构暴露给业务层或者业务领域对象,比如:暴露HTTPServletRequest;
  • 重复提交表单;
  • 敏感资源暴露给客户端直接访问,有个原则,敏感的东西不能放在WEB-INF之外;
  • 胖控制器;

……

怎么区分后台视图层和前台页面层?或者说,怎么划分哪些事情JSP或者模板做,哪些事情JavaScript做?首先,根据模型驱动的原则,通常送到JSP或者模板上的都是通用模型的对象或者对象集,JSP或者模板根据需要选择展示出来,但是后续可抽取为不需和服务端交互状态下响应用户的行为,应当划分为JavaScript的工作。

第3章:业务层设计考虑和不佳实践

session bean:根据EJB规范,每个session bean专门服务于一个客户端或者用户,生命时间等于客户端会话时间;在服务器崩溃后无法存活、无法持久化、会超时、可以涉及事务;支持构造有状态或无状态的对话模型。

不过现在的容器会话大多可以持久化了,会话复制和会话持久化应当是会话管理中重要的两个分支,通常情况下会话不需考虑完整的事务性,保证线程独立性即可。

至于无状态的session bean,可以被池化,以高效利用(EJB容器管理)。

entity bean:实体bean是否应该包含业务逻辑?按照下面三个原则去判定,还是比较清晰的:

  • 这样的业务逻辑是否会引入实体之间的关系?比如处理UserInfo的时候,是否引入了AccountInfo,这样应当考虑根据模型驱动的原则,放置到专门的User或者Account相关的业务无状态bean中去;
  • 是否要负责管理用户交互的工作流?
  • 是否会担负起本该属于其他业务组件的责任?

有一个“是”,就说明不该包含这段业务逻辑。

尤其提一句,如果使用远程实体bean,就更应该减少实体bean之间的依赖关系,以提高性能和可用性。

业务层和集成层不佳实践:

对象模型或关系模型或每个用例直接映射成实体bean:导致粒度过细,EJB就给网络传输带来太多的负担;

通过getter、setter暴露EJB所有属性:这也是不好的,提供少量和可控的方法调用,减少远程方法调用的开销;

客户端中包括服务寻址代码:寻址这件事情应当从单纯的客户端抽离出来,把不同的寻址策略和复杂度封装起来,真正做到透明传输(扩展到without EJB的系统中也一样,集群环境中也一样,把寻址的行为隐藏于业务逻辑之下)。

EJB用户长时间持续的事务:会锁住其他EJB需要的资源;

……

第4章:J2EE重构

对业务层隐藏表现细节:对用户请求的处理和通信协议相关的数据不应当被业务层获取,最简单的例子就是HttpServletRequest对象。

用session bean包装entity bean:现在这里说的问题一般不会出现,一般也不会有人直接把Action对象扔给后面的业务逻辑去处理,原文说的解决办法是引入业务代表,涉及到此的还有两条:减少entity bean之间的通信;将业务逻辑移至session bean。

分离数据访问代码:DAO。

按层重构系统架构(这里也正好归纳一下现在J2EE系统中常涉及到的Action、Service和EJB中的几种bean的内在联系),例如:

  • 客户端层:浏览器
  • 表现层:JSP、模板、业务代表
  • 业务层:entity bean(Action)、session bean(各种粒度的Service)
  • 集成层:DAO
  • 资源层:DB

……

J2EE 核心模式学习理解和记录

 

表现层模式

拦截过滤器:Intercepting Filter。正如图中的“Apply zero or more”和Servlet规范所述一样,应当具备一个链式结构。这个链式结构中的每个filter,互相之间应当是一个互不依赖的松耦合关系,以便于容易地组合。

前端控制器:Front Controller。给表现层请求安排一个集中访问点。集中了控制逻辑,一定程度避免了重复代码。和拦截过滤器的区别:拦截过滤器使用的是松耦合的,结合成链式的处理器逻辑,适合进行强大的预处理、后处理的策略分布;而前端控制器则专注于集中控制,减少视图中的业务和处理逻辑,提高重用度。

在常用的Struts网站构架中,N个拦截器都是可以自由组合的,也可以自定义合适的拦截器栈来继承某个通用的基础拦截器栈,一些通用的拦截逻辑变放置在基础拦截器栈中,这里是一个拦截过滤器和前端控制器结合实现的例子。

Context对象:不想在与协议无关的环境上下文中使用针对特定协议的系统信息。就是说系统信息,比如请求、配置和安全数据等等,这些东西,通常应当被隐藏起来,不能被业务逻辑看到;但是在某些情形下,业务组件可能又必须用到这些信息,例如,进行终端适配的组件,需要用到HTTP报文中的一些header,那么直接使用会导致组件的灵活性和可重用性的下降,导致前一篇我提到的表现层数据结构和业务层的紧耦合。

解决方法就是制定一个特定的API,将业务组件需要的部分通过API来包装和筛选,而不是直接把表现层数据结构直接暴露给它。这样一来,对于表现层的一些改变,比如协议等方面的改变,不会直接影响到业务组件的接口和运行,只需要修正API的实现逻辑。

还有个什么好处?如果我需要测试业务层的逻辑,因为有了这样一层特殊的API,我可以把整个表现层mock掉。

这里有一个应用例子就是RequestContext对象,API只传输这个,而不是具体的某一Request对象,对于复杂的请求层面被隔离掉,留下一个包装好的上下文给后面的逻辑。

应用控制器:集中地、模块化地进行操作管理和视图管理。

  • 操作管理:把输入请求解析到一个操作(action),让它处理该请求。
  • 视图管理:选定返回给客户端的视图,并把请求分派到这个视图。

这两点的应用例子其实就是在struts-xxx.xml里面定义的配置,如同一个路标,对于出入视图层的数据进行方向上的导航。

举例来说,它的实现经常采用的策略是command对象的策略,命令对象的说法具体可见GoF的那本经典设计模式的书。

效果:把操作管理和视图管理分离开了,提高了模块化程度;再一个这个导航的逻辑被抽取成为一处独立的配置单独维护,方便扩展。

视图助手:View Helper。把视图和相关处理逻辑分离开。

这里需要先提及两个重要的阶段:视图准备阶段:这是指请求被分配到一个具体的视图上面;视图创建阶段:视图根据从模型中取得的内容来实例化自己。

因此使用视图封装显示格式的代码,而使用助手封装视图处理逻辑。助手在视图和模型之间充当了一个适配器的角色,同时也会做一些格式逻辑相关的处理。

一个很好的例子就是各种标签,包括自定义标签,比如一个时间格式化的标签,对于一个时间,在不同的环境下以不同的格式展示。

视图助手终究是“视图”的助手,它的核心始终是视图,对于已经生成了的成熟的具备一定模型的数据,试图助手协助将它们以某种合适的方式展示出来,而不应当做复杂或具体的业务逻辑。

于是这里提出第一点需要注意,怎样把视图助手和后端的逻辑区分开?视图助手得到的数据应当是已经成熟的一定模型化的数据,需要做的是仅仅是做一些格式的处理,对展示效果的修正和增强,并不做任何业务逻辑的相关事宜。

第二点需要注意,应当把视图助手和JavaScript区分开来,前者在服务端完成,后者在客户端完成:把处理逻辑从页面中抽取出来,一个重要原因就是要减少在页面中直接暴露的实现细节。在实际开发中,这二者之间的区分,常常带来困扰。比如在模板或者JSP中使用if标签,还是在客户端使用JavaScript来控制逻辑?我建议这里应当有一个区分的原则:这些逻辑是否属于客户端才能决策的页面展示细节?如果是,就使用JavaScript来完成,反之还是应当隐藏到页面助手中。

复合视图:Composite View。使用由多个原子化的子视图构成的复合视图。特点是组合是可以动态的,而页面布局又可以整体控制,和页面内容互相独立。

有这么几个常见的例子:Portlet就是一个复合视图结合的最好例子,主题可以影响到所有视图的呈现,又是和展示的具体内容没有关系的,Portlet可以在服务端做到视图的聚合,而不把事情遗留到客户端完成,不涉及浏览器跨域的安全性问题;SiteMesh是一个很适合对页眉、页脚等页面通用元素拼装的框架,比jsp:include标签优雅;更小维度上,标签的引用也可以认为是视图的复合。

视图的复合增进了视图模块化和重用能力,这方面来看是增加了可维护能力;但是另一方面,一个完整的直观的页面被拆得七零八落,又降低了可维护性,为了解决这个问题,我觉得对于一个大型Web应用,一个好的思路是提供一种工具,至少是一个简易的指导方法,从页面的某一部分元素快速定位到具体的最小视图上;另外,视图的复合带来了服务端拆解和部署的灵活性,但一定也带来性能损耗,Portlet聚合尤为明显。

还有一个重要的事项是,页面布局需要和页面内容相独立。一个较大的视图拆解成若干个小的子视图,这些小的子视图应当具备独立的展示内容,但是页面的布局不应当有其中的任一子视图控制,而可以落到某一个整体的主题定义中去。

服务到工作者:Service To Worker。集中控制权管理和请求的处理,再把控制权交给视图之前获取表现模型。视图则根据获得的表现模型生成一个动态响应。这个模式是由前端控制器、应用控制器和视图助手组合而成的。具体说:前端控制器集中了访问视图的逻辑,然后应用控制器完成了视图导航,最后由视图助手协助准备了视图所使用的模型数据。

分配器视图:Dispatcher View。把视图本身作为请求的最初访问点,把业务处理的逻辑交由视图完成。

服务到工作者和分配器视图是非常类似的两种模式,前者以进视图前的逻辑处理为核心,后者才真正以视图为核心。当业务处理比较简单,或者不能合适地通过视图之外的逻辑来控制时,可以采用分配器视图模式,把控制逻辑放到视图中。在这种方式下,不代表分配器视图做了所有的业务逻辑,对于数据的准备完全可以在进视图之前完成,毕竟视图中完成大量的业务逻辑通常不是一个优秀的解决方案。

一个很好的例子就是页面集成,进入集成页之前准备好集成的子页面的URL,到了集成的父页面中再执行拼装操作,这个行为,甚至可能被到客户端才完成。这种情形下,尽管页面去做了聚合视图的事,但这恰恰是页面最擅长的行为,比进页面之前把数据准备好、拼装好再一并写入页面要可见和可接受得多。

顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
标签(Tag):Java JAVA实例教程 JAVA基础教程 Java源代码 Java技巧
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
验证码:点击我更换图片
猜你感兴趣