spring碎碎念(二)

Web 程序构架(web application architecture)

一、MVC

MVC构架最早由Trygve Reenskaug在smalltalk工作时提出,最早应用于桌面程序。他将表现层从组件中分离出来。

Model1中MVC组件描述表
组件描述
模型层(Model)view渲染所需要的数据。如订单数据,产品列表之类的。
视图层(View)使用模型层对自身进行渲染的部分。可以是jsp或jsf页面,也可以是一个pdf或xml文件。
控制层(Controller)对用户的行为进行相应的组件。这些行为包括点击提交按钮、点击超链接等。这一层的组件更新model层,以及响应其他的需要行为,例如调用service,放置一个订单。







但Model1的MVC直接应用于Web程序却存在一定困难,因为http协议是一种无状态的协议,保持一个model存在困难。

*因为无状态,所以跨请求同一个model存在困难。php等程序使用mvc存在性能瓶颈问题就是因为没有有效解决这一问题,java中是使用容器的概念解决这一问题的。

于是有了Model2模型,这个模型里改进了controll层,引入了前端controller,其中的一个controller可以将一个请求发送到另外一个controller上。control 层中的一个controller响应一个request,返回一个model,并选择一个view。

model2模式的构架图:



这里面的前端控制器(front controller)就是接受请求的controller。它将把请求委托给适当的controller,当被委托的controller完成请求后,front controller根据返回的数据选择合适的view。在许多情况下,这个前端控制器由 javax.servlet.Servlet servlet来实现(例如 structs 里面的 ActionServlet 和 JSF 里面的 FacesServlet )。在spring mvc 里面,这个front controller 就是 org.springframework.web.servlet.DispatcherServlet;

*其中的一个重要划分原则:View层不负担任何的业务逻辑和数据访问逻辑,就是把model在View中渲染出来,以 html , xml , pdf , json 等形式返回到浏览器。

mvc 结构的 Web 程序的构架图:


mvc 结构的Web程序构架概览:

表现层表现层应该尽可能的薄。它作为一个表现变化的层次。应提供一个可变化的web-前端,甚至仅仅是一个web server 的包装。一个设计良好的server层通过表现层来进行操作。
服务层实际的包含业务逻辑的调用点。service层:提供调用系统的一个粗糙接口;提供事务边界。持久层以及表现层对于这个层来说,是透明的。
数据访问层一个提供数据访问支持的接口,不对上层暴露(透明)。在这一层李,对实际的持久层进行抽象(如:jdbc、JDO、JPA)。注意访问层不提供业务逻辑。





各层之间的通信是通过自上而下的单向调用。也就是说表现层可以调用服务层,但服务层不可以调用表现层,等等。在设计中各层要避免循环依赖,因为循环依赖会造成维护困难。

实际应用中,一个典型的系统在概念上可以切出5个层面,如表现层可以切成web层和用户层两个接口。同时程序应包含领域层(domain layer)。领域层横贯系统各个层次,因为从数据访问层到用户层都需要被访问。

典型的系统分层:

实际系统中举例:

com.apress.bookstore.domain :领域层

com.apress.bookstore.service :服务层

com.apress.bookstore.repository :数据访问层

一个实际系统的结构图



分离关注点:

好处:有助于设计、变更以及测试。

在设计中添加新层的原则:如果一个层对于其他的层依赖太多,那么就引入一个层来和其他的各层交互。如果一个层看起来与其它层始终是一个独立的层,那么我们就要重新考虑将其作为程序的一个切面,在spring中,专门用AOP来处理这个问题。

注意:spring中AOP可以是一个基于类的代理,在这种情况下,spring使用了cglib库。

好了言归正传,说说在spring中的层次划分:

1、领域层

程序中用到的实体类。

2、用户界面层

将service层计算结果渲染传给客户端。例如,对于web程序,传回html文档,对于另外一个web程序,传回xml数据,对于一个客户端,传回pdf文件等。

spring支持如下表现层类型:

1、pdf

2、jsp

3、excel

4、freemarker

5、velocity

6、jasperReports

7、Tiles

8、xml

9、json

用户界面层一般依赖于领域层。在实际使用中,我们常常暴露领域层,并直接渲染领域层的数据,这在大量使用form的情况下尤其常见。对于这一点,有广泛争议,当地应不应该呢,直接访问可以降低系统的复杂度,但不直接访问又可以提供程序的弹性。不过在spring-mvc中,并不提倡我们直接暴露领域层的情况。

Web层:

