Abp太重了?轻量化Abp框架
在进行框架的选型时,经常会听到“***框架太重了”之类的声音,比如“Abp太重了,不适合我们...”。事实上,Abp框架真的很重吗?
框架的“轻”和“重”,我没有在网上找到明确的定义,通过阅读一些技术博客,大致可以把框架的“轻”和“重”通过以下几个方面进行区分:
- 所依赖程序集的数量
- 所实现的功能的多少
- 上手难度及易用性
“轻量级”的框架,大概指的是一个程序集依赖少且程序集文件小、功能虽少但足够满足需求、上手容易使用简单的框架;“重量级”的框架,大概指的是一个程序集依赖多且程序集文件大、功能丰富但大多数用不到、上手困难且使用困难的框架。
这篇文章将从上述几个方面来探索Abp是一个“轻量级”还是“重量级”的框架。
最小依赖
Abp开发了一些启动模板来为我们生成项目。启动模板采用了领域驱动设计的分层方案来建立项目层级,包括了展示层、应用层、领域层与基础设施层。

我们通常都会通过Abp CLI或Abp.io来创建类似上图架构的项目。Abp为我们生成的项目,减少了我们初始化项目的工作量,开箱即用,因此将我们可能会使用的Nuget包预先引入到我们的项目中,也就给我们一种依赖项太多的感觉。

