|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
ruby里有这些工具吗?又要简单多少?我没有用过这两门语言,我估计在这些语言力没有很统一的这种标准,或者根本就没有提供。web 择要:
这篇文章将会商如何组合几个出名的框架往做到松耦合的目标,如何创建你的构架,如何让你的各个使用层坚持分歧。富于应战的是:组合这些框架使得每层都以一种松耦合的体例相互相同,而与底层的手艺有关。这篇文章将利用3种盛行的开源框架来会商组合框架的战略
实在,就算用Java制作一个不是很啰嗦的web使用程序,也不是件轻松的事变。当为一个使用程序制作一个构架时有很多事变必要思索。从高层来讲,开辟者必要思索:如何创建用户接口?在那里处置营业逻辑?和如何耐久化使用数据。这三层每层都有它们各自的成绩必要回覆。各个条理应当利用甚么手艺?如何才干把使用程序计划得松耦合和能天真改动?构架同意层的交换不会影响到别的层吗?使用程序如何处置容器级的服务,好比事件处置?
当为你的web使用程序创立一个构架时,必要触及到相称多的成绩。侥幸的是,已有很多开辟者已碰到过这类反复产生的成绩,而且创建了处置这类成绩的框架。一个好框架具有以下几点:加重开辟者处置庞大的成绩的包袱(“不反复创造轮子”);外部界说为可扩大的;有一个壮大的用户群撑持。框架一般可以很好的办理一方面的成绩。但是,你的使用程序有几个层大概都必要它们各自的框架。就如办理你的用户接口(UI)成绩时你就不该该把事件逻辑和耐久化逻辑搀杂出去。比方,你不该该在把持器内里写jdbc代码,使它包括有营业逻辑,这不是把持器应当供应的功效。它应当是轻量级的,代办署理来自用户接口(UI)外的挪用哀求给别的服务于这些哀求的使用层。好的框架天然的构成代码怎样散布的引导。更主要的是,框架加重开辟者重新入手下手写像耐久层如许的代码的疾苦,使他们专注于对客户来讲很主要的使用逻辑。
这篇文章将会商如何组合几个出名的框架往做到松耦合的目标,如何创建你的构架,如何让你的各个使用层坚持分歧。富于应战的是:组合这些框架使得每层都以一种松耦合的体例相互相同,而与底层的手艺有关。这篇文章将利用3种盛行的开源框架来会商组合框架的战略。体现层我们将利用Struts;营业层我们将利用Spring;耐久层利用Hibrenate.你也能够在你的使用程序中交换这些框架中的任何一种而失掉一样的效果。图1展现了当这些框架组合在一同时从高层看是甚么模样。
[img=450style=,193alt=]http://www.alixixi.com/UploadPic/2007-7/200777112522615.gif[/img]
用Struts,Spring,和Hibernate框架构建的概览
使用程序的分层
年夜多半不庞大的web使用都能被分红最少4个各负其责的条理。这些条理是:体现层、耐久层、营业层、范畴模子层。每层在使用程序中都有明白的义务,不该该和别的层搅浑功效。每使用层应当相互自力但要给他们之间放一个通信接口。让我们从审阅各个层入手下手,会商这些层应当供应甚么和不该该供应甚么。
体现层
在一个典范的web使用的一端是体现层。良多Java开辟者也了解Struts所供应的。但是,太罕见的是,他们把像营业逻辑之类的耦合的代码放进了一个org.apache.struts.Action。以是,让我们在像Struts如许一个框架应当供应甚么上获得分歧定见。这儿是Struts卖力的:
・为用户办理哀求和呼应;
・供应一个把持器代办署理挪用营业逻辑和别的下层处置;
・处置从别的层掷出给一个StrutsAction的非常;
・为显现供应一个模子;
・实行用户接口考证。
这儿是一些常常用Struts编写的可是却不该该和Struts体现层相伴的项目:
・间接和数据库通信,好比JDBC挪用;
・营业逻辑和与你的使用程序相干的考证;
・事件办理;
・在体现层中引进这类代码将招致典范耦合和厌恶的保护。
耐久层
在典范web使用的另外一端是耐久层。这一般是使事变敏捷掉控的中央。开辟者低估了构建他们本人的耐久层框架的应战性。一样平常来讲,机构外部本人写的耐久层不但必要大批的开辟工夫,并且还常常短少功效和变得难以把持。有几个开源的“对象-干系映照”框架十分办理成绩。特别是,Hibernate框架为java供应了"对象-干系耐久化"机制和查询服务。Hibernate对那些已熟习了SQL和JDBCAPI的Java开辟者有一个适中的进修曲线。Hibernate耐久对象是基于复杂新式Java对象和Java汇合。别的,利用Hibernate其实不妨害你正在利用的IDE。上面的列表包括了你该写在一个耐久层框架里的代码范例:
查询相干的信息成为对象。Hibernate经由过程一种叫作HQL的面向对象的查询言语大概利用前提表达式API来做这个事变。HQL十分相似于SQL--只是把SQL里的table和columns用Object和它的fields取代。有一些新的公用的HQL言语成份要学;不外,它们简单了解并且文档做得好。HQL是一种利用来查询对象的天然言语,花很小的价值就可以进修它。
保留、更新、删除贮存在数据库中的信息。
像Hibernate如许的初级“对象-干系”映照框架供应对年夜多半支流SQL数据库的撑持,它们撑持“父/子”干系、事件处置、承继和多态。
这儿是一些应当在耐久层里被制止的项目:
营业逻辑应当在你的使用的一个高一些的条理里。耐久层里仅仅同意数据存取操纵。
你不该该垄断久层逻辑和你的体现层逻辑搅在一同。制止像JSPs或基于servlet的类这些体现层组件里的逻辑和数据存取间接通信。经由过程垄断久层逻辑断绝进它本人的层,使用程序变得易于修正而不会影响在别的层的代码。比方:Hebernate可以被别的耐久层框架大概API取代而不会修正在别的任何层的代码。
营业层
在一个典范的web使用程序的两头的组件是营业层或服务层。从编码的视角来看,这个服务层是最简单被无视的一层。不难在用户接口层大概耐久层里找到分布在个中的这类范例的代码。这不是准确的中央,由于这招致了使用程序的紧耦合,如许一来,跟着工夫推移代码将很难保护。幸亏,针对这一成绩有好几种Frameworks存在。在这个范畴两个最盛行的框架是Spring和PicoContainer,它们叫作微容器,你能够不吃力不劳神的把你的对象连在一同。一切这些框架都事情在一个复杂的叫作“依附注进”(也通称“把持反转”)的观点上。这篇文章将着眼于Spring的为指定的设置参数经由过程bean属性的setter注进的利用。Spring也供应了一个构建器注进的庞大情势作为setter注进的一个替换。对象们被一个复杂的XML文件连在一同,这个XML文件含有到像事件办理器、对象工场、包括营业逻辑的服务对象、和数据存取对象这些对象的援用。
这篇文章的前面将用例子来把Spring利用这些观点的办法说得更分明一些。营业层应当卖力上面这些事变:
・处置使用程序的营业逻辑和营业考证;
・办理事件;
・预留和别的层交互的接口;
・办理营业层对象之间的依附;
・增添在体现层和耐久层之间的天真性,使它们互不间接通信;
・从体现层中供应一个高低文给营业层取得营业服务;
・办理从营业逻辑到耐久层的完成。
范畴模子层
最初,由于我们会商的是一个不是很庞大的、基于web的使用程序,我们必要一组能在分歧的层之间挪动的对象。范畴对象层由那些代体现实天下中的营业对象的对象们构成,好比:一份定单、定单项、产物等等。这个层闪开发者中断创建和保护不用要的数据传输对象(大概叫作DTOs),来婚配他们的范畴对象。比方,Hibernate同意你把数据库信息读进范畴对象的一个对象图,如许你能够在毗连断开的情形下把这些数据显现到UI层。那些对象也能被更新和送回到耐久层并在数据库里更新。并且,你不用把对象转化成DTOs,由于DTOs在分歧的使用层间挪动,大概在转换中丧失。这个模子使得Java开辟者天然地以一种面向对象的作风和对象打交道,没有附加的编码。
分离一个复杂的例子
既然我们已从一个高的条理上了解了这些组件,如今就让我们入手下手理论吧。在这个例子中,我们仍是将兼并Struts、Spring、Hibernate框架。每个这些框架在一篇文章中都有太多的细节掩盖到。这篇文章将用一个复杂的例子代码展现如何把它们分离在一同,而不是进进每一个框架的很多细节。示例使用程序将树模一个哀求如何超过每层被服务的。这个示例使用程序的一个用户能保留一个定单到数据库中和检察一个在数据库中存在的定单。进一步的加强可使用户更新或删除一个存在的定单。
由于范畴对象将和每层交互,我们将起首创立它们。这些对象将使我们界说甚么应当被耐久化,甚么营业逻辑应当被供应,和哪一种体现接口应当被计划。然后,我们将设置耐久层和用Hibernate为我们的范畴对象界说“对象-干系”映照。然后,我们将界说和设置我们的营业对象。在有了这些组件后,我们就可以会商用Spring把这些层连在一同。最初,我们将供应一个体现层,它晓得如何和营业服务层交换和晓得如何处置从别的层发生的非常。
范畴对象层
由于这些对象将和一切层交互,这大概是一个入手下手编码的好中央。这个复杂的范畴模子将包含一个代表一份定单的对象和一个代表一个定单项的对象。定单对象将和一组定单项对象有一对多的干系。例子代码在范畴层有两个复杂的对象:
・com.meagle.bo.Order.java:包含一份定单的提要信息;
・com.meagle.bo.OrderLineItem.java:包含一份定单的具体信息;
思索一下为你的对象选择包名,它将反应你的使用程序是如何分层的。比方:复杂使用的范畴对象能够放进com.meagle.bo包。更多专门的范畴对象将放进在com.meagle.bo上面的子包里。营业逻辑在com.meagle.service包里入手下手打包,DAO对象放进com.meagle.service.dao.hibernate包。关于forms和actions的体现类分离放进com.meagle.action和com.meagle.forms包。正确的包定名为你的类供应的功效供应一个分明的辨别,使当妨碍保护时更容易于保护,和当给使用程序增添新的类或包时供应分歧性。
耐久层设置
用Hibernate设置耐久层触及到几个步骤。第一步是举行设置耐久化我们的范畴营业对象。由于我们用于范畴对象耐久化的Hibernate和POJOs一同事情,因而,定单和定单项对象包含的一切的字段的都必要供应getter和setter办法。定单对象将包含像ID、用户名、算计、和定单项如许一些字段的尺度的JavaBean格局的setter和getter办法。定单项对象将一样的用JavaBean的格局为它的字段设置setter和getter办法。
Hibernate在XML文件里映照范畴对象到干系数据库。定单和定单项对象将有两个映照文件来表达这类映照。有像XDoclet如许的工具来匡助这类映照。Hibernate将映照范畴对象到这些文件:
Order.hbm.xml
OrderLineItem.hbm.xml
你能够在WebContent/WEB-INF/classes/com/meagle/bo目次里找到这些天生的文件。设置HibernateSessionFactory使它晓得是在和哪一个数据库通讯,利用哪一个数据源或毗连池,加载哪些耐久对象。SessionFactory供应的Session对象是Java对象和像拔取、保留、更新、删除对象如许一些耐久化功效间的翻译接口。我们将在前面的部分会商Hibernate操纵Session对象必要的SessionFactory设置。
营业层设置
既然我们已有了范畴对象,我们必要有营业服务对象来实行使用逻辑、实行向耐久层的挪用、取得从用户接口层的哀求、处置事件、处置非常。为了将一切这些毗连起来而且易于办理,我们将利用Spring框架的bean办理方面。Spring利用“把持反转”,大概“setter依附注进”来把这些对象连好,这些对象在一个内部的XML文件中被援用。“把持反转”是一个复杂的观点,它同意对象承受别的的在一个高一些的条理被创立的对象。利用这类办法,你的对象从必需创立别的对象中束缚出来并下降对象耦合。
这儿是个不利用IoC的对象创立它的附属对象的例子,这招致紧的对象耦合:
:没有利用IoC的对象构造。对象A创立对象B和C。
这儿是一个利用IoC的例子,它同意对象在一个高一些条理被创立和传进别的的对象,以是别的的对象能间接利用现成的对象・[译者注:别的的对象不用再亲身创立这些要利用的对象]:
:对象利用IoC构造。对象A包括setter办法,它们承受到对象B和C的接口。这也能够用对象A里的承受对象B和C的构建器完成。
创建我们的营业服务对象
我们将在我们的营业对象中利用的setter办法承受的是接口,这些接口同意对象的松懈界说的完成,这些对象将被设置大概注进。在我们这个例子里我们将使我们的营业服务对象承受一个DAO往把持我们的范畴对象的耐久化。当我们在这篇文章的例子中利用Hibernate,我们能够简单的转换到一个分歧的耐久框架的完成,关照Spring利用新的完成的DAO对象。你能分明编程到接口和利用“依附注进”形式是如何宽松耦合你的营业逻辑和你的耐久化机制的。
这儿是营业服务对象的接口,它是一个DAO对象依附的桩。
publicinterfaceIOrderService{
publicabstractOrdersaveNewOrder(Orderorder)
throwsOrderException,
OrderMinimumAmountException;
publicabstractListfindOrderByUser(Stringuser)
throwsOrderException;
publicabstractOrderfindOrderById(intid)
throwsOrderException;
publicabstractvoidsetOrderDAO(IOrderDAOorderDAO);
}
注重下面的代码有一个为DAO对象筹办的setter办法。这儿没有一个getOrderDAO办法由于它不是需要的,由于不太有从表面会见连着的OrderDAO对象的必要。DAO对象将被用来和我们的耐久层相同。我们将用Spring把营业服务对象和DAO对象连在一同。由于我们编码到接口,我们不会紧耦合完成。
下一步是写我们的DAO完成对象。由于Spring有内建的对Hibernate的撑持,这个例子DAO将承继HibernateDaoSupport类,这使得我们简单获得一个到HibernateTemplate类的援用,HibernateTemplate是一个匡助类,它能简化HibernateSession的编码和处置HibernateExceptions。这儿是DAO的接口:
publicinterfaceIOrderDAO{
publicabstractOrderfindOrderById(finalintid);
publicabstractListfindOrdersPlaceByUser(finalStringplacedBy);
publicabstractOrdersaveOrder(finalOrderorder);
}
我们另有两个对象要和我们的营业层连在一同。这包含HibernateSessionFactory和一个TransactionManager对象。这在Spring设置文件里间接完成。Spring供应一个HibernateTransactionManager,它将从工场绑定一个HibernateSession到一个线程来撑持事件。这儿是HibernateSessionFactory和HibernateTransactionManager的Spring设置。
<beanid="mySessionFactory"
class="org.springframework.orm.hibernate.
LocalSessionFactoryBean">
<propertyname="mappingResources">
<list>
<value>
com/meagle/bo/Order.hbm.xml
</value>
<value>
com/meagle/bo/OrderLineItem.hbm.xml
</value>
</list>
</property>
<propertyname="hibernateProperties">
<props>
<propkey="hibernate.dialect">
net.sf.hibernate.dialect.MySQLDialect
</prop>
<propkey="hibernate.show_sql">
false
</prop>
<propkey="hibernate.proxool.xml">
C:/MyWebApps/.../WEB-INF/proxool.xml
</prop>
<propkey="hibernate.proxool.pool_alias">
spring
</prop>
</props>
</property>
</bean>
<!--TransactionmanagerforasingleHibernate
SessionFactory(alternativetoJTA)-->
<beanid="myTransactionManager"
class="org.
springframework.
orm.
hibernate.
HibernateTransactionManager">
<propertyname="sessionFactory">
<reflocal="mySessionFactory"/>
</property>
</bean>
每个对象能被Spring设置里的一个<bean>标志援用。在这个例子里,bean“mySessionFactory”代表一个HibernateSessionFactory,bean“myTransactionManager”代表一个Hibernatetransactionmanager。注重transactionMangerbean有一个叫作sessionFactory的属性元素。HibernateTransactionManager有一个为sessionFactory筹办的setter和getter办法,它们是用来当Spring容器启动时的依附注进。sessionFactory属性援用mySessionFactorybean。这两个对象如今当Spring容器初始化时将被连在一同。这类毗连把你从为援用和创立这些对象而创立singleton对象和工场中束缚出来,这削减了你使用程序中的代码保护。mySessionFactorybean有两个属性元素,它们翻译成为mappingResources和hibernatePropertes筹办的setter办法。一般,假如你在Spring以外利用Hibernate,这个设置将被保留在hibernate.cfg.xml文件中。不论如何,Spring供应了一个便利的体例--在Spring设置文件中兼并Hibernate的设置。
既然我们已设置了我们的容器服务beans和把它们连在了一同,我们必要把我们的营业服务对象和我们的DAO对象连在一同。然后,我们必要把这些对象毗连到事件办理器。
这是在Spring设置文件里的模样:
<!--ORDERSERVICE-->
<beanid="orderService"
class="org.
springframework.
transaction.
interceptor.
TransactionProxyFactoryBean">
<propertyname="transactionManager">
<reflocal="myTransactionManager"/>
</property>
<propertyname="target">
<reflocal="orderTarget"/>
</property>
<propertyname="transactionAttributes">
<props>
<propkey="find*">
PROPAGATION_REQUIRED,readOnly,-OrderException
</prop>
<propkey="save*">
PROPAGATION_REQUIRED,-OrderException
</prop>
</props>
</property>
</bean>
<!--ORDERTARGETPRIMARYBUSINESSOBJECT:
Hibernateimplementation-->
<beanid="orderTarget"
class="com.
meagle.
service.
spring.
OrderServiceSpringImpl">
<propertyname="orderDAO">
<reflocal="orderDAO"/>
</property>
</bean>
<!--ORDERDAOOBJECT-->
<beanid="orderDAO"
class="com.
meagle.
service.
dao.
hibernate.
OrderHibernateDAO">
<propertyname="sessionFactory">
<reflocal="mySessionFactory"/>
</property>
</bean>
是我们已连在一同的工具的一个概览。它展现了每一个对象是如何相干联的和如何被Spring设置进别的对象中。把这幅图和示例使用中的Spring设置文件对照检察它们之间的干系。
:这是Spring如何将在这个设置的基本上拆卸beans。
这个例子利用一个TransactionProxyFactoryBean,它有一个为我们已界说了的事件办理者筹办的setter办法。这是一个有效的对象,它晓得如何处置声明的事件操纵和你的服务对象。你能够经由过程transactionAttributes属性界说事件如何被处置,transactionAttributes属性为办法名界说形式和它们如何介入进一个事件。
TransactionProxyFactoryBean类也有一个为一个target筹办的setter,target将是一个到我们的叫作orderTarget的营业服务对象的援用。orderTargetbean界说利用哪一个营业服务对象并有一个指向setOrderDAO()的属性。orderDAObean将居于这个属性中,orderDAObean是我们的和耐久层交换的DAO对象。
另有一个关于Spring和bean要注重的是bean能以两种形式事情。这两种形式被界说为singleton和prototype。一个bean默许的形式是singleton,意味着一个共享的bean的实例将被办理。这是用于无形态操纵--像一个无形态会话bean将供应的那样。当bean由Spring供应时,prototype形式同意创立bean的新实例。你应该只要在每个用户都必要他们本人的bean的拷贝时才利用prototype形式。
提供一个服务定位器
既然我们已把我们的服务和我们的DAO连起来了,我们必要把我们的服务表露给别的层。一般是一个像利用Struts或Swing如许的用户接口层里的代码来利用这个服务。一个复杂的处置办法是利用一个服务定位器形式的类从一个Spring高低文中前往资本。这也能够靠援用beanID经由过程Spring来间接完成。
这儿是一个在StrutsAction中如何设置一个服务定位器的例子:
publicabstractclassBaseActionextendsAction{
privateIOrderServiceorderService;
publicvoidsetServlet(ActionServlet
actionServlet){
super.setServlet(actionServlet);
ServletContextservletContext=
actionServlet.getServletContext();
WebApplicationContextwac=
WebApplicationContextUtils.
getRequiredWebApplicationContext(
servletContext);
this.orderService=(IOrderService)
wac.getBean("orderService");
}
protectedIOrderServicegetOrderService(){
returnorderService;
}
}
用户接口层设置
示例使用的用户接口层利用Struts框架。这儿我们将会商当为一个使用分层时和Struts相干的部分。让我们从在struts-config.xml文件里反省一个Action设置入手下手。
<actionpath="/SaveNewOrder"
type="com.meagle.action.SaveOrderAction"
name="OrderForm"
scope="request"
validate="true"
input="/NewOrder.jsp">
<display-name>SaveNewOrder</display-name>
<exceptionkey="error.order.save"
path="/NewOrder.jsp"
scope="request"
type="com.meagle.exception.OrderException"/>
<exceptionkey="error.order.not.enough.money"
path="/NewOrder.jsp"
scope="request"
type="com.
meagle.
exception.
OrderMinimumAmountException"/>
<forwardname="success"path="/ViewOrder.jsp"/>
<forwardname="failure"path="/NewOrder.jsp"/>
</action>
SaveNewOrderAction被用来耐久化一个用户从用户接口层提交的定单。这是一个典范的StrutsAction;但是,注重这个action的非常设置。这些Exceptions为我们的营业服务对象也在Spring设置文件中设置了。当这些非常被从营业层掷出我们能在我们的用户接口里得当的处置它们。第一个非常,OrderException,当在耐久层里保留定单对象失利时将被这个action利用。这将引发事件回滚和经由过程营业对象传送把非常传回给Struts层。OrderMinimumAmountException,在营业对象逻辑里的一个事件由于提交的定单达不到最小定单数目而失利也将被处置。然后,事件将回滚和这个非常能被用户接口层得当的处置。
最初一个毗连步骤是使我们的体现层和我们的营业层交互。这已经由过程利用后面会商的服务定位器来完成了。服务层充任一个到我们的营业逻辑和耐久层的接口。这儿是Struts中的SaveNewOrderAction大概如何利用一个服务定位器挪用一个营业办法:
publicActionForwardexecute(
ActionMappingmapping,
ActionFormform,
javax.servlet.http.HttpServletRequestrequest,
javax.servlet.http.HttpServletResponseresponse)
throwsjava.lang.Exception{
OrderFormoForm=(OrderForm)form;
//UsetheformtobuildanOrderobjectthat
//canbesavedinthepersistencelayer.
//Seethefullsourcecodeinthesampleapp.
//Obtainthewiredbusinessserviceobject
//fromtheservicelocatorconfiguration
//inBaseAction.
//Delegatethesavetotheservicelayerand
//furtherupstreamtosavetheOrderobject.
getOrderService().saveNewOrder(order);
oForm.setOrder(order);
ActionMessagesmessages=newActionMessages();
messages.add(
ActionMessages.GLOBAL_MESSAGE,
newActionMessage(
"message.order.saved.successfully"));
saveMessages(request,messages);
returnmapping.findForward("success");
}
结论
这篇文章依照手艺和架构掩盖了很多话题。从中而掏出的次要头脑是如何更好的给你的使用程序分层:用户接口层、耐久逻辑层、和别的任何你必要的使用层。如许能够解耦你的代码,同意增加新的代码组件,使你的使用在未来更容易保护。这里掩盖的手艺能很好的办理这类的成绩。不论如何,利用如许的构架可让你用其他手艺取代如今的层。比方,你大概不想利用Hibernate耐久化。由于你在你的DAO对象中编码到接口,你能如何利用别的的手艺或框架,好比iBATIS,作为一个替换是不言而喻的。大概你大概用分歧于Struts的框架替换你的UI层。改动UI层的完成不会间接影响你的营业逻辑层大概你的耐久层。交换你的耐久层不会影响你的UI逻辑或营业服务层。集成一个web使用实在也不是一件啰嗦的事情,靠解耦你的各使用层和用得当的框架构成它,它能变得更简单处置。
先谈谈我对java的一些认识。我选择java,是因为他语法简单,功能强大,从web,到桌面,到嵌入式,无所不能。但当我进一步了解了java后,感叹,java原来也有许多缺点。 |
|