ABP+AdminLTE+Bootstrap Table权限管理系统第四节--仓储,服务,服务接口及依赖注入
在ABP框架中,仓储,服务,这块算是最为重要一块之一了.ABP框架提供了创建和组装模块的基础,一个模块能够依赖于另一个模块,一个程序集可看成一个模块,
一个模块可以通过一个类来定义这个模块,而给定义这个类要继承自已经疯转好的AbpModule..net通过反射来获取这些程序集中的类或者方法
模块的调用往往涉及到先后顺序,如果模块A依赖于模块B,那么模块B要在模块A之前初始化,初始化就相当于注册,如使用IocManager对登记类进行注册,
上面这个方法我们就把MyModule1 注入到MyModule2中了,在调用MyModule2的时候可以初始化MyModule1 .
什么是依赖注入呢?百科是这样说:“依赖注入是一种软件设计模式,一个或多个依赖项(或服务)被注入或通过引用传递到一个依赖对象,并且成为客户端状态的一部分。这种模式把客户端依赖项的创建从它自己的行为中分离出来,允许程序设计成松耦合的,遵循依赖倒置和单一职责的原则。和服务定位器模式相比,它允许客户端知道他们使用的系统查找依赖项。”
不使用依赖注入技术,很难管理依赖项和发布一个结构良好的应用。
假设我们有一个应用程序服务,使用仓储(repository)类插入实体到数据库。在这种情况下,应用程序服务类依赖于仓储(repository)类,如下
UserService使用UserRepository插入Person到数据库。但是这段代码有一些问题:
1,服务层UserService通过接口IUserRepository调用CreatePerson实现新增一个User对象,看似调用了IUserRepository接口,但是实际上还是依赖于仓促层的UserRepository.
2,UserService通过IUserRepository创建对象的时候,实际上new一个UserRepository区实现,这与直接调用UserRepository无差别,IUserRepository失去存在的意义.
3,如果未来我们需要修改UserRepository类,但是UserService依赖于它,这时候,我们需要修改所有依赖UserRepository的类.
4,有了这样的依赖,很难对UserService进行单元测试。
5,与"高内聚低耦合"的的原则背道而驰,这里可以看到服务层与仓储层有依赖.
为了解决这些问题于是就有了下面这个版本.
这就是工厂模式,实际上在abp之前我也经常用这种方式,非常繁琐,搭框架老是出错,UserRepositoryFactory是一个静态类,创建并返回一个IUserRepository
UserService服务不需要直接去创建UserRepository.
这种方法虽然可以,但是依然存在一些问题.
1,UserService依然依赖于UserRepositoryFactory
2,每一个仓储都有写一个工厂,很繁琐.
3,测试性还是不好.
解决办法有几种,包括属性注入,构造函数注入,和依赖注入框架等等.
上面就是abp中构造函数注入与属性输入的完美运用.现在,UserService不知道哪些类实现userRepository以及如何创建它。谁需要使用UserService,首先创建一个IUserServiceUserService并将其传递给构造函数就可以了.
有人可能说userRepository的从属类里面可能存在依赖,依赖注入框架自动化管理依赖关系都已经解决了这些问题.构造函数注入模式是一个完美的提供类的依赖关系的方式。通过这种方式,你不能创建类的实例,而不提供依赖项。它也是一个强大的方式显式地声明是什么类的需求正确地工作。
但是,在某些情况下,该类依赖于另一个类,但也可以没有它。这通常是适用于横切关注点(如日志记录)。一个类可以没有工作日志,但它可以写日志如果你提供一个日志对象。在这种情况下,您可以定义依赖为公共属性,而不是让他们放在构造函数,上面例子中NullLogger.Instance 是一个单例对象,实现了ILogger接口,但实际上什么都没做(不写日志。它实现了ILogger实例,且方法体为空),在我们需要写日志的地方,我们只需要UserService.Logger = new Log4NetLogger();如此,我们就可以写入日志了,如果不写就不调用,因此是一个可选的依赖.
几乎所有的依赖注入框架都支持属性注入模式
ABP的依赖注入基于 Castle Windsor框架。Castle Windsor最成熟的DI框架之一。依赖注入的框架还有好多,如Unity,Ninject,StructureMap,Autofac等,之前我用过Unity其他的几个没有研究过,依赖框架都可以自动解决依赖关系。他们可以创建所有依赖项(递归地依赖和依赖关系)。所以你只需要根据注入模式写类和类构造函数&属性,其他的交给DI框架处理!在良好的应用程序中,类甚至独立于DI框架。整个应用程序只会有几行代码或类,显示的与DI框架交互。
有人说上面这个例子看不出来依赖注入啊,其实这里UserService是继承自IUserService,而IUserService继承自IApplicationService,abp在IApplicationService封装了很多东西,ABP会自动注册它,因为它实现IApplicationService接口(它只是一个空的接口)。它会被注册为transient (每次使用都创建实例)。当你注入(使用构造函数注入)IUserService接口成一个类,UserService对象会被自动创建并传递给构造函数。
命名约定在这里非常重要。例如你可以将名字PersonAppService改为 MyPersonAppService或另一个包含“PersonAppService”后缀的名称,由于IPersonAppService包含这个后缀。但是你可以不遵循PeopleService命名您的服务类。如果你这样做,它将不会为IPersonAppService自动注册(它需要自注册(self-registration)到DI框架,而不是接口),所以,如果你想要你应该手动注册它.
仓储
上一章我们已经定义实体类,和DTOs,在仓储中可以直接调用,仓储是在领域层和数据映射层的中介,使用类似集合的接口来存取领域对象.
接口:
实现:
在例子中IRepository继承自abp已经封装好的IRepository<TEntity>中,在IRepository<TEntity>中已经为我们封装好了许多方法,这就省得我们在为每一个仓储创建不同的方法了,这点很好如下图.
包含了各式各样的方法,如增删查改等方法.还有一些Async的异步方法.GetAll返回IQueryable<T>类型的对象。因此我们可以在调用完这个方法之后进行Linq操作.
现在项目中运用的是EF框架,所以如果ORM框架没有提供Async的仓储方法则它会以同步的方式操作。同样地,举例来说,InsertAsync操作起来和EF的新增是一样的,因为EF会直到单元作业(unit of work)完成之后才会写入新实体到数据库中(DbContext.SaveChanges)。
数据库连接的开启和关闭,在仓储方法中,ABP会自动化的进行连接管理.当仓储方法被调用后,数据库连接会自动开启且启动事务。当仓储方法执行结束并且返回以后,所有的实体变化都会被储存, 事务被提交并且数据库连接被关闭,一切都由ABP自动化的控制。如果仓储方法抛出任何类型的异常,事务会自动地回滚并且数据连接会被关闭。上述所有操作在实现了IRepository接口的仓储类所有公开的方法中都可以被调用。如果仓储方法调用其它仓储方法(即便是不同仓储的方法),它们共享同一个连接和事务。连接会由仓储方法调用链最上层的那个仓储方法所管理。
另外所有的仓储对象都是暂时性的。这就是说,它们是在有需要的时候才会被创建。ABP大量的使用依赖注入,当仓储类需要被注入的时候,新的类实体会由注入容器会自动地创建.
ABP+AdminLTE+Bootstrap Table权限管理系统第四节--仓储,服务,服务接口及依赖注入的更多相关文章
- ABP+AdminLTE+Bootstrap Table权限管理系统第五节--WBEAPI及SwaggerUI
一,Web API ABP的动态WebApi实现了直接对服务层的调用(其实病没有跨过ApiController,只是将ApiController公共化,对于这一点的处理类似于MVC,对服务端的 调用没 ...
- ABP+AdminLTE+Bootstrap Table权限管理系统第六节--abp控制器扩展及json封装
一,控制器AbpController 说完了Swagger ui 我们再来说一下abp对控制器的处理和json的封装. 首先我们定义一个控制器,在新增控制器的时候,控制器会自动继承自AbpContro ...
- ABP+AdminLTE+Bootstrap Table权限管理系统第六节--abp控制器扩展及json封装以及6种处理时间格式化的方法
返回总目录:ABP+AdminLTE+Bootstrap Table权限管理系统一期 一,控制器AbpController 说完了Swagger ui 我们再来说一下abp对控制器的处理和json的封 ...
- ABP+AdminLTE+Bootstrap Table权限管理系统第十一节--bootstrap table之用户管理列表
这张开始bootstrap table,引入项目有两种方法,一种是直接去官网下载 地址:http://bootstrap-table.wenzhixin.net.cn/ 另一种是Nuget引入. 然后 ...
- ABP+AdminLTE+Bootstrap Table权限管理系统第十节--AdminLTE模板菜单处理
上节我们把布局页,也有的临时的菜单,但是菜单不是应该动态加载的么?,所以我们这节来写菜单.首先我们看一下AdminLTE源码里面的菜单以及结构. <aside class="main- ...
- ABP+AdminLTE+Bootstrap Table权限管理系统第七节--登录逻辑及abp封装的Javascript函数库
经过前几节,我们已经解决数据库,模型,DTO,控制器和注入等问题.那么再来看一下登录逻辑.这里算是前面几节的一个初次试水. 首先我们数据库已经有的相应的数据. 模型和DTO已经建好,所以我们直接在服务 ...
- ABP+AdminLTE+Bootstrap Table权限管理系统第十一节--Bootstrap Table用户管理列表以及Module Zero之用户管理
返回总目录:ABP+AdminLTE+Bootstrap Table权限管理系统一期 用户实体 用户实体代表应用的一个用户,它派生自AbpUser类,如下所示: public class User : ...
- ABP+AdminLTE+Bootstrap Table权限管理系统第七节--登录逻辑及几种abp封装的Javascript函数库
返回总目录:ABP+AdminLTE+Bootstrap Table权限管理系统一期 简介 经过前几节,我们已经解决数据库,模型,DTO,控制器和注入等问题.那么再来看一下登录逻辑.这 ...
- ABP+AdminLTE+Bootstrap Table权限管理系统一期
学而时习之,不亦说乎,温顾温知新,可以为师矣. 这也是算是一种学习的方法和态度吧,经常去学习和总结,在博客园看了很多大神的文章,写下一点对于ABP(ABP是“ASP.NET Boilerplat ...
随机推荐
- Linux: bash script
content [toc] bash scripts equivalent bash command to rename a bash variable/command alias fire='fir ...
- 有关ArrayList常用方法的源码解析
我相信几乎所有的同学在大大小小的笔试.面试过程中都会被问及ArrayList与LinkedList之间的异同点.稍有准备的人这些问题早已烂熟于心,前者基于数组实现,后者基于链表实现:前者随机方法速度快 ...
- 【原创】Kafka Consumer多线程实例续篇
在上一篇<Kafka Consumer多线程实例>中我们讨论了KafkaConsumer多线程的两种写法:多KafkaConsumer多线程以及单KafkaConsumer多线程.在第二种 ...
- Python的迭代器与生成器
Python中的生成器和迭代器方便好用,但是平时对生成器和迭代器的特性掌握的不是很到位,今天将这方面的知识整理一下. 迭代器 为了更好的理解迭代器和生成,我们需要简单的回顾一下迭代器协议的概念. 迭代 ...
- c#中的委托和c++中的bind/function对比
在c++中,如果要实现这样一个功能,比如定时器,在指定的时间执行指定的函数,接口可以采用如下的设计 uint64_t addtimer(uint64_t t, std::function<voi ...
- UML中关联(Association)和依赖(Dependency)的区别
原文转自:http://blog.csdn.net/metasearch/article/details/2334853 在UMLCHINA精华区,看到了一些关联和依赖的讨论,似乎越讲越糊涂.我想谈一 ...
- Linux之通配符
前言:学习通配符有点为正则表达式打基础的感觉……之前学python有学过正则表达式,所以这篇博客学起来还是挺快的. 特殊符号 | #管道符,或者(正则) > #输出重定向 >> #输 ...
- IOS开发基础环境搭建
一.目的 本文的目的是windows下IOS开发基础环境搭建做了对应的介绍,大家可根据文档步骤进行mac环境部署: 二.安装虚拟机 下载虚拟机安装文件绿色版,点击如下文件安装 获取安装包: ...
- centos 7 部署Thinksns
因为Thinksns是PHP项目,我们这里部署需要搭建Apache+mysql+php环境. 1.mysql的安装,这里使用yum安装可以解决很多依赖包的问题.由于centos 7 没有自带mysql ...
- gulp 运用 的理解
ugulp.task('build', function() { runSequence('clean', 'copy', ['uglify', 'sass', 'htmlmin'], 'base64 ...