从架构设计上来讲,模块化是Abp的核心;而从技术角度来看,依赖注入则是Abp实现众多功能的一个主要手段。只要了解Abp的模块化和依赖注入,我们就能够基于Abp框架来进行项目开发。
接下来将创建一个原生的ASP.NET Core Web API项目,围绕模块化和依赖注入两个核心概念,来展示如何以最小依赖的方式使用Abp。
- 通过VS或者dotNet cli新建一个原生的
ASP.NET Core Web API项目,命名为LightweightAbp; - 安装Nuget包
Volo.Abp.Autofac和Volo.Abp.AspNetCore.Mvc; - 将项目进行模块化:在项目根目录新建一个Abp模块代码文件
LightweightAbpModule.cs,并复制以下代码:
[DependsOn(
typeof(AbpAutofacModule),
typeof(AbpAspNetCoreMvcModule))]
public class LightweightAbpModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
}
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
}
}
- 将
Startup中的代码调整到LightweightAbpModule中,代码如下:
[DependsOn(
typeof(AbpAutofacModule),
typeof(AbpAspNetCoreMvcModule))]
public class LightweightAbpModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddControllers();
context.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "LightweightAbp", Version = "v1" });
});
}
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
var env = context.GetEnvironment();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "LightweightAbp v1"));
}
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
- 更改
Startup中的代码以使用Abp的模块化系统:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddApplication<LightweightAbpModule>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
{
app.InitializeApplication();
}
}
- 更改
Program的CreateHostBuilder方法以使用Abp的依赖注入系统(基于Autofac):
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.UseAutofac();
- 将项目生成的
WeatherForecastController基类ControllerBase更改为AbpController。 - 按
F5运行。
至此项目的创建完成了。可以看到,仅仅依赖了Volo.Abp.Autofac和Volo.Abp.AspNetCore.Mvc两个Nuget包,即可利用Abp进行开发。若从所依赖Nuget包数量来评估框架的“轻”和“重”,那么Abp不可谓不轻。
功能按需使用
得益于模块化设计,Abp将其所能提供的功能,划分并封装到了不同的模块中。要想使用Abp提供的某一功能,只需引入相关的Nuget包并依赖(DependsOn)模块即可。
数据访问
要想实现数据访问功能,首先我们需要定义Entity、DbContext并配置数据库支持。在Abp的层次架构中,Entity、Repository属于领域层,Service属于应用层,DbContext则属于EntityFramework Core模块,因此我们按需引入所需模块即可。
- 安装Nuget包
Volo.Abp.Ddd.Application、Volo.Abp.Ddd.Domain和Volo.Abp.EntityFrameworkCore.Sqlite; - 在
LightweightAbpModule类中配置DependsOn特性,将AbpDddApplicationModule、AbpDddDomainModule和AbpEntityFrameworkCoreSqliteModule模块依赖到我们的项目模块中。
[DependsOn(
typeof(AbpAutofacModule),
typeof(AbpAspNetCoreMvcModule),
typeof(AbpDddApplicationModule),
typeof(AbpDddDomainModule),
typeof(AbpEntityFrameworkCoreSqliteModule))]
public class LightweightAbpModule : AbpModule
{ ... }
- 然后创建实体
Book及数据库上下文LightweightAbpDbContext:
using System;
using Volo.Abp.Domain.Entities;
namespace LightweightAbp
{
public class Book : Entity<Guid>
{
public string Name { get; set; }
}
}
[ConnectionStringName("Default")]
public class LightweightAbpDbContext : AbpDbContext<LightweightAbpDbContext>
{
public LightweightAbpDbContext(DbContextOptions<LightweightAbpDbContext> options)
: base(options)
{ }
public DbSet<Book> Books { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<Book>(b =>
{
b.ToTable(nameof(Books));
});
}
}
- 在
LightweightAbpModule的ConfigureServices方法中配置数据库访问:
public override void ConfigureServices(ServiceConfigurationContext context)
{
...
context.Services.AddAbpDbContext<LightweightAbpDbContext>(options =>
{
options.AddDefaultRepositories(includeAllEntities: true);
});
Configure<AbpDbContextOptions>(options =>
{
options.UseSqlite();
});
}
- 在
appsettings.json中配置数据库连接字符串
{
...
"ConnectionStrings": {
"Default": "Data Source=LightweightAbp.db"
}
}
- 安装Nuget包"Microsoft.EntityFrameworkCore.Tools",并在在项目根目录下打开命令行工具,依次执行以下命令进行数据迁移和数据库更新:
dotnet ef migrations add InitialCreate
dotnet ef database update
- 创建
IBookAppService及BookAppService:
public interface IBookAppService
{
Task CreateAsync(string name);
}
public class BookAppService : ApplicationService, IBookAppService
{
public IRepository<Book, Guid> Repository => LazyServiceProvider.LazyGetRequiredService<IRepository<Book, Guid>>();
public async Task<string> CreateAsync(string name)
{
var book = await Repository.InsertAsync(new Book()
{
Name = name
});
return book.Name;
}
}
- 在文件夹Controllers中创建
BookController:
[ApiController]
[Route("[controller]")]
public class BookController : AbpController
{
private readonly IBookAppService _service;
public BookController(IBookAppService service)
{
_service = service;
}
[HttpGet]
public Task<string> CreateAsync(string name)
{
return _service.CreateAsync(name);
}
}
- F5以调试模式运行即可在Swagger页面上插入数据:

