Mvc概念:M:model(模型),V:view(视图),C:Controller(控制器)
视图层:用于做数据的展示以及与用户进行交互的一个界面
控制层:能够接收客户端的请求,具体的业务功能还是需要模型组件来完成。
模型层:负责处理业务逻辑以及数据库的交互,承载数据。模型分为多种,有简单的pojo/vo(value object),有业务模型组件,以及数据访问层组件。
模型层类别:
1)pojo/vo:值对象:一个fruit类就是值对象,可以获取相应的属性数据。
2)DAO:数据访问对象:连接数据库并操作相应数据库表单的DAO类
3)BO: 业务对象:业务对象调用相应的数据对象进行一系列操作。
区分业务对象以及数据访问对象:
1)DAO中的方法都是单精度方法或细粒度的方法,一个方法只考虑一个操作,比如添加到数据库就是insert,无需考虑其他操作的影响。
2)BO中的方法属于业务方法,实际的业务是比较复杂的,因此业务方法粒度是比较粗的。service层的业务实现,具体要调用已经定义的dao层接口,封装service层业务逻辑有利于通用的业务逻辑的独立性和重复利用性。程序显得非常简洁。
例如账户注册这个功能属于业务功能,因此注册这个方法属于业务方法。
那么这个业务方法就包含了许多DAO方法,也就是说注册这个业务功能需要通过多个DAO方法的组合进行调用,从而完成注册功能的实现。
注册:
1、检查用户名是否被注册-DAO中的select操作
2、向用户表新增一条新用户记录-DAO中的insert操作
3、向用户表新增一条新用户记录-DAO中的insert操作
4、向系统消息表新增一条新用户记录-DAO中的insert操作
5、向系统日志表新增一条新用户记录-DAO中的insert操作
6、。。。
简单的说DAO层是跟数据库打交道的,service层是处理一些业务流程(不仅仅包括DAO调用操作)。
能够将各个层次强制性分开,这样分开之后就会减少层与层之间的依赖,这样就能最大化的重用代码了。例如MVC层的话多个视图就能共享一个模型,控制器也可以连接不同的模型和视图来完成用户的需求,三个部件相互独立这种设计思想能构造好的松耦合构建。
在原来优化后的水果系统中用户发送请求的处理流程如下图所示:
用户中央控制器接收请求后直接向控制层发出命令,由控制层访问model进行一系列的DAO方法调用获取数据,最后view渲染页面。
当日积月累的使用MVC模式开发之后,会逐渐感受到层与层之间的粘连以及模棱两可的地方存在,这就是service层出现的重要原因。业务逻辑粘连了C层以及M层,因此需要将业务逻辑解耦出来,成为独立的Service层。
假设现在你做这个功能会用到user表和权限表,那么你前台的页面访问action,action再去调用用户模块service,用户模块service判断你是操作user表还是权限表,如果你操作的是user表则service的实现类就去调用userDAO。如果是操作的是权限表则调用权限的DAO。也就是说DAO一定是和数据库的每张表一一对应,而service则不是。
没有service层会产生的问题:
只能在控制层直接实现业务逻辑导致多个控制器无法共享通用的业务逻辑,如果业务逻辑需要升级,则需要直接在源代码上修改兼容,会导致控制器代码不断膨胀复杂。
service层的作用:
service是业务层,是使用一个或者多个模型执行操作的方法。
1:封装一些通用的业务逻辑。
2:与数据层交互。
3:其他请求:如获取远程服务数据。
因此需构建一个业务模型来进行模型的调用,这样控制器能够更专注于模型构建的调用以及视图的处理。
package com.ck.fruit.biz.impl; import com.ck.dao.FruitDAO; import com.ck.fruit.biz.FruitService; import com.ck.fruit.pojo.Fruit; import java.util.List; public class FruitServiceImpl implements FruitService { FruitDAO fruitDAO=null; @Override public ListgetFruitList(String keyword, Integer pageNo) { return fruitDAO.getFruitList(keyword,pageNo); } @Override public void addFruit(Fruit fruit) { fruitDAO.addFruit(fruit); } @Override public Fruit getFruitById(Integer fid) { return fruitDAO.getFruitByFid(fid); } @Override public void delFruit(Integer fid) { fruitDAO.deleteFruit(fid); } @Override public Integer getPageCount(String keyword) { Integer fruitCount=fruitDAO.countNum(keyword); Integer pageCount=(fruitCount+5-1)/5; return pageCount; } @Override public void updateFruit(Fruit fruit) { fruitDAO.updateFruit(fruit); } }
构建上述模型之后在控制器上进行业务调用即可,无需再直接再调用fruitDAO中的方法。
Service层是建立在DAO层之上的,建立了DAO层后才可以建立Service层,而Service层又是在Controller层之下的,因而Service层应该既调用DAO层的接口,又要提供接口给Controller层的类来进行调用,它刚好处于一个中间层的位置。每个模型都有一个Service接口,每个接口分别封装各自的业务处理方法。
采用MVC综合设计模式,MVC本身不属于设计模式的一种,它描述的是一种结构,最终目的达到解耦,解耦说的意思是你更改某一层代码,不会影响我其他层代码,如果你会像spring这样的框架,你会了解面向接口编程,表示层调用控制层,控制层调用业务层,业务层调用数据访问层。初期也许都是new对象去调用下一层,比如你在业务层new一个DAO类的对象,调用DAO类方法访问数据库,这样写是不对的,因为在业务层中是不应该含有具体对象,最多只能有引用,如果有具体对象存在,就耦合了。因此在层与层之间实现解耦很有必要,IOC就能实现此需求。
依赖指的是某某某离不开某某某
在软件系统中,层与层之间是存在依赖的。我们也称之为耦合。
我们系统架构或者是设计的一个原则是: 高内聚低耦合。
层内部的组成应该是高度聚合的,而层与层之间的关系应该是低耦合的,最理想的情况0耦合(就是没有耦合)
控制反转:
1)在之前项目中的ControllerServlet中,我们创建了service对象,FruitService fruitservice=new FruitServiceImpl();
如果出现在Servlet的某个方法中,那么这个fruitservice的作用域(生命周期)就是方法级别。
如果出现在servlet类中,也就是fruitService是一个成员变量,那么这个fruitservice的作用域就是这个servlet实例级别。
2)之后我们在applicationContext.xml中定义了这个fruitService,然后通过解析XML,产生fruitService实例,存放在beanMap中,这个beanMap在beanFactory类中产生其他类的实例。因此,我们转移(改变)了之前的service实例,DAO实例等等他们的生命周期。控制权从程序员转移到了BeanFactory。这个现象称为控制反转。
依赖注入:
1.之前我们在控制层出现代码:FruitService fruitService=new FruitServiceImpl(),那么,控制层与service层存在耦合.
2.之后,我们将代码修改成FruitService fruitService=null,然后在配置文件中配置:
这样就可以通过配置中的属性找到类所需要的依赖并进行实例化,这就是注入依赖。
1.在原先的项目中在控制器以及service层中均存在实例化其它层的类再进行调用,这样层与层之间就存在耦合依赖的情况,因此需要对当前结构进行改进。
2.将需要的类先赋值为null
3.建立一个Beanfactory接口并创建其实现类用来构建一个MAP集合存放xml配置文件中存放的类
xml配置文件,各个bean节点对应各个类,bean中的property节点表示该bean代表的类需要依赖的类,用于后续注入依赖使用。
ClassPathXmlApplicationContext类实现beanFactory接口,将xml配置文件中的类全部通过反射映射入相应集合中:
将xml中所有的类注入集合后就要开始组装bean之间的依赖关系,通过获取bean下的property子节点,来从集合中获取相应的类实例,然后通过反射技术将相应的类中的属性赋值,注入依赖。
最终实现水果系统: