??xml version="1.0" encoding="utf-8" standalone="yes"?> J2EE体系包括java server pages(JSP) ,java SERVLET, enterprise beanQW(xu)EB service{技术。这些技术的出现l电(sh)子商务时代的WEB应用E序的开发提供了一个非常有竞争力的选择。怎样把这些技术组合v来Ş成一个适应目需要的E_架构是项目开发过E中一个非帔R要的步骤。完成这个步骤可以Ş成一个主要里E碑基线。Ş成这个基U有很多好处Q?/P>
大家都知道这些好处,一心想形成一个这L(fng)J2EE应用E序架构Q就像在windowsq_中的MFCQ。在q个路程中经历了两个大的阶段Q?/P>
模型1其实不是一个什么稳定架构,甚至谈不上Ş成了架构。模?的基是JSP文g。它从HTTP的请求中提取参数Q调用相应的业务逻辑Q处理HTTP?x)话Q最后生成HTTP文档。一pdq样的JSP文g形成一个完整的模型1应用Q当然可能会(x)有其他辅助类或文件。早期的ASP ?PHP 技术就属于q个情况?/P>
ȝ看来Q这个模型的好处是简单,但是它把业务逻辑和表现在一块,对大应用来说Q这个缺Ҏ(gu)令h容忍不了的?/P>
1.2. 模型2 它在览器(本文对客户代理都U浏览器Q和JSP或SERVLET之间插入一个控制组件。这个控制组仉中了处理览器发q来的HTTPh的分发逻辑Q也是_(d)它会(x)Ҏ(gu)HTTPh的URL,输入参数Q和目前应用的内部状态,把请求分发给相应的WEB 层的JSP 或SERVLET。另外它也负责选择下一个视图(在J2EE中,JSP,SERVLET?x)生成回l浏览器的html从而Ş成视图)。集中的控制lg也有利于安全验证Q日志纪录,有时也封装请求数据给下面的WEB tier层。这一套逻辑的实现Ş成了一个像MFC的应用框Ӟ位置如图Q?/P>
1.3. 多层应用 应用框架目前主要集中在WEB层,旨在规范q一层Y件的开发。其实企业组件层也可以实现这个模型,但目前主要以设计模式的Ş式存在。而且有些框架可以扩充Q有了企业组件层lg的参与,框架?x)显得更紧凑Q更自然Q效率会(x)更高?/P>
目前Q实现模?的框架也在不断的涌现Q下面列出比较有名的框架?/P>
2.1. Apache Struts 2.1.1. Struts和MVC 模型2的目的和MVC的目的是一L(fng)Q所以模?基本可以和MVC{同h。下图体CStruts的运作机理:(x) 2.1.1.1. 控制 如图所C,它的主要部g是一个通用的控制组件。这个控制组件提供了处理所有发送到Struts 的HTTPh的入口点。它截取和分发这些请求到相应的动作类Q这些动作类都是Actioncȝ子类Q。另外控制组件也负责用相应的h参数填充 From bean,q传l动作类。动作类实现核心商业逻辑Q它可以通过讉Kjava bean 或调用EJB。最后动作类把控制权传给后箋的JSP 文gQ后者生成视图。所有这些控刉辑利用一个叫struts-config.xml文g来配|?/P>
2.1.1.2. 模型 模型以一个或几个java bean的Ş式存在。这些bean分ؓ(f)三种Q?/P>
2.1.1.3. 视图 控制lgl传HTTPhl实C视图的JSP文g。JSP能访问beans q生成结果文档反馈到客户。Struts提供JSP 标签库:(x) HtmlQBeanQLogicQTemplate{来辑ֈq个目的Qƈ有利于分开表现逻辑和程序逻辑?/P>
2.1.2. Struts的细节分?/B> 2.1.2.1. 视图-控制-模型 用户发出一?.do的HTTPhQ控制组件接收到q个h后,查找针对q个h的动作映,再检查是否曾创徏q相应的动作对象Qaction实例Q,如果没有则调用actionmapping生成一个动作对象,控制lg?x)保存这个动作对象供以后使用。接着调用actionmapping的方法得到actionForm对象。之后把actionForm作ؓ(f)参数传给动作对象的performҎ(gu)Q这个方法结束之后会(x)q回l控制组件一?actionforward对象。控制组件接着从这个对象中获取下一个视囄路径和重定向属性。如果ؓ(f)重定向则调用HTTPSERVLETREPONSE的方法来昄下一个视图,否则相调用requestdispatcher, SERVLETcontext的方法箋传HTTPhC一个视图?/P>
当动作对象运行performҎ(gu)Ӟ可能出现错误信息。动作对象可以保存这些错误信息到一个error对象中,接着调用自n的saveerrorsҎ(gu)把这个错误保存到request对象的属性中。接着动作对象调用actionmapping对象的getInputҎ(gu)从动作映中获取input参数Q也是产生输入的视图,q以q个input为参数生成一个actionforward对象q回。这个input参数的JSP中一般有HTTP:errors定制标签dq些错误信息q显C在面上?/P>
下面是一个logon.JSP 的代码实例:(x) 2.1.2.2. 模型到视?/P>
模型到视图指视图在显CZ前装载系l数据到视图的过E。系l数据一般ؓ(f)模型内java bean的信息。示意图表现了由控制lgforwardq来的有html:form定制标签的JSP 的处理逻辑?/P>
html:form定制标签处理对象从application scopeQ通过查询SERVLETCONTEXT对象的属性来实现Q获取先前由控制lgactionSERVLET攑֜那里的动作映等对象Q由html:form 的action属性查得actionform名字、类型和范围{信息,在相应的范围内查找actionformQ如果有则利用它的信息填充html form表单[实际填充动作在嵌套的html:text{定制标{处理对象中]。否则在相应范围内创Z个actionform 对象?/P>
2.1.3. 优缺?/B> 优点Q?/P>
~点Q?/P>
修改把actionform属性的讄器和讉K器修Ҏ(gu)d或生成xml文档的方法,然后 html form和actionform之间用xml文档q行数据交换Q之松散耦合Q适应数据l构易变化的应用?/P>
2.2. JATO q个框架功能主要有三部分l成Q?/P>
应用框架核心定义了基本接口、对象协议、简单组Ӟ以及(qing)iPlanet应用框架E序的最核心。包括视囄单组件、模型简单组件、请求分发组件和可重用命令对象。iPlanet应用框架lg利用框架核心定义的基本接口、协议和lg向开发者提供高层的重用lgQ这些组件既有与特定视觉效果无关的水q组Ӟ同时也有适应特定实用环境、提高可用性而特意提供的垂直型组件。框架扩展实C用框架相容的Ҏ(gu)讉K非J2EE环境的方法。通常情况下,扩展被框架应用程序用来无~访问J2EE容器特定功能。JATOq_栈图很清楚地表达了这个情c?/P>
JATO最大的威力在:(x)对于快速开发用P你能利用框架lg和扩展提高生产率Q对于要求更大灵zL的用户Q你能实现框架核心提供的接口来保持应用的框架兼容性?/P>
此图表示实现一个JATO应用E序Q可以简单地实现控制lgmodule1ServletQ视囄件ListCustomersViewBean和模型组件CustomersModuleImplQ以?qing)一个给客户代理昄界面的ListCustomers.jsp文g。ƈ清楚地表明这些组件与JATO框架lg的承关pR?/P>
JATO标签库提供了VIEW对象与JSP文g的接口。库中标{֤理程序负责实现VIEW对象和JSP产生地客L(fng)文档的信息同步和交换。这个图清楚地表达了q种对应关系 2.2.1. MVC分析 前端控制lg接收用户发来的Q何请求,q个可在WEB.xml中指定请求分发组件负责视囄理和DQ和前端控制lg装在ApplicationSERVLETBase一起实现。应用程序开发者需要ؓ(f)每一个子pȝQh力资源,财务QCRM{)实现一个此cȝl承?/P>
h分发lg分发hl工作者,工作者实Ccommand接口。应用开发者可以实现这个接口。JATO提供了一个缺省实玎ͼ(x)DefaultRequestHandingCommandQ这个实C(x)把请求传l视囄件的特定事g?/P>
l合视图是指视图lg在显C给用户时的层次关系Q根视图是一个ViewBeancȝ对象字段是一个DisplayFieldcȝ对象Q容器视图是一个ContainerViewcȝ对象。视囄件类的层ơ关pd下图Q?/P>
2.2.2. 优缺点分?/B> 优点Q?/P>
~点Q?/P>
修改 2.3. JSF(JavaServer Faces) JSF非常单,是一个定义良好的~程模型。利用这个技术,开发者通过在页面内l合可重用的UIlgQ在把这些组件和应用的数据源相连Q\由客户生的事g到服务器端的事g处理器进行编E。JSP处理了所有幕后的复杂工作Q得开发者把x重点攑֜应用代码上?/P>
2.3.1. STRUTS、JATO和JSF比较 它们之间有部分重叠,但重点不一栗?/P>
2.4. WAF 2.4.1. l节分析 2.4.2. 视图-控制-模型 如图所C,开发h员编写的两个xml配置文g定义了WAF的运作参数。Screendefinition.xml定义了一pd的屏q?screen)。Mapping.xml则定义了某个动作之后应该昄的屏q,但没有指定屏q到哪里拿数据?/P>
用户发出一个HTTPhQ?.screenQ,由TemplateSERVLET屏幕前端控制lg接收Q它提取h信息Q设|request对象CurrentScreen属性,再把h发到模版JSP。模版JSP收到h后,JSP中的Template标签察看q个当前屏幕Qƈ从屏q定义文ӞScreendefinition.xmlQ中获取q个屏幕的具体参敎ͼ再生成htmlq回l客戗?/P>
假设q回l客L(fng)html中包括了html表单Q用户在输入一定数据之后提交,发出一个HTTPhQ?.doQ。这个请求被MainSERVLET接收Q它提取h信息Q察看动作映文Ӟmapping.xmlQ,讄处理q个h的动作对?HTTPAction对象)Q交lrequestprosessor对象处理。Requestprosessor对象调用动作对象完成dQ如果需要进一步处理,requestprosessor对象?x)调用WEBclientcontroler对象的事件处理机制。MainSERVLET在处理完h之后Q从屏幕管理对象那里得C一个屏q,q把h传给q个屏幕的JSP文g?/P>
值得一提的是WEBclientcontroler事g处理机制最l把HTTPh的数据传CEJBAction对象那里处理。这样HTTPAction对象和EJBAction对象形成了两U处理机Ӟ前一U与request对象紧密相关Q把数据装h形成一个Event对象Q再传给了EJBAction对象Q后者与Request对象无关。这个方式可以Ş成一个sessionU别的数据处理机制。下图显CZq个Ҏ(gu)。HTTPAction1对象处理一个请求,q把数据攑ֈ一个状态SessionBean内,HTTPAction2也如此,当HTTPAction3接收到HTTPh之后Q把控制传给EJBAction, 后者获取状态SessionBean数据Q处理请求,成功后清控状态SessionBean的内宏V这个机刉帔R应多个输入面才能满一个业务的输入数据的情况(比如购物车)?/P>
2.4.3. 优缺点分?/B> 优点 ~点 修改意见 现在的问?/STRONG> 现在我们J2EE开发碰C什么问题呢Q?让我们想象一下用Spring和Hibernate开发一个J2EE WEB应用是什么样的:(x)我们需要增加一个新的域对象cd为PersonQ下面主要的开发步骤:(x) 你会(x)实感慨Q真是需要很多步骤啊?/P>
如何解决Q?/STRONG> 关键问题是我们开发时不能重复一些步骤,因此必须量减少步骤Q如果只减少步骤? 是否只需要第一个步骤就可以Q在W一步时Q我们花Ҏ(gu)多时间精力进行域建模Q确定域模型的属性行为等。其他步骤我们会(x)发现下面的规律:(x) 当然Q在复杂应用中,不会(x)只是q些功能Q但是如果我们将q些功能通过框架实现Q将大大提高我们的开发效率?/P>
域驱动开?/STRONG> 域驱动开?domain driven development framework )Q简UDDD是一U最新的OO设计概念Q它是由ROR?A target=_blank>Naked Objectl织提出的?/P>
所谓naked Object是指一个复杂的域对象,q个Object是一个POJOQ但是不是一个傻?c)完全是属性的POJOQ而是装了业务逻辑的POJOQ注意这里是最大的区别Q一般业务逻辑我们是通过另外的ServicecL实现Q然后在Service中封装的transaction script(Martin Fowler却称血模型) Q?naked Object则是合ƈh的(有的cM回归传统?W合Martin Fowler审美观了Q,但是Q这U纯OO是和SOA()思想矛盾?Service-Oriented vs. Object-Oriented )Q可?A id=viewpost.ascx_TitleUrl target=_blank>Adventures in SOA(puts the business logic in service-like methods instead of on the object, service method -> business method --> persistence method) ) 个h感觉整个软g好像一直在??的游戏,不过也许最复杂的体pd是来自最单的抉择Q如股票/汇市{投资领域也如此?/P>
naked Object提出现在J2EE开发和怽对象DDD开发下的图Q?/P>
通过q张图我们可以看刎ͼ以前方式造成J2EE开发层ơ之间调用乱,修改和拓展非怸方便Q而在双的DDD开发方式下Q?STRONG>界面(边界)对象是域对象就是持久化的实体BOQ没有多余的Contorller或Action了。原来Domain层被服务层Service layer遮挡Q在叛_中,则Domain层直接暴露给前台了,所以Domain没有东西被遮盖,裔R了,UCؓ(f)Naked(裔R) Objects. 现在怎么办? ROR提倡的DDD方式引v了众多J2EE开发者的兴趣Q在各大Java媒体正在引vq泛的讨论,但是ROR不是Java的,那么有无ZJava的DDD开发框架呢Q?/P>
目前有不DDD开发框架正在诞生中Q?A target=_blank>Jdon框架正是在RORq种_指引下的一Ƒֿ速开源开发框ӞJdon框架1.2.2版本虽然不是一个完全意义上的Naked ObjectQ基于Service-Oriented 架构,但是已经初步具备上图双开发流E,具体可参?A target=_blank>Jdon Sample的开发流E?/A> 使用Jdon框架开发J2EE应用pȝQ最重要的一个前提是Q设计好你的域对象,然后在将域对象复制到表现层,变成表现层的ActionForm/ModelFormQ将域对象直接在持久层用Hibernate/iBatis{持久化到数据库Q如果用EJB的实体Bean持久化技术,无需实现建立数据表;应用pȝ部vӞJ2EE容器直接根据实体徏立数据表Q也可节省前面步骤中两个步骤?/P>
当然Q目前Jdon框架是采取分L法,遵@桥模式,抽象和行ؓ(f)分离Q每个域对象对应一个操作它的服务类或DAOc,服务cM要用来封装业务逻辑层,然后业务Service作ؓ(f)一个业务组件暴露给表现层的Controller/Actionc,而Controller/Action则无需代码Q只要通过如下配置卛_完成Q?/P>
<model key="username" class="com.jdon.framework.samples.jpetstore.domain.Account"> 通过上述配置Q净化了上图中应用控制层(Application or Controller layer)和Domain Layer之间对应关系Q变得有条理而且明晰?/P>
随着Naked Object 被越来越多h认识和应用成熟,Jdon框架也将转向支持另外一个纯OO派Naked ObjectQ?p它同时支持POJOz֒EJBz一栗? 在Jdon框架以后版本中,?x)很方便支持Naked ObjectQ只要将上面配置文g指向Service去除QCRUDҎ(gu)由Model自己实现Q如下:(x) <model key="username" class="com.jdon.framework.samples.jpetstore.domain.Account">
作ؓ(f)一个用OOP多年的h来说Q当我听说AOP可以解决一些OOP一直都不能优雅地解决的问题Ӟ我觉得应该去探个I竟了。对两种技术的比较最能给我们实际应用提供见解。这里我设计了一个例?一个OOP应用Q其中某些方面适合使用AOP?
本文展示了一个简单的例子。一开始介l了问题域,然后分别l出OOP与AOP的解x案。后者用了JDK5.0QJUnitQ和AspectWerkz。最后说明如何编写代码。读完本文后Q我希望你能知道AOP到底是什么,解决什么样的问题?׃作者在后面AOP的例子中使用了Java5?的批?Annotation)Q徏议读者先有所了解)
问题域描q?
一个Y件公叔R佣一个程序员Q指定给他一个业务部门ƈ要求他随时向l理报告。当团队成员完成他们的目标时Q经理会(x)l他们相应的奖金。公司所需要的Ҏ(gu)必须能够增加一个新的雇员ƈl当前的员工增加奖金。ؓ(f)了方便,我们用CSV文g存储数据?
cManager(l理)l承自类EmployeeQ包含一个额外的属性,Managing Project。一个部门可能包含很多员工。多个部门构成了公司。暂不考虑公司q样的一个类Q因为它在问题域之外?
解决Ҏ(gu)设计
以下程图描qC解决Ҏ(gu)设计?
Z单的考虑Q本文只x必需的细节。当然你也可以深入代码得C惌的其他信息?
[link]http://www.devx.com/assets/sourcecode/13172.zip[/link]
EmployeeServiceTestCaseQ一个JUnit试用例Q模拟一个最l用P创徏新员工记录,指派部门和经理。它获取所有可用的部门和经理数据ƈ昄在图形界面上?
Z实例化域对象BusinessUnit和ManagerQ获得的记录传递给工厂cR之后,通过lEmployeeService传递一个引用来创徏一个Employee对象?
q个服务cM用EmployeeFactory创徏对象Qƈ把这个对象传lEmployeeRepository 来进行持久化操作?
应用E序中需要面向哪?切面"
到目前ؓ(f)止,Ҏ(gu)型和设计的讨限于一个较抽象的层面。现在,我{向这个应用的其他斚w - q对理解AOP的h(hun)D关重要?
操作所需的资?BR>
上面的代码通过FileReader和BUfferedReader来读取CSV文g中的业务数据。应用程序重复地从资源文件中取得数据然后在操作完成后释放。我们会(x)发现:LE序的这两个"切面"提高代码的可读性ƈ辑ֈ一个更好的设计Q因为去掉这?多余"的东西,剩下的代码才是这个方法真正的_N?
q个Ҏ(gu)的作用是d业务单位数据。所以不应该也不需要去知道"如何获取和释放资源以?qing)这个过E中出现的异?q个"切面"。同样地Q用AOP处理异常也变得不同?后面详l介l?
持久?
传统的OOP使用仓库c?repository classes)来打理应用程序的持久层。即:
cEmployeeService 使用一个仓库类l应用中相关雇员提供服务Q在一个企业应用中Q从域模?domain model)中去掉持久层代码是一U设计上的改q。模型设计者和E序员就可以x各自的业务逻辑和持久层处理。后面你会(x)看到如何通过AOP来达到这L(fng)效果?
日志
删除用于调试的日志代码将?x)极大地改进代码的可L。考虑下面的代码片?
上面的代码里包含了一个致命错误和一个成功信息。输出日志这一"切面"同样可以Ud业务模型外独立实现?
异常处理
异常处理的例子我q里不再赘述Q但q节已经通过上面的代码讨Z潜在的问题。当你调用EmployeeRepository对象的createEmployeeҎ(gu)Ӟ你可能会(x)得到一个RepositoryException异常?
传统的解x法是Q在q个cM处理。另一U方法是Q当RepositoryException异常被抛出时createEmployee Ҏ(gu)q回nullQcatch块中的其他逻辑可以在类外处理这一错误?
错误处理在不同的情况中也?x)不同。但是,通过AOP可以区分开每种情况?BR>
?中描qCAOPҎ(gu)的设计以?qing)在一个更抽象的层ơ上c间的交互。你可以通过Ҏ(gu)?和图3来更好地理解AOP。程序的目的是通过BusinessUnit对象dCSV文g中的记录然后填入cBusinessUnitService中的map?
使用AOP来填充这个map有点cM后门(backdoor)Ҏ(gu) -- 控制被委zBusinessUnit 来读取存储介质中的记录?
AOP是定义一些切入点(pointcut)和处理方?advice)。一?切入?是源代码中一个执行点。前面的例子定义了一?切入?--cBusinessUnitService中的findBusinessUnitsҎ(gu)。一?处理Ҏ(gu)"思义是当执行到某个"切入?时的一块代码?
cBusinessUnitPersistentAspect包括adviceҎ(gu)findAllBusinessUnitsQ该Ҏ(gu)从存储介质中载入数据Q然后用工厂类创徏BusinessUnit对象。然后这个对象被加入mapQmap对象的引用通过BusinessUnitService对象获得?
"切入??处理Ҏ(gu)"l成了所谓的"切面(Aspect)"Zd存储介质中的数据QOOPҎ(gu)通过一个DAOcL做。而AOP中,你只要定义一?切入?和相应的"处理Ҏ(gu)"来读取数据。AOP框架?x)以advice的Ş式注入代码,既可以在执行期也可以在编译期?
总而言之,当类BusinessUnitService 中的findAllBusinessUnits Ҏ(gu)被调用时QAOP框架?x)?切入?处注入处理方法,通过BusinessUnit 对象预先d数据来填充map对象。这P持久层方面的代码可以移C务代码之外了?
新方法里?切面"
本节讨论如何用AOP为应用程序的各个"切面"建模
操作资源
cBusinessUnitPersistenceAspect 的持久方法用了一个buffered reader。你甚至可以定义"切面"?切面"Q但Z单,q里只关注类的查找方法?
上面的代码试图ؓ(f)每一个方法创?切入?--所有以find开头的Ҏ(gu)。无Z时这些方法被调用QassignReaderҎ(gu)都会(x)被提前执行。这里它获取被调用的cd例然后设|新建的buffered reader?
同样圎ͼ在releaseReader Ҏ(gu)里,代码?x)预先关闭buffered reader集合。本节只解释@before和@
AfterFinally q两?切入??以J2SE 5?的标记定?。另外,你也可以在方面定义的xml文g中声明他们。你可以查看例程源代码中的aop。xml文g?
下蝲
持久?
前面提到QOOPҎ(gu)使用BusinessUnit来ؓ(f)应用的持久层填充Map。在下面的高亮代码中(@before一行,以及(qing)while循环代码)Q当BusinessUnitService中的Ҏ(gu)findAllBusinessUnits 被调用时"处理Ҏ(gu)"findAllBusinessUnits 也将被调用?BR>
"处理Ҏ(gu)"从数据存储中d记录Q用工厂类创徏一个BusinessUnit实例。然后这个实例被加入到Map。该Map掌管E序的所有持久化"切面"?
日志
本文中的例子没有包含一个完整的日志AOP解决Ҏ(gu)。但是,它ؓ(f)java。lang。ObjectcȝtoStringҎ(gu)定义了一?切入?来获取类的调试信息。因此,域中的类不需要实现toStringҎ(gu)。通常可能你可能需要ؓ(f)每一个类都要实现q个Ҏ(gu)?
你也可以用这个样例代码完成错误处?切面"?
深入源代?
Z理解样例需求的OOP设计Q请参看源代码ƈ思考以下几个问? 下蝲
* 首先分析oldway包中EmployeeServiceTestCase cM的代?
*查看testEmployeeCredit Ҏ(gu)
*搞懂业务cEmployee和BusinessUnit
*学习(fn) serviceQrepository和factory概念。这些是业务驱动设计的主要概c?
*更深入地理解oldway包中的serviceQrepository和factoryc?
而AOP地理解则应该?
*分析newway包中EmployeeServiceTestCase c?
*查看serviceQrepository和factoryc,基本和前一U差不多。只是你要让"处理Ҏ(gu)"截获E序的执行流E?
*研究aspectcd?切入?的定?
要执行程序,你需要做的工?
* 下蝲AspectWerkz 2? http://aspectwerkz。codehaus。org/
*讄以下的环境变?
*解压~源代码和其他文?
*~译Java文gQ但不要~译试用例否则你调试时?x)遇C个错误?
*q行ȝ调试。假设你把文件解压羃到c:\aopQ类文g解压到c:\aop\classesQ在c:\aop目录下执行以下命?
*AOP框架?x)修改类来注入必要的字节?
*~译试用例Q用JUnitq行它?
后记
当你完成了上面的q些工作Q你应该有以下的领?zhn)?
*E序中的交叉兌
*关于AOP中深入源代码
Z理解样例需求的OOP设计Q请参看源代码ƈ思考以下几个问?
下蝲
* 首先分析oldway包中EmployeeServiceTestCase cM的代?
*查看testEmployeeCredit Ҏ(gu)
*搞懂业务cEmployee和BusinessUnit
*学习(fn) serviceQrepository和factory概念。这些是业务驱动设计的主要概c?
*更深入地理解oldway包中的serviceQrepository和factoryc?
而AOP地理解则应该?
*分析newway包中EmployeeServiceTestCase c?
*查看serviceQrepository和factoryc,基本和前一U差不多。只是你要让advice截取E序的流E?
*研究aspectcd?fn)point cut的定?
要执行程序,你需要做的工?
* 下蝲AspectWerkz 2.0 http://aspectwerkz。codehaus。org/
*讄以下的环境变?
*解压~源代码和其他文?
*~译Java文gQ但不要~译试用例否则你调试时?x)遇C个错误?
*q行ȝ调试。假设你把文件解压羃到c:\aop Q类文g解压到c:\aop\classesQ在c:\aop目录下执行以下命?
*AOP框架?x)修改类来注入必要的字节?
*~译试用例Q用JUnitq行它?
后记
当你完成了上面的q些工作Q你应该有以下的领?zhn)?
*E序中的交叉兌
*关于AOP?切面"的含?
*如何用AOP来把E序业务层中的交叉关联分d来,使用"切入??处理Ҏ(gu)"
*OOP和AOP时在E序控制上的不?
从本文你应该也得CU看待实际开发的新视角。你应该有信心用AOP来改q项目中的设计,建模Q提高代码的重用性。至,你可以开始用AOP来处理日志,错误和持久化?
个h觉得QAOP的学?fn)曲U相对较陡,其在理解定?切入?的句法时。理想的情况是,使用OOP来设计业务模型,使用AOP把业务模型中的交叉关联移出,从而代码zƈ提高可读性?
AOP的一个缺Ҏ(gu)?x)调试变得困难Q因Z同于OOPQ程序流变的复杂了,交互是由~译期或执行期决定。我准备来做一些自动化工具来解册个问题?
]]>
Z形成架构基线Q架构设计师要对q_Q体p)中的技术进行筛选,各种利弊的权衡。往往架构设计师在q个q程中要阅读大量的技术资料,听取目l成员的Q考虑领域专家的需求,考虑赞助商成本(包括开发成本和q行l护成本Q限额。一旦架构设计经q评审,q些因数初步地就有了在整个项目过E中的对目起多大作用的定位?
一旦架构师设计的架构得C批准形成了基U,目开发和q行所采用的技术基本确定下来了。众多的目l理都会(x)寚w备项目组成员的技术功底感到担心;他们需要培训部门提供培训,但就架构师面对的技术vz,目l理Ҏ(gu)提不出明确的技术培训需求。怎不能够对体pM所有技术都q行培训吧!有了架构里程基U,目l理能确定这个项目开发会(x)采用什么技术,q是提出培训需求应该是最_的。不q在实际目开发中Q技术培训可以在基线定之前与架构设计ƈ发进行?
有了一个好的架构蓝图,我们p准确划分工作。如|页设计QJSP 标签处理c设计,SERVLET 设计Qsession bean设计Q还有各U实现。这些Q务在架构蓝图上都可以清晰地标Z|,使得目l成员能很好地定位自qd。一个好的架构蓝囑时也能规范化dQ能很好地把d划分为几c,在同一cM的Q务的工作量和性质相同或相伹{这样工作量估计h有一个非常好的基?
前面说过各个d在架构图上都有比较好的定位。Q何h能借助它很快地熟?zhn)整个目的运行情况,错误出现时能比较快速地定位错误炏V另外,有了清晰的架构图Q项目版本管理也有很好的版本?wi)躯qӀ?
架构犹如一颗参天大?wi)的w干Q只要躯q根pȝQ树(wi)q粗Q长一些旁支,加一些树(wi)叶轻而易举无疑。同P有一个稳定的l得赯验的架构,增加一两个业务lg是非常快速和Ҏ(gu)的?
在经q一番实践,q广泛借鉴和ȝl验教训之后QJ2EE应用E序l于q来了MVCQ模?视图-控制Q模式。MVC模式q不是J2EE行业人士标新立异的,所以前面我谈到q发借鉴。MVC的核心就是做C层甚臛_层的松散耦合。这对基于组件的Q所覆盖的技术不断膨胀的J2EE体系来说真是音和救星?/P>
下图为J2EE体系中典型的多层应用模型?/P>
一般ؓ(f)览器或其他应用。客户层普遍地支持HTTP协议Q也U客户代理?
在J2EE中,q一层由WEB 容器q行Q它包括JSP, SERVLET{WEB部g?
企业lg层由EJB容器q行Q支持EJB, JMS, JTA {服务和技术?
企业信息pȝ包含企业内传l信息系l如财务QCRM{,特点是有数据库系l的支持?
Struts是一个免费的开源的WEB层的应用框架Qapache软g基金致力于struts的开发。Strutsh高可配置的性,和有一个不断增长的Ҏ(gu)列表。一个前端控制组Ӟ一pd动作c,动作映射Q处理XML的实用工L(fng)Q服务器端java bean 的自动填充,支持验证的WEB 表单Q国际化支持Q生成HTMLQ实现表现逻辑和模版组成了struts的灵?/P>
它保存了HTTP posth传来的数据,在Struts里,所有的Form beans都是 ActionFrom cȝ子类?
专门用来处理业务逻辑?
它保存了跨越多个HTTP h的单个客L(fng)?x)话信息Q还有系l状态?
<%@ page language="java" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<html:html locale="true">
<head>
<title><bean:message key="logon.title"/></title>
<html:base/>
</head>
<body bgcolor="white">
<html:errors/> <!-- 如果出现错误?x)显C在q里 -->
<html:form action="/logon" focus="username">
<table border="0" width="100%">
<tr>
<th align="right">
<bean:message key="prompt.username"/>
</th>
<td align="left">
<html:text property="username" size="16" maxlength="16"/>
</td>
</tr>
<tr>
<th align="right">
<bean:message key="prompt.password"/>
</th>
<td align="left">
<html:password property="password" size="16" maxlength="16"
redisplay="false"/>
</td>
</tr>
<tr>
<td align="right">
<html:submit property="submit" value="Submit"/>
</td>
<td align="left">
<html:reset/>
</td>
</tr>
</table>
JATO应用E序框架是iPlanet 应用E序框架的旧名。它是一个成熟的、强大的Q基于J2EE标准的面向于开发WEB应用E序的应用框架。结合了昄字段、应用程序事件、组件层ơ和以页面ؓ(f)中心的开发方法、以?qing)MVC和服务到工作者service-to-workers的设计模式等概念。JATO可适用于中、大、超大规模的WEB应用。但是它也不是一个企业层的应用框Ӟ也就是说它不?x)直接提供创建EJB, WEB services{企业层lg的方法,但用它可以构造出讉K企业层组件的客户应用?/P>
把众多的VIEW/MODEL对应修改成xml文档传递数据,加上集中的网导航定?
JSF是一个包括SUN在内的专家组正在定义的开发WEB应用用户界面的框ӞJSF 技术包括:(x)
WAF是WEB APPLICATION FRAMWORK的简Uͼ是SUN蓝皮书例子程序中提出的应用框架。它实现?MVC和其他良好的设计模式?/P>
只有一个框架躯qԌ正ؓ(f)实现自己的应用框架提供了灉|性。没有僵化的视图概念Q提供了在网输入到模型的扩充接口,比如插入XML数据交换?
]]>
复杂?BR> 复杂性是应用开发过E中最令h头疼的一个问题。每当在一个应用中增加一个功能时Q它的复杂性通常呈几何的增ѝ这U复杂性往往DE序的开发无法再l箋下去。这也是现在Z么许多应用只有Beta版本而没有正式版的原因?BR>
专家应用开发过E生的复杂性分Zc,即非本质的(accidentalQ和本质的(essentialQ。本质的复杂性是对于解决目标问题所必然产生的复杂性,非本质的复杂性是׃选择了不适当的开发工具和设计工具而生的复杂性。对于一个功能确定的E序来讲Q本质的复杂性是定的,而非本质的复杂性则是没有限制的。因此,一个应用的开发要惌利地取得成功,需要尽可能地减非本质的复杂性?BR>
OOD的特?BR> 面向对象的设计(OODQ将一个程序分解成Ҏ(gu)具体的对象而设计的一pd元素。这些具体对象的行ؓ(f)和数据以一U叫做“类QclassQ”的~程单元q行打包。应用程序创Z个或多个q些cȝ例示Q也UCؓ(f)“对象(objectQ”。类的行为是通过创徏对象之间的关pȝ合在一L(fng)?BR>
OOD允许开发者用两种主要的方法来控制复杂性的增加。第一QOOD定义严格的出口语义,q允许开发者隐藏实现的l节Qƈ且明说明什么方法是其它的对象可以访问的。这个信息隐藏得可以对大部分的代码q行修改而不影响其它的对象?BR>
W二QOOD对象之间的关系分ؓ(f)四类Qѝ包宏V用和协调。适当C用这些关pd以大大减应用开发过E中本质的和非本质的复杂性。如Q承是产生面向对象设计中可再用的主要因素。这个再使用性是通过代码׃n和多态性获得的。这U再使用可以大大减少应用的本质的复杂性。包容允怸个类的用户在使用包容器时忽略被包容的c(classQ。这个简化设计者能够大大减应用的非本质的复杂性?BR>
可视化接口在OOD斚w的不?BR> 许多E序都需要可视化接口Q这些接口由对话框、选单、工h{组成。这些可视化接口的增加会(x)引进OOD设计的不I使得一个好的面向对象的设计走向反面。可视化接口有三个属性可能会(x)l应用开发带来麻烦?BR>
W一Q可视化接口提高了传l的面向操作的拓扑结构。用户生接口事Ӟ如开x键和列表框选择{,受到E序的一个模块的驱动q且用来寚w态的数据q行操作。在设计中将q面向操作的拓扑l构同一个面向对象的设计混合在一起将D对象之间的大量的杂合?BR>
W二Q用h口通常对于同样的信息经怼(x)需要许多不同的昄。如Q一个客户选择列表框可以包含一个客L(fng)名字和电(sh)话号码以?qing)许多其它客L(fng)名字?BR>
当用户选择某个特定的客户后Q他Q她的名字和?sh)话L(fng)?qing)其它全部相关的信息都?x)详细地显C出来?BR>
除此之外Q一个简单的E序可能h不同的用h口。如一个银行̎L(fng)l有一个接口用于出U_来访问̎户^衡、存?gu)Ƒ֒取款Q而监督者的接口则包含另外的信息q加上̎L(fng)理的功能。这些不同的接口很容易导致类的扩展?BR>
最后,可视化接口在整个设计阶段q会(x)q行较大的改变。这些改变包括完全重新安排用户与pȝ的交互操作等。可视化接口的这些改变即使在最好的设计中也?x)增加应用开发的复杂性?BR>
MVC弥补可视化接?OOD的不?BR> 模型Q界面/控制器(ModelQViewQControllerQMVCQ编E技术允怸个开发者将一个可视化接口q接C个面向对象的设计中,而同时还可以避免我们上面讨论的几个问题。MVC最初是为Smalltalk语言而设计的。MVC通过创徏下面三个层将面向对象的设计与可视化接口分开Q?BR>
模型QModelQ:(x)模型包含完成d所需要的所有的行ؓ(f)和数据。模型一般由许多cȝ成ƈ且用面向对象的技术来创徏满五个设计目标的程序?BR>
界面QViewQ:(x)一个界面就是一个程序的可视化元素,如对话框、选单、工h{。界面显CZ模型中提供的数据Q它q不控制数据或提供除昄外的其它行ؓ(f)。一个单一的程序或模型一般有两种界面行ؓ(f)?BR>
控制器(ControllerQ:(x)控制器将模型映射到界面中。控制器处理用户的输入,每个界面有一个控制器。它是一个接收用戯入、创建或修改适当的模型对象ƈ且将修改在界面中体现出来的状态机。控制器在需要时q负责创建其它的界面和控制器?BR>
控制器一直决定哪些界面和模型lg应该在某个给定的时刻是活动的Q它一直负责接收和处理用户的输入,来自用户输入的Q何变化都被从控制器送到模型?BR>
界面从模型内的对象中昄数据。这些对象的改变可以通过也可以不通过用户的交互操作来完成。如Q在一个Web览器中负责接收面的对象收集和装配栈中的信息,必须有某U方式来让这些对象通知界面数据已经被改变了。在模型变化时有两种Ҏ(gu)来对界面q行更新?BR>
在第一U方法中Q界面可以告诉模型它正在监视哪些对象。当q些对象中有M一个发生变化时Q一个信息就被发送给界面。界面接收这些信息ƈ且相应地q行更新。ؓ(f)了避免我们上面讨论的不Q模型必能够不用修改就支持许多U不同的界面昄?BR>
W二个方法ƈ不直接将界面q接到模型中Q它的控制器负责在模型变化时更新界面。控制器通过Ҏ(gu)型对象或观察器方法进行监来模型中的变化。这个方法不用了解界面的模型知识Q因此界面就变成是可以跨应用使用的?BR>
使用MVC的优?BR> MVC通过以下三种方式消除与用h口和面向对象的设计有关的l大部分困难Q?BR>
W一Q控制器通过一个状态机跟踪和处理面向操作的用户事g。这允许控制器在必要时创建和破坏来自模型的对象,q且面向操作的拓扑l构与面向对象的设计隔离开来。这个隔L助于防止面向对象的设计走向反面?BR>
W二QMVC用h口与面向对象的模型分开。这允许同样的模型不用修改就可用许多不同的界面昄方式。除此之外,如果模型更新由控制器完成Q那么界面就可以跨应用再使用?BR>
最后,MVC允许应用的用h口进行大的变化而不影响模型。每个用h口的变化只需要对控制器进行修改,但是既然控制器包含很的实际行ؓ(f)Q它是很Ҏ(gu)修改的?BR>
面向对象的设计h员在一个可视化接口dC个面向对象的设计中时必须非常心Q因为可视化接口的面向操作的拓扑l构可以大大增加设计的复杂性?BR>
MVC设计允许一个开发者将一个好的面向对象的设计与用h口隔d来,允许在同L(fng)模型中容易地使用多个接口Qƈ且允许在实现阶段Ҏ(gu)口作大的修改而不需要对相应的模型进行修攏V?img src ="http://www.aygfsteel.com/qq13367612/aggbug/16890.html" width = "1" height = "1" />
]]>
Person
c?
PersonDAO
c?
Person数据?/CODE>.
PersonDAO?/CODE>Spring的application context XML文g.
实例. Person
page面和actionc?
Person面?/CODE>web框架(如struts)XML配置文g?
.
personList
面来显C?CODE>Person实例personEdit
面来编?CODE>Person
Person
c?
<actionForm name="accountForm"/> //指定边界c?/FONT>
<handler>
<service ref="accountService"> //指定某个业务接口
<getMethod name="getAccount"/>
<createMethod name="insertAccount"/> //业务接口的新增方?/FONT>
<updateMethod name="updateAccount"/> //业务接口的修Ҏ(gu)?/FONT>
<deleteMethod name="deleteAccount"/>
</service>
</handler>
</model>
<actionForm name="accountForm"/> //指定边界c?/FONT>
<handler>
<!-- <service ref="accountService"> //指定某个业务接口 无需业务层,去除-->
<getMethod name="getAccount"/>
<createMethod name="insertAccount"/> //业务接口的新增方?/FONT>
<updateMethod name="updateAccount"/> //业务接口的修Ҏ(gu)?/FONT>
<deleteMethod name="deleteAccount"/>
<!-- </service> -->
</handler>
</model>
]]>
应用E序l构和J2EE
J2EE是一个很成功的技术,它ؓ(f)一些基本的d提供了一致的标准Q例如数据库q接、分布式应用E序{。但是用J2EEq不能保证开发h员开发出成功的应用程序。有些h认ؓ(f)J2EE本n是一U框架技术,但是q种认识是不正确的,我们应该意识到J2EEq没有提供一个能够帮助开发h员开发出高质量应用程序的框架Q因此很多有l验的开发h员通过利用设计模式来I补这一~项?
设计模式
在开发h员的圈子中,大家通过怺交流在开发过E中所遇到的问题以?qing)解x法来丰富整个圈子的经验。而设计模式就是在q样的情况下产生的。一个设计模式必然是针对某个特定的问题的Q这个问题的解决Ҏ(gu)以及(qing)q样解决问题产生的后果。在解决利用J2EEq行E序开发中出现的问题的q程中,Z把设计模式分Zc,一U是通用开发模式,一U是Z解决特定的J2EE问题的模式。下面让我们来看一看每一U类型的开发模式都包含了哪些内宏V?
J2EE设计模式
J2EE设计模式在过dq中随着Java开发h员经验的不断成长而发展。这些设计模式是针对使用各种J2EE技术时可能出现的问题提出的Q它们能够帮助开发h员构造出应用E序框架的要求。例如,Front ControllerQ前端控Ӟ模式servlet代码的开发{化ؓ(f)在图形用L(fng)面下的开发。但是需要记住J2EE设计模型解决了那些在J2EE目中最可能出现的问题。如果你在J2EE遇到的问题很Ҏ(gu)Q很有可能没有相应的设计模型来解军_?
软g开发设计模?
软g开发设计模式又被分ZU,一U是通用的面向对象设计模式。例如工厂(F(tun)actoryQ模式是一U面向对象的设计模式Q它?yu)对象的创徏装hQ对象能够重用Q这样就可以减少E序占用的系l资源。而另一U是ZJava的设计模式,q些设计模式要么是和Java的语aҎ(gu)结合得很紧Q要么是面向对象技术在Java中的深化。不要以Y件设计模式相对独立于J2EEp为它们不重要Q通常它们比J2EE设计模式更重要。这是因为:(x)
1QJ2EE设计模式是近几年才出现的Qƈ且在不断变化Q而Y件开发设计模式经q了长时间的考验Q比前者更加成熟和完善Q?
2Q有些J2EE设计模式是徏立在某些软g开发设计模式之上的Q?
3QY件开发模式ؓ(f)J2EE设计模式提供了坚实的基础。它的应用将影响到整个结构的E_性和可扩充性?
在实际应用中Q设计模式ƈ不是一D具体的代码。设计模式通常是在设计说明书中描述。将设计模式应用到系l中的真正挑战在于如何在pȝ中应用模式中的思想。这些思想必须被应用到恰当的环境中?
Ҏ(gu)设计模式的所解决的问题,又可以分Z下几个类型:(x)
· 创徏cdQ创建类型的模式都是用于创徏cȝ实例。但是和通过new来创建实例不同,q些模式提供了更加灵zȝ方式Q是E序能够Ҏ(gu)特定的情况创建特定的cR?
· l构cdQ结构类型的模式帮助开发h员将单对象组合在一起以后的更加复杂的结构?
· 行ؓ(f)cdQ行为类型的模式帮助开发h员控制类之间的通讯?
创徏cd的模?
所有创建类型的模式都和如何有效地创建类的实例相兟뀂在Java中,如果开发h员要生成一个类的实例,最单的Ҏ(gu)是用new关键字:(x)
MyFoo = new Foo(); // 生成一个Foo的实?BR>
q种Ҏ(gu)只能够在E序中生成固定的cR但是在很多情况下,E序需要根据不同的情况生成不同的类的实例,q就需要将实例的生成过E抽象到一个特D的创徏cMQ由该类在运行时军_生成哪种cȝ实例。这样得程序有更好的灵zL和通用性?
创徏cd的模式包括:(x)
· 工厂模式QF(tun)actory PatternQ:(x)Ҏ(gu)工厂模式实现的类可以Ҏ(gu)提供的数据生成一l类中某一个类的实例,而这一l类有一个公q抽象父类?
· 抽象工厂模式QAbstract Factory PatternQ:(x)抽象工厂模式也可以根据提供的数据生成一l类中某一个类的实例,而这一l类有一个公q抽象父类。只不过它定义的是一个接口?
· 构造者模式(Builder PatternQ:(x)构造者模式将一个复杂对象的构造过E和它的表现层分d来,q样cd可以Ҏ(gu)不同情况展现Z同的表现方式?
· 原型模式QPrototype PatternQ:(x)原型模式通过对类的实例进行拷贝来创徏新的实例?
· 单一模式QSingleton PatternQ:(x)Ҏ(gu)单一模式实现的类只允许有一个是c,q且提供了一个全局指针来引用该实例?
l构cd的模?
l构cd的模式将cd对象l合hQ以构成更加复杂的结构。它又被划分为类模式和对象模式。类模式和对象模式之间的区别在于cL式通过l承关系来提供有效的接口Q而类模式通过对象合成或将对象包含在其它对象中的方式构成更加复杂的l构?
l构cd的模式包括了以下模式Q?
· 适配器模式(Adapter PatternQ:(x)适配器模式可以将一个类的接口和另一个类的接口匹配v来?
· 桥梁模式QBridge PatternQ:(x)桥梁模式对客L(fng)E序提供一个固定的接口Q但是允许开发h员变化实际的实现cR这样开发h员就可以接口是具体的实现类分离开来?
· 复合模式QComposite PatternQ:(x)复合模式可以多个对象进行复合,其中的每个对象可以是单对象,也可以是复合对象?
· 代理模式QProxy PatternQ:(x)代理模式利用一个简单的对象替代一个复杂的对象Q当复杂对象在需要的时候才?x)被加蝲到系l中Q这样可以节U系l资源,提高pȝ的响应速度。在|络环境中这U模式很有用处?
· 修饰模式QDecorator PatternQ:(x)通过修饰模式Q开发h员可以在q行时将特定的功能绑定在对象上?
· 轻量模式QF(tun)lyweight PatternQ:(x)轻量模式通过对象中的一部分数据保存在对象外Q在调用对象中的Ҏ(gu)时再这些数据传回对象。这样做可以减少大量比较单的对象占用的空间?
· 正面模式QF(tun)a?ade PatternQ:(x)正面模式复杂的cdơ结构组lv来,通过一个简单的接口来获得层ơ结构中的数据?
行ؓ(f)cd的模?
行ؓ(f)cd的模式主要是那些处理对象之间通讯的模式,该类型的包括以下模式Q?
· 观测者模式(Observer PatternQ:(x)观测者模式可以在发生变化时将变化通知多个cR?
· 中介模式QMediator PatternQ:(x)中介模式可以通过一个中间类来控制若q个cM间的通讯Qƈ且这些类怺之间不需要了解对方的信息?
· 回忆模式QMemento PatternQ:(x)回忆模式可以在不破坏对象装性的前提下保存和恢复对象的内部状态?
· 职责链模式(Chain of ResponsibilityQ:(x)职责链模式将h传递给一l对象,只有特定的对象才?x)处理该h。这样就q一步削q之间的联pR?
· 命o(h)模式QCommand PatternQ:(x)命o(h)模式请求传递给特定的对象,q样客户端即使在不知道服务器端如何处理请求的情况下也可以发送请求?
· 模板模式QTemplate PatternQ:(x)模板模式提供了对法的抽象定义?
· {略模式QStrategy PatternQ? {略模式定义了一l算法,每个算法都装hQƈ且它们之间可以互换。策略模式ɘq些法在客L(fng)调用它们的时候能够互不媄响地变化?
· 讉K者模式(Visitor PatternQ:(x)讉K者模式通过一个访问类来访问其他类中的数据?
· 状态模式(State PatternQ:(x)状态模式将一个类实例的变量保存在独立的内存空间中?
· q代模式QIterator PatternQ:(x)q代模式在不知道数据的内部表现Ş式的前提下,通过标准的接口来遍历数据集合中的数据?
?SPAN lang=EN-US>Web services作為存取介面的服務導向應用程式架?/SPAN>企業運用a計模式
入C業的pȝ(dng)架構中之?/SPAN>只是的手D?/SPAN>而非的目的?SPAN lang=EN-US>Web services不是只為了Internet而設a,重點在於他是一E用標準技術的分散式應用程式?/SPAN>
Q?/SPAN>Q?SPAN lang=FR>Web servicesQ這一的a計模式大概可分為幾E狀況?/SPAN>
企業直接利用上的Q以軟體I木的方式,加快pȝ(dng)開發的速度Q尤其對g些輔助性的功能Q或一些共通的商業智慧。在上一文章中Q我們也舉了Google的例子, Google Web services可在應用程式中加入此一功能。除此以外,由微軟所提供?SPAN lang=EN-US>.NET My Service也提供了非常多的軟體I木可供使用Q其中最為熟(zhn)的應屬Passport驗證制?/SPAN>
或許(zhn)要問,目前已有很多的流E管理軟體與跨^台整合軟體,位什麼還要有Web servicesQ這是因為這些軟體都是為個別pȝ(dng)間整合所a計Q即使主要大廠所提供的流E管理軟體,包括Microsoft、IBM、BEA{?SPAN style="COLOR: black">Q也須為不同的Adapter付出不同的軟體授Ɗ費Q若採用Web services則不須為不同的系i就要採購另一套整合或程軟體?/SPAN>
]]>