web层有两个职责:其一是引导用户访问整个应用。其二整合service层http协议(从这点看,web层更像是一个facade,一家之言)。

典型的,web层提供浏览导航的功能,相关的逻辑不能出现在service层和领域层(如web分页中,常常出现一个page对象,这类对象只能放在web层整,不能发在领域层,在设计中常常发现这类错误)。web层的浏览导航功能是通过url来实现的(现在流行restful设计,对良好的url设计很有帮助)。

在设计中,web层应该尽可能的薄,他将用户的请求转化为service层所需要的数据,将处理的结果转化并返回给用户界面。web层中不能包含任何业务逻辑,这是service层干的事儿。

web层中也应该保持cookies,会话 (http session),http头(http head)。管理这类对象的事儿也应该web层来做,不能让他们蔓延到service层中去。例如在service层中管理一个session,肯定设计上就有错误。在设计中注意这一点,才能设计出测试性良好且易于复用的service层。例如,我们通过java消息驱动(jms-driven)去调用另外一个系统,如果另外一个系统包含了session代码,那么几乎就不可用。

对于java开发者来说,servlet、jsp为编写web层提供了很大的方便。

几大框架:spring mvc、struct、tapestry,jsp都对对于mvc模式都提供了支持,但实现上有很大不同。我们可以将其划分为两类:

一是 请求\响应(request\response)类的,如spring mvc 和 struct。二是基于组件(component-base)的,例如tapestry和jsf。请求响应类的框架通过操作javax.servlet.ServletResponse类来实现,所有的servlet API对于这类框架是暴露的。而基于组件的框架则试图隐藏相关的API,给用户提供一个类似于swing的编程界面。

spring mvc 在请求/响应类框架以及基于组件的框架之间保持了一个平衡。他将相关的servlet api隐藏起来,但如果需要的话,也可以很方便的访问到他们。

web层依赖于domain层和service层,有时候,我们需要将一个请求映射为一个domain对象,然后调用service层处理domain对象。在spring mvc 中,可以很方便的讲request映射为一个domain对象。

在spring mvc中,web层通过org.springframework.web.servlet.mvc.Controller接口或者org.srpingframework.stereotype.Controller注解来实现。

在执行Controller开始执行之后,需要有一个org.springframework.web.servlet.ModelAndView类的实例。这个实例组装model(通过org.springframework.ui.ModelMap),向视图返回渲染的结果.这个视图是org.springframework.web.servlet.View接口的实现或者一个view的名称。

注意:不要把@Controller注解用于实现了Controller接口的类,会带来难以预料的后果。

服务层层(service layer):

服务层在程序中是非常重要的层,可以看做是整个应用程序的心脏,为用户提供了系统的各项功能。为系统提供了各项原始功能。

一个service的例子:

package com.apress.prospringmvc.bookstore.service;

import com.apress.prospringmvc.bookstore.domain.Account;

public interface AccountService {
    Account save(Account account);
    Account login(String username, String password) throws AuthenticationException;

    Account getAccount(String username);

}

这个service提供为实现一个用例提供了基本的操作。此外,还可以加入void updateLastLogin(Account account)方法对用户进行更新。

一个service层可以对多种客户端提供服务,为一个系统提供唯一的入口。

数据访问层 (data access layer):

存取数据的层,这个层的实现目的是避免service层与具体的持久化方法相关。

分离出数据访问层的目的:1、服务器层不需要了解持久化的知识(最少知识原则),使数据存储对服务层透明化。2、便于测试。数据访问的速度一般是比较慢的,将这层抽离出来单独测试后,测试服务层就不必使用数据访问层的代码,提高了测试速度。

spring框架为整合data access layer 的实现提供了方便(jdbc,jpa,hibernate,ibatis,jdo)。对于这些数据访问层,spring的相关扩展提供了三个功能:

1、事物管理。

2、资源处理。

3、异常转换。

事物管理甚至支持JTA(分布式或全局式事物管理)。资源管理使我们不必担心连接关闭的问题,由框架自动处理。

相关的实现在org.springframework.jdbc 以及org.springframework.orm包中。

异常转换将数据访问的相关异常转化为org.springframework.dao.DataAccessException,这个异常继承自RuntimeException,是UnChecked的异常。

一个Repository例子:

package com.apress.prospringmvc.bookstore.repository;
import com.apress.prospringmvc.bookstore.domain.Account;
public interface AccountRepository {
Account findByUsername(String username);
Account findById(long id);
Account save(Account account);
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值