这里我们实现了简单的数据插入。可以看到,项目中并没有使用复杂架构和复杂的领域驱动设计,仅引用并配置Abp模块,即可使用常规的 ASP.NET Core Web API方式进行开发。
缓存
接下来我们将继续实现缓存功能。
- 引用Nuget包
Volo.Abp.Caching并向LightweightAbpModule添加AbpCachingModule模块依赖; - 修改
IBookAppService及BookAppService实现GetAllAsync方法:
public interface IBookAppService
{
Task<string> CreateAsync(string name);
Task<string[]> GetAllAsync();
}
public class BookAppService : ApplicationService, IBookAppService
{
private readonly IRepository<Book, Guid> _repository;
private readonly IDistributedCache<string[]> _cache;
public BookAppService(
IRepository<Book, Guid> repository,
IDistributedCache<string[]> cache)
{
_repository = repository;
_cache = cache;
}
public async Task<string> CreateAsync(string name)
{ ... }
public async Task<string[]> GetAllAsync()
{
return await _cache.GetOrAddAsync(
"AllBooksName",
async () => await _repository.Select(b => b.Name).ToArrayAsync(),
() => new DistributedCacheEntryOptions
{
AbsoluteExpiration = DateTimeOffset.Now.AddHours(1)
}
);
}
}
- 修改
BookAppService实现GetAllAsyncAPI接口:
public class BookController : AbpController
{
...
[HttpGet("all")]
public Task<string[]> GetAllAsync()
{
return _service.GetAllAsync();
}
}
- F5以调试方式运行,即可调用实现了缓存功能的
GetAllAsync接口。
这里我们实现了缓存功能。显而易见,按需使用缓存功能所在的Nuget包及模块即可,并没有很多繁杂的操作。
众所周知,Abp实现了相当多的功能,其中有些功能也许整个项目生命周期中都不会用到。得益于模块化的方式,我们可以只依赖我所需要的Nuget包和Abp模块。如果根据功能多少来评判框架的“轻”和“重”,我们按需依赖不同模块时Abp框架不可谓不轻。由此可见,一个框架的“轻”和“重”,有时还会取决于使用方式。
上手难度及易用性
学习一门新技术最好的起点便是官方文档,Abp也是如此,Abp的官方文档非常详尽介绍了各个功能。Abp还为我们提供了启动模板,模板遵循了领域驱动设计的最佳实践来进行项目分层,并且为我们继承了很多项目中常用的功能模块。
对于初学者而言,面对一个复杂的分层架构及丰富的功能特性支持,一瞬间需要接受非常多的知识,因此会产生无从下手的感觉,进而得出一种上手难度高,框架很“重”的结论。
如果从另外一种角度来学习Abp的话,也许情况会有所不同。在本文之初,我便提出了Abp的核心是模块化及依赖注入的观点,当我们将入门的重点放在模块化和依赖注入上,那么会发现Abp是一个极易上手并且学习曲线很平缓的框架。正如上文我所进行的代码演示,如果感觉这个演示项目简单易学,那么就证明了我这一观点。
至于易用性,首先Abp实现的功能很全面,我们可以按需使用;其次,随着对Abp框架的逐步深入,会发现模块化的设计让我们的项目集成多种功能变得简单,并且随着项目的演进,Abp的模块化给我们提供了轻易切换到微服务方案的能力;依赖注入系统让我们能够轻易的定制并替换Abp默认实现的功能。因此,我认为Abp是一个易于使用的框架。
总结
在这里我们从一个不同的角度来认识了Abp框架,显而易见,对于Abp来讲,是否太“重”,和我们对他的认知及使用方式有很大的关联。
项目示例代码将托管在Github中。
致谢
感谢Abp群(QQ群:48039003)的群友们提供的热心帮助。
Abp太重了?轻量化Abp框架的更多相关文章
- 深度学习与CV教程(10) | 轻量化CNN架构 (SqueezeNet,ShuffleNet,MobileNet等)
作者:韩信子@ShowMeAI 教程地址:http://www.showmeai.tech/tutorials/37 本文地址:http://www.showmeai.tech/article-det ...
- ABP前端使用阿里云angular2 UI框架NG-ZORRO分享
一.前言 前段时间写博客分享和介绍了阿里云的UI框架NG-ZORRO(博客请查看:http://www.cnblogs.com/donaldtdz/p/7892960.html),结合近段时间对.Ne ...
- 56 Marvin: 一个支持GPU加速、且不依赖其他库(除cuda和cudnn)的轻量化多维深度学习(deep learning)框架介绍
0 引言 Marvin是普林斯顿视觉实验室(PrincetonVision)于2015年提出的轻量化GPU加速的多维深度学习网络框架.该框架采用纯c/c++编写,除了cuda和cudnn以外,不依赖其 ...
- 轻量化模型训练加速的思考(Pytorch实现)
0. 引子 在训练轻量化模型时,经常发生的情况就是,明明 GPU 很闲,可速度就是上不去,用了多张卡并行也没有太大改善. 如果什么优化都不做,仅仅是使用nn.DataParallel这个模块,那么实测 ...
- CNN结构演变总结(二)轻量化模型
CNN结构演变总结(一)经典模型 导言: 上一篇介绍了经典模型中的结构演变,介绍了设计原理,作用,效果等.在本文,将对轻量化模型进行总结分析. 轻量化模型主要围绕减少计算量,减少参数,降低实际运行时间 ...
- 适配抖音!三角面转换和3d模型体量减小,轻量化一键即可完成!
抖音3d特效,可谓是越来越火爆了,这个有着迪士尼画风的3D大眼,就刷屏了国内外用户的首页! 有人好奇这些特效究竟是怎么制作的?其实就是把3D模型调整适配到头部模型上,调整位置或者大小就可以制作出一个简 ...
- 大数据开发,Hadoop Spark太重?你试试esProc SPL
摘要:由于目标和现实的错位,对很多用户来讲,Hadoop成了一个在技术.应用和成本上都很沉重的产品. 本文分享自华为云社区<Hadoop Spark太重,esProc SPL很轻>,作者: ...
- 随应潮流-基于ABP+Angulsrjs现代化应用软件开发框架(2)-abp说明
前言 上周未发布完<基于ABP+Angulsrjs现代化应用软件开发框架(1)-总体介绍> 文章后,好多朋友问了我一些ABP的问题,并且希望我开源我的项目源码,向朋友们说一下,我项目的源码 ...
- 铁大Facebook轻量化界面NABCD
界面轻量化: N:满足了用户更快速.更直接.更方便寻求自己所要信息的需求,不被复杂界面以及各种广告所困扰. A:我们将会用Bootstrap工具包开发前端界面,Bootstrap是基于jQuery框架 ...
随机推荐
- springcloud中 getway中的断言配置: Predicate 9中配置过程, getway的 filters实现限流功能:
https://www.cnblogs.com/grasp/p/11506426.html 这里引用别人的,,且试验过 ,没问题 server: port: 9527 spring: applicat ...
- JDBC连接MySQL、Oracle和SQL server的配置
什么是JDBC 我们可以将JDBC看作是一组用于用JAVA操作数据库的API,通过这个API接口,可以连接到数据库,并且使用结构化查询语言(SQL)完成对数据库的查找,更新等操作. JDBC连接的流程 ...
- powerDisigner使用
最近要忙期考,但还是决定每天抽点空来写CodeSmith的系列文章了,在此实在不敢用教程这个词语,毕竟自己对CodeSmith了解的也不是很多,有很多牛人都在博客园发布了不少关于CodeSmith ...
- 【NX二次开发】切换模块的方法,切换到制图模块
源码(NX12.0): Session theSession = NXOpen::Session::GetSession(); theSession->ApplicationSwitchImme ...
- python学习笔记04-了解操作符与条件分支
先来了解一下条件操作符: 运算符 描述 示例 == 检查两个操作数的值是否相等,如果是则条件变为真. 如a=3,b=3则(a == b) 为 true. != 检查两个操作数的值是否相等,如果值不相等 ...
- 11:(1055, "'bbs02.app01_category.name' isn't in GROUP BY")
后台报错:[err] 1055 -- 'xxx' isn't in GROUP BY 解决方案: 初步判断是数据库(版本?配置?)的问题 进入mysql 的my.ini配置文件 ctrl+f 搜索找 ...
- 【题解】hdu 3586 Information Disturbing 二分 树形dp
题目描述 Information DisturbingTime Limit: 6000/3000 MS (Java/Others) Memory Limit: 131072/65536 K (Java ...
- 同事内推的那位Linux C/C++后端开发同学面试没过......
最近同事内推了一位 Linux C/C++ 后端开发的同学到我们公司面试,我是一面的面试官,很遗憾这位工作了两年的同学面试表现不是很好.我问了如下一些问题: "redis持久化机制,redi ...
- springboot bean的循环依赖实现 源码分析
springboot bean的循环依赖实现 源码分析 本文基于springboot版本2.5.1 <parent> <groupId>org.springframework. ...
- 微信小程序电子签名实现
实现签名方法就是使用canvas <canvas canvas-id="firstCanvas" id='firstCanvas' bindtouchstart=" ...