ï»??xml version="1.0" encoding="utf-8" standalone="yes"?>精品视频www,欧美女优在线,精品视频在线你懂得http://www.aygfsteel.com/hongyunxp/zh-cnMon, 28 Jul 2025 15:55:21 GMTMon, 28 Jul 2025 15:55:21 GMT60用Spring AOP实现开发中松散耦合http://www.aygfsteel.com/hongyunxp/archive/2007/05/20/118699.html徐洪äº?/dc:creator>徐洪äº?/author>Sun, 20 May 2007 08:35:00 GMThttp://www.aygfsteel.com/hongyunxp/archive/2007/05/20/118699.htmlhttp://www.aygfsteel.com/hongyunxp/comments/118699.htmlhttp://www.aygfsteel.com/hongyunxp/archive/2007/05/20/118699.html#Feedback0http://www.aygfsteel.com/hongyunxp/comments/commentRss/118699.htmlhttp://www.aygfsteel.com/hongyunxp/services/trackbacks/118699.html  摘要 面向斚w¢¾~–程åQˆAOPåQ‰æ˜¯é¢å‘对象¾~–程åQˆOOPåQ‰çš„一¿Uæ‰©å±•技术,能够很好的解å†Ïx¨ªåˆ‡å…³æ³¨ç‚¹é—®é¢˜ä»¥åŠç›¸å…³çš„设计难题来实现松散耦合。Spring AOP æ˜?AOP 技术的一¿Uå®žçŽ°ã€‚æœ¬æ–‡ä»‹¾läº†AOP 概念åQŒç„¶åŽè¯¦¾l†è®¨è®ÞZº†å¦‚何利用Spring AOP 开发AOP ½E‹åºåQŒæœ€åŽå±•望了Spring AOP 的前景ã€?br>
  关键�/strong> AOP Spring AOP Java

  引言

  AOPåQˆAspected Oriented ProgrammingåQ‰æ˜¯ä¸€¿Uæ–°å…´çš„¾~–程技术。它可以解决OOP和过½E‹åŒ–æ–ÒŽ³•不能够很好解决的横切åQˆcrosscutåQ‰é—®é¢˜ï¼Œå¦‚:事务、安全、日志等横切å…Ïx³¨ã€‚当未来¾pȝ»Ÿå˜å¾—­‘Šæ¥­‘Šå¤æ‚,横切å…Ïx³¨ç‚¹å°±æˆäؓ一个打问题的时候,AOPž®±å¯ä»¥å¾ˆè½ÀL¾çš„è§£å†Ïx¨ªåˆ‡å…³æ³¨ç‚¹˜q™ä¸ªé—®é¢˜åQŒä‹Éå¾—AOP¾~–ç¨‹æˆäØ“ã€‚Spring 是基于J2EE的轻量çñ”开源开发框æžÓž¼Œå…¶ä¸­Spring AOP¾l„äšg实现了面向方面编½E‹ã€?br>
  AOP 概述

  面向斚w¢¾~–程 (AOP) 提供从另一个角度来考虑½E‹åº¾l“构以完善面向对象编½E‹ï¼ˆOOPåQ‰ã€?面向对象ž®†åº”用程序分解成各个层次的对象,而AOPž®†ç¨‹åºåˆ†è§£æˆå„个斚w¢æˆ–者说å…Ïx³¨ç‚?。这使得可以模块化诸如事务管理等˜q™äº›æ¨ªåˆ‡å¤šä¸ªå¯¹è±¡çš„关注点ã€?

  1、AOP 基本概念

  斚w¢åQˆAspectåQ‰ï¼š 一个关注点的模块化åQŒè¿™ä¸ªå…³æ³¨ç‚¹å®žçŽ°å¯èƒ½å¦å¤–æ¨ªåˆ‡å¤šä¸ªå¯¹è±¡ã€‚äº‹åŠ¡ç®¡ç†æ˜¯J2EE应用中一个很好的横切å…Ïx³¨ç‚¹ä¾‹å­ã€‚方面用Springçš?Advisor或拦截器实现ã€?br>
  ˜qžæŽ¥ç‚¹ï¼ˆJoinpointåQ? ½E‹åºæ‰§è¡Œ˜q‡ç¨‹ä¸­æ˜Ž¼‹®çš„点,如方法的è°?用或特定的异常被抛出ã€?br>
  通知åQˆAdviceåQ? 在特定的˜qžæŽ¥ç‚¹ï¼ŒAOP框架执行的动作。各¿Uç±» 型的通知包括“around”ã€?#8220;before”å’?#8220;throws”通知。通知¾cÕdž‹ž®†åœ¨ä¸‹é¢è®¨è®ºã€‚许多AOP框架 包括Spring都是以拦截器做通知模型åQŒç»´æŠ¤ä¸€ä¸?#8220;围绕”˜qžæŽ¥ç‚¹çš„æ‹¦æˆªå™¨é“¾ã€?br>
  切入点(PointcutåQ? 指定一个通知ž®†è¢«å¼•发的一¾pÕdˆ—˜qžæŽ¥ç‚?的集合。AOP框架必须允许开发者指定切入点åQšä¾‹å¦‚,使用正则表达式ã€?br>
  引入åQˆIntroductionåQ? æ·ÕdŠ æ–ÒŽ³•或字ŒDµåˆ°è¢«é€šçŸ¥çš„ç±»ã€?Spring允许引入新的接口åˆîC“Q何被通知的对象。例如,你可以ä‹É用一个引入ä‹Éä»ÖM½•对象实现 IsModified接口åQŒæ¥½Ž€åŒ–缓存ã€?br>
  目标对象åQˆTarget ObjectåQ? 包含˜qžæŽ¥ç‚¹çš„对象。也被称ä½?被通知或被代理对象ã€?br>
  AOP代理åQˆAOP ProxyåQ? AOP框架创徏的对象,包含通知ã€?在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理ã€?br>
  ¾l‡å…¥åQˆWeavingåQ? ¾l„装斚w¢æ¥åˆ›å»ÞZ¸€ä¸ªè¢«é€šçŸ¥å¯¹è±¡ã€‚这可以在编译时 完成åQˆä¾‹å¦‚ä‹É用AspectJ¾~–译器)åQŒä¹Ÿå¯ä»¥åœ¨è¿è¡Œæ—¶å®Œæˆã€‚Spring和其他纯Java AOPæ¡†æž¶ä¸€æ øP¼Œ 在运行时完成¾l‡å…¥ã€?br>
  Spring AOP 介绍

  Spring的一个关键组件就是AOP框架ã€?Spring IoC容器(BeanFactory å’ŒApplicationContext)òq¶ä¸ä¾èµ–于AOP, ˜q™æ„å‘³ç€å¦‚果你不需要ä‹É用,AOP可以不用åQŒAOP完善了Spring IoCåQŒä‹É之成ä¸ÞZ¸€ä¸ªæœ‰æ•ˆçš„中间件解å†Ïx–¹æ¡ˆã€?br>
  Spring AOP 是Spring 框架的重要组成部分,它实çŽîCº†AOP联盟¾U¦å®šçš„æŽ¥å£ã€‚Spring AOP 是由¾U¯Java开发完成的。Spring AOP 只实çŽîCº†æ–ÒŽ³•¾U§åˆ«çš„连接点åQŒåœ¨J2EE应用中,AOP拦截到方法çñ”的操作已¾lèƒö够。OOP倡导的是åŸÞZºŽsetter/getter 的方法访问,而非直接讉K—®åŸŸï¼Œè€ŒSpring 有èƒö够理ç”׃»…仅提供方法çñ”çš„è¿žæŽ¥ç‚¹ã€‚äØ“äº†ä‹É控制反è{åQˆIoCåQ‰å¾ˆæ–¹ä¾¿çš„ä‹É用到非常健壮、灵‹zȝš„企业服务åQŒåˆ™éœ€è¦Spring AOP 的实现。Spring AOP 在运行时才创建Advice 对象。Spring AOP的优点如下:

  ·å…è®¸å¼€å‘者ä‹É用声明式企业服务åQŒæ¯”如事务服务、安全性服务ã€?br>
  ·å¼€å‘者可以开发满­‘³ä¸šåŠ¡éœ€æ±‚çš„è‡ªå®šä¹‰æ–¹é¢ã€?br>
  ·å¼€å‘Spring AOP Advice 很方便,可以借助代理¾cÕd¿«é€Ÿæ­å»ºSpring AOP 应用ã€?br>
  使用Spring AOP松散耦合

  1、创建通知

  为实现AOPåQŒå¼€å‘者需要开发AOP 通知(Advice)。AOP 通知åQˆAdviceåQ?包含了方面(AspectåQ‰çš„逻辑。当创徏一个Advice 对象的时候,你就¾~–写了实现横切(cross-cuttingåQ‰åŠŸèƒ½ã€?Spring 的连接点是用æ–ÒŽ³•拦截器实现的åQŒè¿™ž®±æ„å‘³ç€ä½ ç¼–写的Spring AOP 通知ž®†åœ¨æ–ÒŽ³•调用的不同点¾l„å…¥˜q›ç¨‹åºä¸­ã€‚由于在调用一个方法时有几个不同的旉™—´ç‚¹ï¼ŒSpring 可以在不同的旉™—´ç‚¹ç»„入进½E‹åºã€‚Spring AOP中,提供了四¿Ué€šçŸ¥çš„æŽ¥å£ï¼š MethodBeforeAdvice 用于在目标方法调用前触发åQ›AfterReturningAdvice 用于在目标方法调用后触发åQ›ThrowsAdvice 用于在目标方法抛出异常时触发åQ›MethodInterceptor 用于实现 Around 通知åQˆAdviceåQ‰ï¼Œåœ¨ç›®æ–ÒŽ³•执行的前后触发ã€?br>
  如果要实现相应功能,则需要实çŽîC¸Š˜q°å¯¹åº”的接口。例如:实现Before 通知åQˆAdviceåQ‰éœ€è¦å®žçŽ°æ–¹æ³?void before(Method method, Object[] args, Object target) åQŒå®žçŽ?After 通知åQˆAdviceåQ?需要实现方æ³?void afterReturning (Method method, Object[] args, Object target)ã€?

  2、在Spring 中定义切入点

  在不能明¼‹®è°ƒç”¨æ–¹æ³•的时候,通知ž®±å¾ˆä¸å®žç”¨ã€‚切入点则可以决定特定的¾c»ï¼Œç‰¹å®šçš„æ–¹æ³•是否匹配特定标准。如果某匚w…åQŒåˆ™é€šçŸ¥ž®†åº”用到此方法上。Spring 切入点允许用很灵‹zÈš„æ–¹å¼ž®†é€šçŸ¥¾l„织˜q›æˆ‘们的¾cÖM¸­ã€‚Spring 中的切入ç‚ÒŽ¡†æž¶çš„æ ¸å¿ƒæ˜¯Pointcut接口åQŒæ­¤æŽ¥å£å…è®¸æˆ‘们定义¾l„入通知中的¾cÕd’Œæ–ÒŽ³•。许多方面是通过一¾pÕdˆ—的通知和切入点¾l„合来定义ã€?br>
  在Spring中,一个advisorž®±æ˜¯ä¸€ä¸ªæ–¹é¢çš„完整的模块化表示。Spring提供了PointcutAdvisor接口把通知和切入点¾l„合成一个对象。Spring中很多内建的切入炚wƒ½æœ‰å¯¹åº”çš„PointcutAdvisoråQŒè¿™ä½¿å¾—你可以很方便在一个地方管理切入点和通知。Spring中的切入点分ä¸ÞZ¸¤¾c»ï¼šé™æ€å’ŒåŠ¨æ€ã€‚å› ä¸ºé™æ€åˆ‡å…¥ç‚¹çš„æ€§èƒ½è¦ä¼˜äºŽåŠ¨æ€åˆ‡å…¥ç‚¹åQŒæ‰€ä»¥ä¼˜å…ˆè€ƒè™‘使用。Spring 为我们提供创建静态切入点很实用的¾c»StaticMethodMatherPointcut。在˜q™ä¸ª¾cÖM¸­åQŒæˆ‘们只需要关心setMappedNameå’ŒsetMappedNamsæ–ÒŽ³•。你可以使用具体的类名,也可以ä‹É用通配½W¦ã€‚如åQšè®¾¾|®mappedNameå±žæ€§äØ“set* 则匹配所有的setæ–ÒŽ³•。Spring˜q˜æä¾›äº†å¦é€šè¿‡æ­£åˆ™è¡¨è¾¾å¼æ¥åˆ›å¾é™æ€åˆ‡å…¥ç‚¹çš„实用类RegexpMethodPointcut。通过使用Perl样式的正则表辑ּæ¥å®šä¹‰ä½ æ„Ÿå…´­‘£çš„æ–ÒŽ³•。当切入炚wœ€è¦è¿è¡Œæ—¶å‚数值来执行通知æ—Óž¼Œ˜q™æ—¶ž®±éœ€è¦ä‹É用动态切入点。Spring提供了一个内建的动态切入点åQšControlFlowPointcutåQŒæ­¤åˆ‡å…¥ç‚¹åŒ¹é…åŸºäºŽå½“前线½E‹çš„调用堆栈。我们可以在只有在当前线½E‹æ‰§è¡Œçš„æ‰§è¡Œæ—¶æ‰¾åˆ°ç‰¹å®šçš„¾cÕd’Œç‰¹å®šçš„æ–¹æ³•才˜q”回true。ä‹Éç”¨åŠ¨æ€åˆ‡å…¥ç‚¹æœ‰å¾ˆå¤§çš„æ€§èƒ½æŸè€—ã€‚å¤§å¤šæ•°çš„åˆ‡å…¥ç‚¹å¯ä»¥é™æ€ç¡®å®šï¼Œæˆ‘ä»¬å¾ˆå°‘æœ‰æœºä¼šåˆ›å»ºåŠ¨æ€åˆ‡å…¥ç‚¹ã€‚äØ“äº†å¢žåŠ å¯åˆ‡å…¥ç‚¹çš„å¯é‡ç”¨æ€§ï¼ŒSpring æä¾›äº†åˆ‡å…¥ç‚¹ä¸Šçš„é›†åˆæ“ä½œâ€”â€”äº¤é›†å’ŒåˆåÆˆã€?br>
  3、用ProxyFactoryBean创徏AOP代理

  ProxyFactoryBeanåQŒå’Œå…¶ä»–Springçš?FactoryBeanå®žçŽ°ä¸€æ øP¼Œå¼•å…¥ä¸€ä¸ªé—´æŽ¥çš„å±‚æ¬¡ã€‚å¦‚æžœä½ å®šä¹‰ä¸€ä¸ªåå­—äØ“myfactoryçš„ProxyFactoryBeanåQ?引用myfactory的对象所看到的不是ProxyFactoryBean 实例本èínåQŒè€Œæ˜¯ç”±å®žçްProxyFactoryBean的类çš?getObject()æ–ÒŽ³•所创徏的对象。这个方法将创徏一个包装了目标对象 çš„AOP代理。ä‹É用ProxyFactoryBean或者其他IoC可知的类来创建AOP代理的最重要的优点之一是IoC可以½Ž¡ç†é€šçŸ¥å’Œåˆ‡å…¥ç‚¹ã€‚这是一个非常的强大的功能,能够实现其他AOP框架很难实现的特定的æ–ÒŽ³•。例如,一个通知本èín可以引用应用对象åQˆé™¤äº†ç›®æ ‡å¯¹è±¡ï¼Œ 它在ä»ÖM½•AOP框架中都可以引用应用对象åQ‰ï¼Œ˜q™å®Œå…¨å¾—益于依赖注入所提供的可插入性。通常åQŒæˆ‘们不需要ProxyFactoryBeançš„å…¨éƒ¨åŠŸèƒ½ï¼Œå› äØ“æˆ‘ä»¬å¸¸å¸¸åªå¯¹ä¸€ä¸ªæ–¹é¢æ„Ÿå…´è¶£åQ?例如åQŒäº‹åŠ¡ç®¡ç†ã€‚å½“æˆ‘ä»¬ä»…ä»…å¯¹ä¸€ä¸ªç‰¹å®šçš„æ–šw¢æ„Ÿå…´­‘£æ—¶åQŒæˆ‘们可以ä‹É用许多便利的工厂来创建AOP代理åQŒå¦‚åQšTransactionProxyFactoryBeanã€?br>
  4、自动代�br>
  在应用较ž®æ—¶åQŒåªæœ‰å¾ˆž®‘类需要被通知的时åQŒProxyFactoryBean 可以很好的工作。当有许多类需要通知的时åQŒæ˜¾½Cºçš„创徏每个代理ž®±æ˜¾å¾—很¾Jçã€‚幸˜qçš„æ˜¯Spring提供了是使用自动通过容器来创å»ÞZ»£ç†ã€‚è¿™æ—Óž¼Œž®±åªéœ€è¦é…¾|®ä¸€ä¸ªBean来做¾Jççš„工作。Spring提供了两个类实现自动代理åQšBeanNameAutoProxyCreatorå’ŒDefaultAdvisorAutoProxyCreator。BeanNameAutoProxyCreator为匹配名字的Bean产生代理åQŒå®ƒå¯ä»¥ä½¿ç”¨åœ¨å°†ä¸€ä¸ªæˆ–è€…å¤šä¸ªæ–¹é¢åº”ç”¨åœ¨å‘½åç›æ€¼¼çš„Bean中。自动代理框架假设代理将要暴露出什么接口。如果目标Bean没有实现ä»ÖM½•接口åQŒè¿™æ—¶å°±ä¼šåŠ¨æ€äñ”生一个子¾c…R€‚而更强大的自动代理是DefaultAdvisorAutoProxyCreatoråQŒä½ æ‰€éœ€è¦åšçš„æ˜¯åœ¨BeanFactory中包含它的配¾|®ã€‚这个类的奇妙之处在于他使用实现了BeanPostProcessor接口。在Bean定义被加载倒Spring容器中后åQŒDefaultAdvisorAutoProxyCreatorž®†æœç´¢ä¸Šä¸‹æ–‡ä¸­çš„AdvisoråQŒæœ€åŽå®ƒž®†Advisor应用到匹配Advisor切入点的Bean中。这个代理只对Advisor起作用,它需要通过Advisor来得到需要通知的Bean。元数据自动代理åQˆMetaData AutoProxyåQ‰ã€‚元数据自动代理配置依赖于源代码属性而不是外部XML配置文äšg。这可以非常方便的ä‹É源代码和AOP元数据组¾l‡åœ¨åŒä¸€ä¸ªåœ°æ–V€‚元数据自动代理最常用的地æ–ÒŽ˜¯ç”¨æ¥å£°æ˜Žäº‹åŠ¡ã€‚Spring提供了很强的框架来通过AOP框架来声明事务。这提供了在EJB使用声明式事务的相同功能ã€?br>
  ¾l“论

  AOP 是面向对象编½E‹çš„æœ‰åŠ›è¡¥å……ã€‚é€šè¿‡æ–šw¢ž®±å¯ä»¥èšåˆåœ¨åº”用中行为åŞ成可重用模块ã€?br>
  通过½E‹åºå¯ä»¥å®žçŽ°æ€Žæ ·å’Œåœ¨ä»€ä¹ˆåœ°æ–ÒŽ¥è°ƒç”¨˜q™äº›è¡Œäؓ。这可以减少代码重复åQŒåƈ使你更加å…Ïx³¨ä¸šåŠ¡é€»è¾‘ã€‚Spring 提供了AOP框架来实现调用方法时加入斚w¢ã€‚在AOP框架中可以很方便的ä‹É用预定义的静态切入点来定义被调用的类和方法。我们需要通过Spring提供的代理类来äñ”生代理对象,可以使用ProxyFactoryBean也可以ä‹É用自动代理。Spring AOP 的编½E‹æ–¹å¼æ¨¡å—化了横向关注点的实玎ͼŒæä¾›äº†ä¸€ä¸ªæ›´å¥½æ›´å¿«çš„软äšg开发方式。在软äšg¾l“构日益扩大åQŒç»“构日益复杂的今天åQŒSpring AOP ž®†ä¼šå‘挥­‘Šæ¥­‘Šé‡è¦çš„作用ã€?


]]>
使用struts+spring+hibernate¾l„装你的web应用架构 http://www.aygfsteel.com/hongyunxp/archive/2007/05/14/117207.html徐洪äº?/dc:creator>徐洪äº?/author>Sun, 13 May 2007 20:32:00 GMThttp://www.aygfsteel.com/hongyunxp/archive/2007/05/14/117207.htmlhttp://www.aygfsteel.com/hongyunxp/comments/117207.htmlhttp://www.aygfsteel.com/hongyunxp/archive/2007/05/14/117207.html#Feedback1http://www.aygfsteel.com/hongyunxp/comments/commentRss/117207.htmlhttp://www.aygfsteel.com/hongyunxp/services/trackbacks/117207.html使用struts+spring+hibernate¾l„装你的web应用架构
      其实åQŒå°±½Ž—用Java建造一个不是很烦琐的web应用åQŒä¹Ÿä¸æ˜¯ä»¶è½»æ„¡š„事情ã€?在构架的一开始就有很多事情要考虑ã€?从高处看åQŒæ‘†åœ¨å¼€å‘者面前有很多问题åQšè¦è€ƒè™‘是怎样建立用户接口åQŸåœ¨å“ªé‡Œå¤„理业务逻辑åQ?怎样持久化的数据ã€?而这三层构架中,每一层都有他们要仔细考虑的ã€?各个层该使用什么技术? 怎样的设计能松散耦合˜q˜èƒ½ç‰|´»æ”¹å˜åQ?怎样替换某个层而不影响整体构架åQŸåº”用程序如何做各种¾U§åˆ«çš„业务处理(比如事务处理åQ‰ï¼Ÿ

      构架一个Web应用需要弄明白好多问题ã€?òq¸è¿çš„æ˜¯åQŒå·²¾læœ‰ä¸å°‘开发者已¾lé‡åˆ°è¿‡˜q™ç±»é—®é¢˜åQŒåƈ且徏立了处理˜q™ç±»é—®é¢˜çš„æ¡†æž¶ã€?一个好框架具备以下几点åQ?减轻开发者处理复杂的问题的负担("不重复发明轮å­?åQ‰ï¼› 内部有良好的扩展åQ?òq¶ä¸”有一个支持它的强大的用户团体ã€?好的构架一般有针对性的处理某一¾c»é—®é¢˜ï¼Œòq¶ä¸”能将它做好(Do One Thing wellåQ‰ã€?然而,你的½E‹åºä¸­æœ‰å‡ ä¸ªå±‚可能需要ä‹É用特定的框架åQŒå·²¾lå®Œæˆçš„UI(用户接口) òq¶ä¸ä»£è¡¨ä½ ä¹Ÿå¯ä»¥æŠŠä½ çš„业务逻辑和持久逻辑偶合åˆîC½ çš„UI部分ã€?举个例子åQ?你不该在一个Controller(控制å™?里面写JDBCä»£ç ä½œäØ“ä½ çš„ä¸šåŠ¡é€»è¾‘åQ?˜q™ä¸æ˜¯æŽ§åˆ¶å™¨åº”该提供的ã€?一个UI 控制器应该委‹z„¡»™å…¶å®ƒ¾l™åœ¨UI范围之外的轻量çñ”¾l„äšgã€?好的框架应该能指å¯ég»£ç å¦‚何分布ã€?更重要的是,框架能把开发者从¾~–码中解攑ևºæ¥ï¼Œä½¿ä»–们能专心于应用程序的逻辑åQˆè¿™å¯¹å®¢æˆäh¥è¯´å¾ˆé‡è¦åQ‰ã€?

      ˜q™ç¯‡æ–‡ç« ž®†è®¨è®ºæ€Žæ ·¾l“合几种著名的框架来使得你的应用½E‹åºåšåˆ°æ‘Ö¼›è€¦åˆã€?
如何建立你的架构åQŒåƈ且怎样让你的各个应用层保持一致。?如何整合框架以便让每个层在以一¿Uæ¾æ•£å¶åˆçš„æ–¹å¼å½¼æ­¤ä½œç”¨è€Œä¸ç”¨ç®¡ä½Žå±‚的技术细节?˜q™å¯¹æˆ‘们来说真是一¿UæŒ‘战ã€?˜q™é‡Œè®¨è®ºä¸€ä¸ªæ•´åˆæ¡†æž¶çš„½{–ç•¥( 使用3 ¿Uå—‹Æ¢è¿Žçš„开源框æž? åQšè¡¨½Cºå±‚我们用StrutsåQ?业务层我们用SpringåQ›è€ŒæŒä¹…层则用Hibernateã€?你也可以用其他FrameWork替换只要能得到同æ ïLš„æ•ˆæžœã€?见图1 åQˆæ¡†æž¶ç»„合示意图åQ?



应用½E‹åºçš„分å±?/span>

大部分的Web应用在职责上臛_°‘能被分成4层ã€?˜q™å››å±‚是åQšpresentationåQˆæ˜qŽÍ¼‰åQŒpersistenceåQˆæŒä¹…)åQŒbusinessåQˆä¸šåŠ¡ï¼‰å’Œdomain modelåQˆåŸŸæ¨¡å—åQ‰ã€‚每个层在处理程序上都应该有一™åÒŽ˜Ž¼‹®çš„è´£ä“Q, 而不应该在功能上与其它层混合åQŒåƈ且每个层要与其它层分开的,但要¾l™ä»–们之间放一个通信接口ã€?我们ž®×ƒ»Žä»‹ç»å„个层开始,讨论一下这些层应该提供什么,不应该提供什么ã€?



表示�The Presentation Layer)

一般来è®ÔŒ¼Œä¸€ä¸ªå…¸åž‹çš„Web应用的的末端应该是表½Cºå±‚ã€?很多Java发者也理解Struts所提供的ã€?象业务逻辑之类的被打包到org.apache.struts.Action.åQ?å› æ­¤åQŒæˆ‘们很赞成使用Struts˜q™æ ·çš„æ¡†æž¶ã€?



下面是Struts所负责的:

* ½Ž¡ç†ç”¨æˆ·çš„请æ±?做出相应的响应ã€?

* 提供一个Controller ,委派调用业务逻辑和其它上层处理�

* 处理异常åQŒæŠ›¾l™Struts Action

* 为显½Cºæä¾›ä¸€ä¸ªæ¨¡åž?

* UI验证�



以下条款åQŒä¸è¯¥åœ¨Struts昄¡¤ºå±‚çš„¾~–码中经常出现ã€?它们与显½Cºå±‚无关的ã€?

* 直接的与数据库通信åQŒä¾‹å¦‚JDBC调用ã€?

* 与你应用½E‹åºç›¸å…³è”的业务逻辑以及校验ã€?

* 事物½Ž¡ç†ã€?

在表½Cºå±‚引入˜q™äº›ä»£ç åQŒåˆ™ä¼šå¸¦æ¥é«˜å¶åˆå’Œéº»çƒ¦çš„¾l´æŠ¤ã€?





持久�The Persistence Layer)

典型的Web应用的另一个末端是持久层。这里通常是程序最å®ÒŽ˜“失控的地斏V€‚开发者æ€ÀL˜¯ä½Žä¼°æž„徏他们自己的持久框架的挑战性。系¾lŸå†…部的持箋层不但需要大量调试时é—ß_¼Œè€Œä¸”˜q˜ç»å¸¸ç¼ºž®‘功能ä‹É之变得难以控åˆÓž¼Œ˜q™æ˜¯æŒä¹…层的通病ã€?˜q˜å¥½æœ‰å‡ ä¸ªORM开源框架很好的解决了这¾c»é—®é¢˜ã€‚尤其是Hibernateã€?Hibernate为java提供了OR持久化机制和查询服务, 它还¾l™å·²¾lç†Ÿæ‚‰SQLå’ŒJDBC API çš„Java开发者一个学习桥梁,他们学习èµäh¥å¾ˆæ–¹ä¾Ñ€?Hibernate的持久对象是åŸÞZºŽPOJOå’ŒJava collections。此外,使用Hibernateòq¶ä¸å¦¨ç¢ä½ æ­£åœ¨ä‹É用的IDEã€?



è¯ïLœ‹ä¸‹é¢çš„æ¡ç›®ï¼Œä½ åœ¨æŒä¹…层编码中需要了解的ã€?

* 查询对象的相关信息的语句ã€?Hibernate通过一个OO查询语言åQˆHQLåQ‰æˆ–者正则表辄¡š„API来完成查询ã€?HQL非常¾cÖM¼¼äºŽSQL-- 只是把SQL里的tableå’Œcolumns用Object和它的fields代替ã€?你需要学习一些新的HQL语言åQ?不管怎样åQŒä»–们容易理解而文档也做的很好ã€?HQL是一¿Uå¯¹è±¡æŸ¥è¯¢çš„自然语言åQŒèŠ±å¾ˆå°çš„ä»£ä»·å°±èƒ½å­¦ä¹ å®ƒã€?

* 如何存储åQŒæ›´æ–ŽÍ¼Œåˆ é™¤æ•°æ®åº“记录ã€?

* 象Hibernate˜q™ç±»çš„高¾U§ORM框架支持大部分主‹¹æ•°æ®åº“åQŒåƈ且他们支æŒ?Parent/child关系åQŒäº‹ç‰©å¤„理,¾l§æ‰¿å’Œå¤šæ€ã€?



业务层(The Business LayeråQ?/span>

一个典型Web应用的中间部分是业务层或者服务层ã€?从编码的视角来看åQŒè¿™å±‚是最å®ÒŽ˜“被忽视的一层ã€?而我们却往往在UI层或持久层周围看到这些业务处理的代码åQŒè¿™å…¶å®žæ˜¯ä¸æ­£ç¡®çš„ï¼Œå› äØ“å®ƒå¯¼è‡´äº†½E‹åºä»£ç çš„紧密偶合,˜q™æ ·ä¸€æ¥ï¼Œéšç€æ—‰™—´æŽ¨ç§»˜q™äº›ä»£ç å¾ˆéš¾¾l´æŠ¤ã€‚幸好,针对˜q™ä¸€é—®é¢˜æœ‰å¥½å‡ ç§Frameworks存在ã€?最受欢˜qŽçš„两个框架是Springå’ŒPicoContainerã€?˜q™äº›ä¸ÞZ¹Ÿè¢«ç§°ä¸ºmicrocontainersåQŒä»–们能让你很好的把对象搭配èµäh¥ã€?˜q™ä¸¤ä¸ªæ¡†æž‰™ƒ½ç€æ‰‹äºŽ‘依赖注射'(dependency injection)(˜q˜æœ‰æˆ‘们知道çš?#8216;控制反è{'Inversion of Control=IoC)˜q™æ ·çš„简单概å¿üc€?˜q™ç¯‡æ–‡ç« ž®†å…³æ³¨äºŽSpring的注ž®„(译注åQšé€šè¿‡ä¸€ä¸ªç»™å®šå‚æ•°çš„Setteræ–ÒŽ³•来构造Bean,有所不同于FactoryåQ? Spring˜q˜æä¾›äº†Setter Injection(type2)åQŒConstructor Injection(type3)½{‰æ–¹å¼ä¾›æˆ‘们选择ã€?Spring把程序中所涉及到包含业务逻辑和Daoçš„Objects——例如transaction management handleråQˆäº‹ç‰©ç®¡ç†æŽ§åˆÓž¼‰ã€Object Factoris(对象工厂)、service objectsåQˆæœåŠ¡ç»„ä»Óž¼‰â€”—都通过XML来配¾|®è”¾p»è“v来ã€?



后面我们会ä‹D个例子来揭示一下Spring 是怎样˜qç”¨˜q™äº›æ¦‚念ã€?

业务层所负责的如下:

* 处理应用½E‹åºçš?业务逻辑和业务校éª?

* ½Ž¡ç†äº‹ç‰©

* å…è®¸ä¸Žå…¶å®ƒå±‚ç›æ€º’作用的接å?

* ½Ž¡ç†ä¸šåС层çñ”别的对象的依赖ã€?

* 在显½Cºå±‚和持久层之间增加了一个灵‹zÈš„æœºåˆ¶åQŒä‹É得他们不直接的联¾pÕdœ¨ä¸€èµ—÷€?

* 通过揭示 从显½Cºå±‚åˆîC¸šåŠ¡å±‚ä¹‹é—´çš„Context来得到business servicesã€?

* ½Ž¡ç†½E‹åºçš„æ‰§è¡Œï¼ˆä»Žä¸šåŠ¡å±‚åˆ°æŒä¹…å±‚åQ‰ã€?





域模块层åQˆThe Domain Model Layer åQ?/span>
既然我们致力于的是一个不是很复杂的Web的应用, 我们需要一个对象集合,让它在不同层之间¿UÕdŠ¨çš„ã€?域模块层由实际需求中的业务对象组æˆ?比如, OrderLineItem , Product½{‰ç­‰ã€?开发者在˜q™å±‚ 不用½Ž¡é‚£äº›DTOsåQŒä»…å…Ïx³¨domain object卛_¯ã€?例如åQŒHibernate允许你将数据库中的信息存攑օ¥å¯¹è±¡åQˆdomain objectsåQ‰ï¼Œ˜q™æ ·ä½ å¯ä»¥åœ¨˜qžæŽ¥æ–­å¼€çš„æƒ…况下把这些数据显½Cºåˆ°UI层ã€?而那些对象也可以˜q”回¾l™æŒ¾l­å±‚åQŒä»Žè€Œåœ¨æ•°æ®åº“里更新ã€?而且åQŒä½ ä¸å¿…把对象è{化成DTOsåQˆè¿™å¯èƒ½ä¼¼çš„它在不同层之间的在传输过½E‹ä¸­ä¸¢å¤±åQ‰ï¼Œ˜q™ä¸ªæ¨¡åž‹ä½¿å¾—Java开发者能很自然运用OOåQŒè€Œä¸éœ€è¦é™„加的¾~–码ã€?

一个简单例�



既然我们已经从全局上理解这些组件ã€?现在ž®Þp®©æˆ‘们开始实践吧ã€?我们˜q˜æ˜¯ç”?StrutsåQŒSpring å’ŒHibernate。这三个框架已经被描˜q°å¤Ÿå¤šäº†åQŒè¿™é‡Œå°±ä¸é‡å¤ä»‹¾läº†ã€?˜q™ç¯‡æ–‡ç« ä¸¾ä¾‹æŒ‡å¯¼ä½ å¦‚何ä‹É用这三个框架整合开å? òq¶å‘你揭½C?一个请求是如何贯穿于各个层的。(从用æˆïLš„加入一个Order到数据库åQŒæ˜¾½Cºï¼›˜q›è€Œæ›´æ–°ã€åˆ é™¤ï¼‰ã€?



从这里可以下载到½E‹åº½E‹åºåŽŸä»£ç ï¼ˆdownloadåQ?

既然每个层是互相作用的,我们ž®±å…ˆæ¥åˆ›å»ºdomain objects。首先,我们要在˜q™äº›Object中要¼‹®å®šé‚£äº›æ˜¯éœ€è¦æŒä¹…化的,哪些是提供给business logicåQŒé‚£äº›æ˜¯æ˜„¡¤ºæŽ¥å£çš„设计ã€?下一步,我们ž®†é…¾|®æˆ‘ä»¬çš„æŒä¹…å±‚åÆˆä¸”å®šä¹‰å¥½Hibernateçš„OR mappings。然后定义好Business Objects。有了这些组成部分之后,我们ž®?使用Spring把这些连接è“v来ã€?最后,我们提供¾l™Spring一个持久层åQŒä»Ž˜q™ä¸ªæŒä¹…层里我们可以知道它是如何与业务逻辑层(business service layeråQ‰é€šä¿¡çš„,以及它是怎样处理其他层抛出的异常的。ã€?



域对象层åQˆDomain Object LayeråQ?/span>


˜q™å±‚是编码的着手点åQŒæˆ‘们的¾~–码ž®×ƒ»Ž˜q™å±‚开始ã€?例子中Order 与OrderItem 是一个One—To—Many的关¾p…R€?下面ž®±æ˜¯Domain Object Layer的两个对象:



· com.meagle.bo.Order.java: 包含了一个Order的概要信æ?

· com.meagle.bo.OrderLineItem.java: 包含了Order的详¾l†ä¿¡æ?

好好考虑怎你的package命名,˜q™ååº”出了你是怎样分层的ã€?例如 domain objects在程序中可能打包在com.meagle.bo内ã€?更详¾l†ä¸€ç‚¹å°†æ‰“包在com. meagle.bo的子目录下面。business logic应该从com.meagle.serice开始打包,而DAO 对象应该位于com.meagle.service.dao.hibernate。反应Formså’ŒActionsçš?持久对象åQˆpresentation classesåQ?应该分别攑֜¨ com.meagle.actionå’Œcom.meagle.forms包ã€?准确的给包命名ä‹Éå¾—ä½ çš„classes很好分割òq¶ä¸”易于¾l´æŠ¤åQŒåƈ且在你添加新的classesæ—Óž¼Œèƒ½ä‹É得程序结构上保持上下一致ã€?

持久层的配置åQˆPersistence Layer ConfigurationåQ?/span>

建立Hibernate的持久层 需要好几个步骤ã€?½W¬ä¸€æ­¥è®©æˆ‘们把BO持久化ã€?既然Hibernate是通过POJO工作的, å› æ­¤Orderå’?OrderLineItem对象需要给所有的fileds 加上getter,setteræ–ÒŽ³•ã€?Hibernate通过XMLæ–‡äšg来映ž®?OR)对象åQŒä»¥ä¸‹ä¸¤ä¸ªxmlæ–‡äšg分别映射了Order å’ŒOrderItem对象。(˜q™é‡Œæœ‰ä¸ªå«XDoclet工具可以自动生成你的XML影射文äšgåQ?

- Order.hbm.xml
- OrderLineItem.hbm.xml

你可以在WebContent/WEB-INF/classes/com/meagle/bo目录下找到这些xmlæ–‡äšg。Hibernateçš?[urlhttp://www.hibernate.org/hib_docs/api/net/sf/hibernate/SessionFactory.html]SessionFactory [/url]是用来告诉程åº?应该与哪个数据库通信åQŒè¯¥ä½¿ç”¨å“ªä¸ª˜qžæŽ¥æ± æˆ–使用了DataSourceåQ?应该加蝲哪些持久对象。è€?a target=_blank rel=nofollow>Session接口是用来完成SelectingåQŒSavingåQŒDeleteå’ŒUpdating˜q™äº›æ“ä½œã€?后面的我们将讲述SessionFactoryå’ŒSession是怎样讄¡½®çš„ã€?

业务层的配置åQˆBusiness Layer ConfigurationåQ?/span>

既然我们已经有了domain objectsåQŒæŽ¥ä¸‹æ¥æˆ‘们ž®Þp¦business service objects了,用他们来执行½E‹åºçš„logic,调用持久层,得到UI层的requests,处理transactionsåQŒåƈ且控制exceptionsã€?ä¸ÞZº†ž®†è¿™äº›è¿žæŽ¥è“væ¥åÆˆä¸”æ˜“äºŽç®¡ç†ï¼Œæˆ‘ä»¬ž®†ä‹É用面向方面的 SpringFrameworkã€?Spring 提供äº?控制倒置åQˆinversion of control 0==IoC)和注ž®„依赖设¾|®ï¼ˆsetter dependency injectionåQ‰è¿™äº›æ–¹å¼ï¼ˆå¯ä¾›é€‰æ‹©åQ‰ï¼Œç”¨XMLæ–‡äšgž®†å¯¹è±¡è¿žæŽ¥è“v来ã€?IoCæ˜¯ä¸€ä¸ªç®€å•æ¦‚å¿µï¼ˆå®ƒå…è®æ€¸€ä¸ªå¯¹è±¡åœ¨ä¸Šå±‚接受其他对象的创建)åQŒç”¨IoC˜q™ç§æ–¹å¼è®©ä½ çš„对象从创徏中释放了出来åQŒé™ä½Žäº†å¶åˆåº¦ã€?




˜q™é‡Œæ˜¯ä¸€ä¸ªæ²¡æœ‰ä‹É用IoC的对象创建的例子åQŒå®ƒæœ‰å¾ˆé«˜å¶åˆåº¦ã€?




�2.没有使用 IoC. A 创徏�B �C

而这里是一个ä‹É用IoC的例子,˜q™ç§æ–¹å¼å…è®¸å¯¹è±¡åœ¨é«˜å±‚å¯ä»¥åˆ›å»ºåÆˆ˜q›å…¥å¦å¤–一个对象,所以这样可以直接被执行ã€?


å›?3. 对象使用äº?IoCã€?A 包含了接受B,Cçš?setteræ–ÒŽ³• , ˜q™åŒæ ¯‚¾¾åˆîCº† ç”±A创徏B,C的目的ã€?/span>

建立我们的业务服务对象(Building Our Business Service ObjectsåQ?


Business Object中的Setteræ–ÒŽ³•接受的是接口åQŒè¿™æ ähˆ‘们可以很松散的定义对象实玎ͼŒç„¶åŽæ³¨å…¥ã€?在我们的案例中,我们ž®†ç”¨ä¸€ä¸ªbusiness service object接收一个DAO,用它来控制domain objects的持久化ã€?ç”׃ºŽåœ¨è¿™ä¸ªä¾‹å­ä¸­ä½¿ç”¨äº†HibernateåQŒæˆ‘们可以很方便的用其他持久框架实现 同时通知Spring 有新的DAO可以使用了ã€?

在面向接口的¾~–程中,你会明白 "注射依赖"模式是怎样松散耦合你的业务逻辑和持久机制的åQšï¼‰ã€?



下面是一个接口business service objectåQŒDAO代码片段åQ?


代码:

public interface IOrderService {

  public abstract Order saveNewOrder(Order order)

    throws OrderException,

           OrderMinimumAmountException;

 

  public abstract List findOrderByUser(

                                     String user)

                           throws OrderException;

 

  public abstract Order findOrderById(int id)

                           throws OrderException;

 

  public abstract void setOrderDAO(

                             IOrderDAO orderDAO);

}

 

注意到这ŒDµä»£ç é‡Œæœ‰ä¸€ä¸?setOrderDaoåQˆï¼‰åQŒå®ƒž®±æ˜¯ä¸€ä¸ªDAO Object讄¡½®æ–ÒŽ³•åQˆæ³¨ž®„器åQ‰ã€?ä½†è¿™é‡ŒåÆˆæ²¡æœ‰ä¸€ä¸ªgetOrderDao的方法,˜q™ä¸å¿…要åQŒå› ä¸ÞZ½ òq¶ä¸ä¼šåœ¨å¤–部讉K—®˜q™ä¸ªorderDao。这个DAO Objectež®†è¢«è°ƒç”¨åQŒå’Œæˆ‘们的persistence layer 通信。我们将用Spring把DAO Object å’?business service object搭配èµäh¥çš„。因为我们是面向接口¾~–ç¨‹çš„ï¼Œæ‰€ä»¥åÆˆä¸éœ€è¦å°†å®žçŽ°¾cȝ´§å¯†çš„耦合在一赗÷€?



接下åŽÀLˆ‘们开始我们的DAO的实现类˜q›è¡Œ¾~–码ã€?既然Spring已经有对Hibernate的支持,那这个例子就直接¾l§æ‰¿HibernateDaoSupport¾cÖMº†åQŒè¿™ä¸ªç±»å¾ˆæœ‰ç”¨ï¼Œæˆ‘们可以参è€?a target=_blank rel=nofollow>HibernateTemplateåQˆå®ƒä¸»è¦æ˜¯é’ˆå¯¹HibernateDaoSupport的一个用法,译注åQšå…·ä½“可以查çœ?a target=_blank rel=nofollow>Srping çš„APIåQ‰ã€?下面是这个DAO接口代码åQ?

代码:
public interface IOrderDAO {
  public abstract Order findOrderById(
                                    final int id);
 
  public abstract List findOrdersPlaceByUser(
                           final String placedBy);
  public abstract Order saveOrder(
                               final Order order);
}


我们仍然要给我们持久层组装很多关联的对象åQŒè¿™é‡ŒåŒ…含了HibernateSessionFactory å’ŒTransactionManagerã€?Spring 提供了一ä¸?HibernateTransactionManageråQŒä»–用线½E‹æ†¾l‘了一个Hibernate SessionåQŒç”¨å®ƒæ¥æ”¯æŒtransactions(è¯ähŸ¥çœ?a target=_blank rel=nofollow>ThreadLocal) ã€?

下面是HibernateSessionFactory å’?HibernateTransactionManager:的配¾|®ï¼š

代码:
<bean id="mySessionFactory"
       class="org.springframework.orm.hibernate.
              LocalSessionFactoryBean">
  <property name="mappingResources">
    <list>
      <value>
        com/meagle/bo/Order.hbm.xml
      </value>
      <value>
        com/meagle/bo/OrderLineItem.hbm.xml
      </value>
    </list>
  </property>
  <property name="hibernateProperties">
    <props>
      <prop key="hibernate.dialect">
        net.sf.hibernate.dialect.MySQLDialect
      </prop>
      <prop key="hibernate.show_sql">
        false
      </prop>
      <prop key="hibernate.proxool.xml">
        C:/MyWebApps/.../WEB-INF/proxool.xml
      </prop>
      <prop key="hibernate.proxool.pool_alias">
          spring
      </prop>
    </props>
  </property>
</bean>
 
<!-- Transaction manager for a single Hibernate
SessionFactory (alternative to JTA) -->
<bean id="myTransactionManager"
         class="org.
                springframework.
                orm.
                hibernate.
                HibernateTransactionManager">
  <property name="sessionFactory">
    <ref local="mySessionFactory"/>
  </property>
  </bean>



可以看出åQšæ¯ä¸ªå¯¹è±¡éƒ½å¯ä»¥åœ¨Spring 配置信息中用<bean>标签引用。在˜q™é‡ŒåQŒmySessionFactory引用了HibernateSessionFactoryåQŒè€ŒmyTransactionManager引用了HibernateTransactionManageã€?注意代码中myTransactionManger Bean有个sessionFactory属性ã€?HibernateTransactionManager有个sessionFactory setter å’?getteræ–ÒŽ³•åQŒè¿™æ˜¯ç”¨æ¥åœ¨Spring启动的时候实çŽ?依赖注入" åQˆdependency injectionåQ‰çš„ã€?在sessionFactory 属性里 引用mySessionFactory。这两个对象在Spring容器初始化后ž®Þp¢«¾l„装了è“v来了ã€?˜q™æ ·çš„æ­é…è®©ä½ ä»Ž 单例åQˆsingleton objectsåQ‰å’Œå·¥åŽ‚åQˆfactoriesåQ‰ä¸­è§£æ”¾äº†å‡ºæ¥ï¼Œé™ä½Žäº†ä»£ç çš„¾l´æŠ¤ä»£ä­hã€?mySessionFactory.的两个属性,分别是用来注入mappingResources å’?hibernatePropertes的。通常åQŒå¦‚果你在Spring之外使用Hibernate,˜q™æ ·çš„设¾|®åº”该放在hibernate.cfg.xml中的ã€?不管怎样,Spring提供了一个便æïLš„æ–¹å¼-----在Springå†…éƒ¨é…ç½®ä¸­åÆˆå…¥äº†Hibernate的配¾|®ã€?如果要得到更多的信息åQŒå¯ä»¥æŸ¥é˜…Spring APIã€?





既然我们已经¾l„装配置好了Service BeansåQŒå°±éœ€è¦æŠŠBusiness Service Objectå’?DAO也组装è“v来,òq¶æŠŠ˜q™äº›å¯¹è±¡é…åˆ°ä¸€ä¸ªäº‹åŠ¡ç®¡ç†å™¨åQˆtransaction manageråQ‰é‡Œã€?



在Spring中的配置信息åQ?
代码:

<!-- ORDER SERVICE -->
<bean id="orderService"
  class="org.
         springframework.
         transaction.
         interceptor.
         TransactionProxyFactoryBean">
  <property name="transactionManager">
    <ref local="myTransactionManager"/>
  </property>
  <property name="target">
    <ref local="orderTarget"/>
  </property>
  <property name="transactionAttributes">
    <props>
      <prop key="find*">
     PROPAGATION_REQUIRED,readOnly,-OrderException
      </prop>
      <prop key="save*">
     PROPAGATION_REQUIRED,-OrderException
      </prop>
    </props>
  </property>
</bean>
 
<!-- ORDER TARGET PRIMARY BUSINESS OBJECT:
Hibernate implementation -->
<bean id="orderTarget"
         class="com.
                meagle.
                service.
                spring.
                OrderServiceSpringImpl">
  <property name="orderDAO">
    <ref local="orderDAO"/>
  </property>
</bean>
 
<!-- ORDER DAO OBJECT -->
<bean id="orderDAO"
         class="com.
                meagle.
                service.
                dao.
                hibernate.
                OrderHibernateDAO">
  <property name="sessionFactory">
    <ref local="mySessionFactory"/>
  </property>
</bean>




å›? 是我们对象搭建的一个提¾UŒÓ€?从中可以看出åQŒæ¯ä¸ªå¯¹è±¡éƒ½è”系着SpringåQŒåƈ且能通过Spring注入到其他对象。把它与Spring的配¾|®æ–‡ä»¶æ¯”较,观察他们之间的关¾p?



å›?4. Springž®±æ˜¯˜q™æ ·åŸÞZºŽé…ç½®æ–‡äšgåQŒå°†å„个Bean搭徏在一赗÷€?/span>

˜q™ä¸ªä¾‹å­ä½¿ç”¨ä¸€ä¸ªTransactionProxyFactoryBeanåQŒå®ƒå®šä¹‰äº†ä¸€ä¸ªsetTransactionManager()ã€?˜q™å¯¹è±¡å¾ˆæœ‰ç”¨åQŒä»–能很方便的处理你ç”Ïx˜Žçš„事物还有Service Objectã€?你可以通过transactionAttributes属性来定义怎样处理ã€?想知道更多还是参考TransactionAttributeEditor吧ã€?

TransactionProxyFactoryBean ˜q˜æœ‰ä¸ªsetter. ˜q™ä¼šè¢«æˆ‘ä»?Business service objectåQˆorderTargetåQ‰å¼•用, orderTarget定义äº?业务服务层,òq¶ä¸”它还有个属性,由setOrderDAO()引用。这个属æ€?



Spring å’ŒBean 的还有一点要注意的: bean可以以用两种方式创造ã€?˜q™äº›éƒ½åœ¨å•例模式åQˆSingtonåQ‰å’ŒåŽŸåž‹æ¨¡å¼åQˆpropotypeåQ‰ä¸­å®šä¹‰äº†ã€?默认的方式是singleton,˜q™æ„å‘³ç€å…׃ín的实例将被束¾~šã€?而原形模式是在Spring用到bean的时候允许新建实例的。当每个用户需要得åˆîC»–们自己Beançš„Copyæ—Óž¼Œä½ åº”该仅使用prototype模式。(更多的请参考设计模式中的单例模式和原åŞ模式åQ?

提供一个服务定位器åQˆProviding a Service LocatoråQ?/span>
既然我们已经ž®†æˆ‘们的Sericeså’ŒDAO搭配èµäh¥äº†ã€‚我们需要把我们的Service昄¡¤ºåˆ°å…¶ä»–层ã€?˜q™ä¸ªé€šå¸¸æ˜¯åœ¨Struts或者Swing˜q™å±‚里编码。一个简单方法就是用 服务定位器返回给Spring context 。当ç„Óž¼Œå¯ä»¥é€šè¿‡ç›´æŽ¥è°ƒç”¨Spring中的Bean来做ã€?

下面是一个Struts Actin 中的服务定位器的一个例子�
代码:

public abstract class BaseAction extends Action {
 
  private IOrderService orderService;
 
  public void setServlet(ActionServlet
                                 actionServlet) {
    super.setServlet(actionServlet);
    ServletContext servletContext =
               actionServlet.getServletContext();
 
    WebApplicationContext wac =
      WebApplicationContextUtils.
         getRequiredWebApplicationContext(
                                 servletContext);
 
      this.orderService = (IOrderService)
                     wac.getBean("orderService");
  }
 
  protected IOrderService getOrderService() {
    return orderService;
  }
}
 

UI 层配¾|?åQˆUI Layer ConfigurationåQ?/span>

˜q™ä¸ªä¾‹å­é‡ŒUIå±?使用了Struts framework. ˜q™é‡Œæˆ‘们要讲˜qîC¸€ä¸‹åœ¨¾l™ç¨‹åºåˆ†å±‚的时候, 哪些是和Struts部分的。我们就从一个Struts-config.xmlæ–‡äšg中的Action的配¾|®ä¿¡æ¯å¼€å§‹å§ã€?
代码:

struts-config.xml file.

<action path="/SaveNewOrder"
    type="com.meagle.action.SaveOrderAction"
    name="OrderForm"
    scope="request"
    validate="true"
    input="/NewOrder.jsp">
  <display-name>Save New Order</display-name>
  <exception key="error.order.save"
    path="/NewOrder.jsp"
    scope="request"
    type="com.meagle.exception.OrderException"/>
  <exception key="error.order.not.enough.money"
    path="/NewOrder.jsp"
    scope="request"
    type="com.
          meagle.
          exception.
          OrderMinimumAmountException"/>
  <forward name="success" path="/ViewOrder.jsp"/>
  <forward name="failure" path="/NewOrder.jsp"/>
</action>

SaveNewOrder ˜q™ä¸ªAction是用来持久化UI层里的表单提交过来Order的。这是Struts中一个很典型的Action; 注意观察˜q™ä¸ªAction中exception配置åQŒè¿™äº›Exceptions也在Spring 配置文äšg(applicationContext-hibernate.xml)中配¾|®äº†åQˆå°±åœ?business service object çš„transactionAttributes属性里åQ‰ã€?当异常在业务层被被抛出时åQŒæˆ‘们可以控制他们,òq‰™€‚当的显½Cºç»™UI层ã€?

½W¬ä¸€ä¸ªå¼‚常,OrderException,在持久层保存order对象å¤ÞpÓ|的时候被触发。这ž®†å¯¼è‡´äº‹ç‰©å›žæ»šåƈ且通过BO把异常回传到Struts˜q™ä¸€å±‚ã€?

½W¬äºŒä¸ªå¼‚常,OrderMinimumAmountException也同½W¬ä¸€ä¸ªä¸€æ —÷€?





搭配整和的最后一æ­?通过是让你显½Cºå±‚和业务层相结合。这个已¾lè¢«æœåŠ¡å®šä½å™¨ï¼ˆservice locatoråQ‰å®žçŽîCº†åQˆå‰é¢è®¨è®ø™¿‡äº†ï¼‰åQ?˜q™é‡ŒæœåŠ¡å±‚ä½œä¸ÞZ¸€ä¸ªæŽ¥å£æä¾›ç»™æˆ‘们的业务逻辑和持久层ã€?



SaveNewOrder Action 在Struts中用一个服务定位器åQˆservice locatoråQ‰æ¥è°ƒç”¨æ‰§è¡Œä¸šåŠ¡æ–ÒŽ³•çš„ã€?æ–ÒŽ³•代码如下åQ?



代码:
public ActionForward execute(

  ActionMapping mapping,

  ActionForm form,

  javax.servlet.http.HttpServletRequest request,

  javax.servlet.http.HttpServletResponse response)

  throws java.lang.Exception {

 

  OrderForm oForm = (OrderForm) form;

 

  // Use the form to build an Order object that

  // can be saved in the persistence layer.

  // See the full source code in the sample app.

 

  // Obtain the wired business service object

  // from the service locator configuration

  // in BaseAction.

  // Delegate the save to the service layer and

  // further upstream to save the Order object.

  getOrderService().saveNewOrder(order);

 

  oForm.setOrder(order);

 

  ActionMessages messages = new ActionMessages();

  messages.add(

      ActionMessages.GLOBAL_MESSAGE,

            new ActionMessage(

      "message.order.saved.successfully"));

 

  saveMessages(request, messages);

 

  return mapping.findForward("success");

}


æ€È»“

˜q™ç¯‡æ–‡ç« åœ¨æŠ€æœ¯å’Œæž„æž¶æ–šw¢æŽ©ç›–了很多低层的基础信息åQ?文章的主要的意图在于让你意识到如何给你应用程序分层ã€?分层可以"è§£è€?你的代码——允许新的组件被æ·ÕdŠ ˜q›æ¥åQŒè€Œä¸”让你的代码易于维护ã€?˜q™é‡Œç”¨åˆ°çš„æŠ€æœ¯åªæ˜¯ä¸“注于æŠ?解偶"做好ã€?不管怎样åQŒä‹É用这æ ïLš„æž„架可以让你用其他技术代替现在的层ã€?例如åQŒä½ å¯èƒ½ä¸ä‹É用Hibernate实现持久化。既然你在DAO中面向接口的¾~–程的,所以你完全可以用iBATIS来代æ›Ñ€‚或者,你也可能想用Struts外的其他的技术或者框架替换现在的UI层(转换久层åQŒå®žçް层òq¶ä¸åº”该直接影响åˆîC½ çš„业务逻辑和业务服务层åQ‰ã€?用适当的框架搭å»ÞZ½ çš„Web应用åQŒå…¶å®žä¹Ÿä¸æ˜¯ä¸€ä»¶çƒ¦ççš„工作åQŒæ›´ä¸»è¦çš„æ˜¯å®?è§£è€?了你½E‹åºä¸­çš„各个层ã€?





后记åQ?

看完˜q™ç¯‡æ–‡ç« åŽï¼Œåªæ˜¯è§‰å¾—很喜‹Æ¢ï¼ŒäºŽæ˜¯ž®Þq¿»è¯‘了åQŒå½“然同时也准备着挨大家扔来的鸡蛋åQšï¼‰ã€?

˜q™ç¯‡æ–‡ç« é‡Œåƈ没有太多的技术细节,和详¾l†çš„æ­¥éª¤ã€‚如果你从未使用˜q‡è¿™äº›æ¡†æž¶è€Œåœ¨˜qè¡Œå®žä¾‹½E‹åºé‡ä¸Šå›°éš¾çš„话åQŒå¯ä»¥åˆ°CSDN论坛Java Open Source版发è´ß_¼Œæˆ‘一定会详细解答的(啊哦åQŒè¿™ä¸ç®—做广告吧åQŸï¼‰åQ?

文章是从一个构架的角度讲述了如何搭配现有的开源框架进行分层, 有太多的术语我都不知道怎么表达åQŒè€Œä¸”可能有很多语句存在错误。如果媄响了你的阅读åQŒè¯·ä½ ç›´æŽ¥ç‚¹åŽŸæ–‡åœ°å€åQŒæˆ‘同时也象你说声抱歉ã€?



作者简介:Mark Eagle 高çñ”软äšg工程师,亚特兰大ã€?
¾˜?译:Totodo,软äšg工程å¸?





参考:

StrutsåQšhttp://jakarta.apache.org/struts/index.html

Spring: http://www.springframework.org

Hibernate: http://www.hibernate.org

http://www.hibernate.org.cn

关于控制反è{IOC和依赖注ž®„:http://www.martinfowler.com/articles/injection.html

原文:

http://www.onjava.com/pub/a/onjava/2004/04/07/wiringwebapps.html?page=1
http://www.onjava.com/pub/a/onjava/2004/04/07/wiringwebapps.html?page=2
http://www.onjava.com/pub/a/onjava/2004/04/07/wiringwebapps.html?page=3
http://www.onjava.com/pub/a/onjava/2004/04/07/wiringwebapps.html?page=4


]]>
Ö÷Õ¾Ö©Öë³ØÄ£°å£º °¢Â³¿Æ¶ûÇ߯ì| ´óÓàÏØ| ÄáÄ¾ÏØ| ¸ùºÓÊÐ| ÅìºþÏØ| ±Ï½ÚÊÐ| ÎäÉ½ÏØ| ÇìÔÆÏØ| ̨±±ÏØ| ¸§Ë³ÏØ| ¶«ÖÁÏØ| ºâÉ½ÏØ| ÄÏ·áÏØ| ÆîÑôÏØ| ÁúÑÒÊÐ| ÈýÃÅÏ¿ÊÐ| Ç±É½ÏØ| Á¬³ÇÏØ| ÉÛÎäÊÐ| ³¯ÑôÏØ| °Ý³ÇÏØ| ̨ÖÐÏØ| ÑŰ²ÊÐ| ȪÖÝÊÐ| ÓñÌïÏØ| μÄÏÊÐ| ÓÀ¼ªÏØ| ÄþÏÄ| ÖñÉ½ÏØ| ¹ÉƱ| ÌÆºÓÏØ| ½ÌÓý| ÷ºÓ¿ÚÊÐ| ¾°ºéÊÐ| ÓÀÇåÏØ| Í©ÏçÊÐ| ³²ºþÊÐ| ÉϺ¼ÏØ| ÏÌ·áÏØ| ÑôÎ÷ÏØ| ÕÑͨÊÐ|