j2ee重组.docx
《j2ee重组.docx》由会员分享,可在线阅读,更多相关《j2ee重组.docx(13页珍藏版)》请在冰豆网上搜索。
j2ee重组
J2EE重组
1、引入控制器
控制逻辑分散在整个应用中,通常在多个java服务器页面(JSP)视图中重复出现。
可以把控制逻辑提取到一个或者多个控制器类,其中后者存在处理客户端请求的最初联系点。
(如图:
)
动机:
在多个JSP中重复的控制代码也需要在每个JSP中维护。
把这种代码抽象出来放在一个或者多个机制化控制器类中,可以提高应用的模块化、可重用性以及维护性。
机制:
使用前端控制器(Front Control)模式来应用抽取类以创建一个控制器类,把重复的控制逻辑从单个JSP中移到该控制器中。
2、分离数据访问代码
数据访问代码可以直接嵌入到有其他不相关职责的某类中。
最佳情况:
把数据访问代码抽取到一个新类,然后把该新类逻辑或者物理地移动到离数据源比较近的位置。
动机:
创建更为清晰的抽象、提高内聚力、降低偶合,因此增强模块化和可重用性。
机制:
在控制器对象中确定数据访问逻辑,并从中抽取出来;使用新DAO对象从控制器访问数据;DAO对象属于集成层访问数据资源层。
范例:
假如,我们拥有两个类:
一个用于Servlet,充当控制器;另外一个名为“UserDAO”的新对象,充当访问用户信息的数据访问对象。
UserDAO封装了所有JAVA数据库连接
考虑另外一个例子,持久性逻辑被嵌入在一个使用BMP的企业EJB对象中。
把持久性代码和企业Bean对象结合起来会创建脆弱的、紧密偶合的代码。
作为重组改善的情况是将数据访问对象从企业Bean中分离。
(如下图:
)
3、使用连接缓冲池
数据库连接不是共享的。
客户端管理着实现数据库调用的自己的连接。
使用连接缓冲池(ConnectionPool),预先初始化多个连接,这样可以提高可扩展性和性能。
(如下图)
动机:
打开数据库连接是个相当昂贵的操作,执行时会花费大量的时间和资源。
其性能和可扩展性都会受到影响。
同时,由于数据库连接有限,并且每个客户端管理着自己的连接,连接数目将很快比想象的消耗完。
(特别是在表示层中组件,如果直接与数据库交互,很容易消耗尽;当然,可以将数据访问代码移动到业务层或者集成层,这方面的知识请参阅:
“分离数据访问代码”和“根据层重组结构”)
机制:
为连接管理创建一个接口,包括查询和返回连接的方法;应用抽取类或者移动方法,把已经有的连接查询代码移动到实现连接管理接口的类中;更改连接管理器实现中的连接查询方法的实现,以预先初始化一些连接实例,并且在用户间共享它们,因而引入缓冲机制。
(使用Tomcat,Resin,Weblogic服务器中,都有配置连接池和数据源的选项,自己写一个数据源DataSource管理类,实现对数据源的JNDI查询和池化连接的获取释放)
4、根据层重组结构
提供结构完善度一般需要更改数据访问逻辑和处理逻辑的本地化。
Increasingarchitecturalsophisticationrequireschangingthelocalizationofdata
accesslogicandprocessinglogic.
逻辑或者物理地把数据访问代码移动到离实际数据源更近的地方。
把处理逻辑从客户端和表示层移动到业务层。
MoveDataAccesscodelogicallyand/orphysicallyclosertotheactualDataSource.
Moveprocessinglogicoutoftheclientandpresentationtiersintothebusinesstier.
动机:
J2EE平台很清晰地把关心的问题分割成Servlet、JSP、EJB组件的角色,以提供有关可扩展性,灵活性、事务、安全等等最大利益。
业务不太复杂的时候,使用Servlet、JSP+JAVABEAN+DAO;在业务复杂性不断增强的情况下,可以引入会话Bean和实体Bean为所有客户提供集中式商务处理,并利用EJB容器带来的好处(事务、安全、资源管理、生命周期管理)。
(如下图演示了一步步层的重组)
Servlet/JSP+DAO(JavaBean)+DataBase
Servlet/JSPs+BusinessDelegates+SessionBean+DAO+DataBase
Servlet/JSPs+BusinessDelegates+SessionBean/EntityBean+DAO(forBMPonly)+DataBase
机制:
从控制和实体对象中分离数据访问代码,并放进数据访问对象;分离表示和业务处理,为业务处理引入会话Bean,在Servlet和JSP中保持表示处理;把实体Bean引入作为模型共享的、事务的、粗粒度的持久性业务对象;借助于业务代表,分离表示层和业务层组件。
5、本地化不同的逻辑
长期以来,业务逻辑和表示格式处理在JSP视图中混合。
把业务逻辑抽取到一个或者多个可以被JSP或者控制器(Servlet)使用的助手类中。
图5-4所示,处理客户端请求的最初联系点可能是JSP视图,请参考“分发者视图模式”
图5-5说明了从视图中抽取的逻辑,被放入控制器、命令对象和助手类中。
这时候,处理客户端请求的最初联系点是控制器。
请参阅“工作者服务模式”
动机:
为了创建更加清晰的抽象,我们可以提供内聚性、并降低偶合,这样做会增强模块性和可重用性。
经过良好划分模块的系统可以提供更好的开发者角色区分,比如:
web
开发人员负责自己格式代码,而且软件开发者负责业务逻辑。
机制:
使用视图助手(ViewHelper)模式作为操作指南,以应用抽取类来创建新的助手类,并把业务逻辑从JSP移动到这些助手中。
范例:
我们以前经常写一下moduleOne形式的JSP程序,在一个JSP中混合业务逻辑和格式代码,如下图:
解决之道应该,应用视图助手模式(通过抽取JavaBean或者JspTag),更改其设计,从JSP视图中抽取scriptlet代码。
如下图:
如图所示,业务逻辑已经被抽取为助手类,而不是直接嵌入到JSP中。
这些助手可以处理各种任务,包括内容检索、访问控制,以及为了显示而调整模型状态等,我们应该尽可能地从视图中抽取尽可能多的编程逻辑。
助手组件可以被实现为JavaBean或者自定义标签。
JavaBean助手非常适合于封装内容检索逻辑和保存结构,而自定义标签助手非常适合于为了显示而转换模型的任务,因为在标签中,可以很容易的访问JSP中各种对象(Out、Request、Response、Session、Application等)。
如下图的总结:
把工作授权给助手
把工作授权给助手,最前点引入一个控制器
6、向业务层隐藏特定表示层的细节
请求处理和/或者与协议相关的数据结构被从表示层展示给业务层。
比如在业务层EJB,大量使用表示层HTTP协议的对象。
从业务层删除所有对请求处理和协议相关的表示层数据结构的引用。
使用更加通用的数据结构以在层之间传递值。
(比如properties对象,Vector,ArrayList对象)如下图所示:
向业务层隐藏特定表示层的细节
动机:
特定于某层的实现细节不应该引入到其他层中。
业务层向表示层展示的服务API将很有可能被其他层使用。
如果该服务API接受带有类型的参数,比如HttpServletRequest,则该服务的每个客户将被迫在Servlet请求数据结构中打包其数据。
这样做会严重影响服务的可重用性。
机制:
使用更为通用的数据结构和类型来替代业务层中对表示层数据结构的引用,比如更为通用的参数:
String,int,UserInfo等;
更改表示层中的客户端代码,这些代码调用相关方法(注意,表示层数据结构片段可以作为单个参数传递到业务方法。
比如传递参数是String类型,但是传递细粒度、单个参数的缺点是这样策略会把表示层细节于业务服务API更为紧密地关联在一起,如果该服务需要的状态发送变化,则服务API必须改变。
一种稍微灵活的替代方法是把相关状态从表示层数据结构拷贝到更为通用的数据结构),比如值对象,然后更通用的数据结构将被传递到业务层;
还有一种替代办法,如果使用某表示层框架,比如常见的Struts项目,我们可以实现覆盖接口类型的策略。
当处理某请求时,框架通常会创建数不清的数据结构。
比如,通常框架会透明地完成将HttpServletRequest数据结构的相关状态拷贝到通用数据结构,以及把请求参数传递到特定框架的数据类型。
因此,把该数据结构传递给业务层会引入请求处理框架和业务服务之间的偶合。
在这种情况下,你仍旧可以使用刚才描述的方法,并且把框架特定的数据结构传递到业务层之前将其拷贝到某通用接口类型。
相反地,更有效的解决方案是简单地创建一个会映射框架特定类型的方法的通用接口类型。
比如:
如果该框架实例化a.framework.StateBean的某子类(名为my.sy.st.MyStateBean),则它是StateBean类型的:
//Note:
Instancecreationistypicallydoneviaafactory
//Note:
Parametersnoshownforsimplicity.
a.framework.StateBeanbean=newmy.stuff.MyStateBean(…)
如果业务层把该bean作为一个参数接收,则该类型是StateBean
PublicvoidaRemoteBizTierMethod(a.framework.StateBeanbean)
我们不必把StateBean类型的bean传递到业务层,可以引入一个新的名为my.stuff.MystateVO的接口,由my.stuff.MyStateBean实现。
PublicclassMyStateBeanextendsa.framework.stateBeanimplementsMyStateVO
现在,业务层可以包含如下方法签名:
PublicvoidaRemoteBizTierMethod(my.stuff.MyStateVObeans)
最后,要记住,你可以进一步地降低应用中逻辑不相关部分之间的偶合,方法是应用该重组到表示层域对象。
范例:
域对象与HttpServletRequest对象之间紧密偶合,使用通用对象降低偶合性。
7、从视图取消转换
在视图组件中模型为了显示需要而必须进行局部转换。
从视图中取消所有的转换代码,并且将其封装在一个或多个助手类中。
(比如,我使用JavaBean中处理逻辑,查询到所有符合条件的学生,存放在Vector对象,需要在页面列表显示Vector中学生信息,按照旧的开发方式,在JSP页面中,就引入了大量的JSP脚本,循环迭代vector,输出学生信息。
更好的解决之道是,在模型显示从视图中取消,使用JSPTag进行局部转换)
从视图中取消转换
动机:
直接在JSP页面中嵌入为显示而转换该模型的逻辑会降低应用的模块化和可重用性。
这类转换可能发生在多个JSP中,所有代码需要复制,使用拷贝-粘贴进行重用的方式,维护起来不太方便。
机制:
应用抽取类把JSP中的转换和调整逻辑移动到助手类中;从JSP中调用这些助手类以处理转换和调整工作。
范例:
第一步把逻辑抽取到助手类中,在这里使用了自定义标签助手。
8、向客户端隐藏资源
客户端浏览器不应该直接访问诸如JSP视图之类的特定资源。
通过容器配置或者使用控制组件,我们可以实现隐藏特定资源。
通过容器配置实现受限访问
通过使用控制组件实现受限访问
动机:
通常,我们需要对进来的请求进行控制。
这种重组描述基于权限的控制和保护。
如果必须控制客户访问的顺序和请求流,则应引入同步令牌(synchronizerToken)
机制:
借助于配置,把要保护的资源移动到/WEB-INF/子目录的下子目录中,这样我们可以实现对特定资源的受限访问控制;使用控制组件实现受限访问控制(引入一个可以使用的控制器,并且把该控制器可以管理对被保护资源的访问);创建一个或者多个助手类(依赖于具体实现的不同,控制器或者每个JSP本身可以授权助手类以检测对该资源的访问是否通过了访问控制)。
范例:
(一)通过容器配置实现访问限制
通过把info.jsp文件移动到/WEB-INF/目录下,我们可以实现除非已经通过控制器认可,否则不能在客户端访问该文件的限制;不能直接访问/WEB-INF目录层次,必须通过内部请求才能访问,比如通过某控制器和RequestDsipatcher的请求。
如果直接访问该资源,比如使用如下的URL地址:
http:
//localhost:
8080/corepatterns/WEB-INF/privateaccess/secure-page.jsp
则服务器会答复所请求的资源不再有效,如图:
(二)通过控制组件实现访问控制
实现访问限制的另外一个方法是授权给某控制组件,如范例代码:
9、用会话封装实体
10、引入业务代表
11、合并会话Bean
12、消除实体Bean之间的通信
13、把业务逻辑移动到会话
参考文献
●精通EJB2
●J2EE核心模式
●实体J2EE设计模式