ABP vNext微服務架構詳細教程(補充篇)——單層模板(上)訂正篇

簡介

33ea2c9ebb58cd0d9fb761ae97f0261d.png

在之前的《ABP vNext微服務架構詳細教程》系列中,我們已經構建了完整的微服務架構實例,但是在開發過程中,我們會發現每個基礎服務都包含10個類庫,這是給予DDD四層架構下ABP的實現方案,但是實際使用中我們會發現,隨著微服務的增多,類庫數量的確太過龐大了。而當時受到ABP vNext版本的限制,并沒有一個快速生成精簡應用框架的方式。

071b35be0f4372b01dc6451d37ff8c46.png

到了ABP vNext 5.3版本之后,官方添加了新的模板——單層應用模板,用于解決微服務架構單個項目類庫過多的問題,也給了我們可以快速構建精簡的微服務項目的入口。

a610d9eb7995dd8b6c32885381168ff4.png

這一篇,我就基于單層應用模板,對《ABP vNext微服務架構詳細教程》系列原有微服務框架基礎上進行簡化,在ABP vNext單層模板上進一步精簡的同時,提出一套在微服務架構下單層應用的最佳實踐方案。

753ad0d70aff9d3420b901725e9b7037.png

此篇內容較長,我會分多節呈現,請一定閱讀到最后。

架構介紹

693f2f6d0cea327dbbd56b2d5f8d65b6.png

在之前的文章編寫時ABP vNext版本為5.1.1,只有5.3.0之后版本才支持單頁應用,目前最新正式版版本為5.3.4,這里我們單層模板以5.3.4版本為例。

cfcfcd8eaf865afa1938cf3424329c31.gif

通過ABP CLI命令,我們可以創建一個簡單的單層應用模板項目。這里的單層是針對類庫來說的,也就是只有一層類庫,但是類庫內部依舊包含著DDD下所有的元素,只是按文件夾劃分并且沒有明確的分層界限。

6d65ef0c850731d5c84bbd2884d1bb66.gif

到當前版本為止,ABP通過官方CLI命令創建的項目,是必須包含用戶角色權限信息管理和身份認證服務的項目。可以理解為過去應用模板的單層形式,但實際在微服務架構下,我們需要進行進一步的調整。

5544b7f56401b0dbf74e606e0f05db60.gif

對于整個微服務項目的總體架構和服務分層,我們依舊沿用之前《ABP vNext微服務架構詳細教程》中的設計,詳見:https://mp.weixin.qq.com/s/uDGwxbEhBv15RdMlflb7LA

73814f4291c4a408ffa2b32ba39962de.gif

在聚合服務層和基礎服務層業務服務中,我們使用單層模板為基礎構建我們的服務。包含以下內容:

主服務:WebAPI啟動項,也是ABP單層模板下生成的項目,包含過去Domain、Application、EntityFramworkCore、HttpApi、HttpApi.Host項目的內容,

契約層:當我們在聚合服務層依賴基礎服務層時,我們肯定只是希望依賴基礎服務中接口聲明而非實現,所以將過去項目中的Application.Contracts和Domain.Shared兩個類庫中的內容從單層模板主項目抽離出來就是一個必須的工作。在這里,我們將其放在契約層中

動態客戶端代理:在之前的基礎服務中,包含一個特殊的類庫:HttpApi.Client。它是對基礎服務層動態客戶端代理的封裝和配置,它依賴于Application.Contracts項目,在當前服務中,我們依舊希望把它單獨保留下來,以便于聚合服務實現HTTP調用。

6087b6239cdeacbdbb0f0fa4ce7b50c8.png

這里,基礎服務層需要包含以上三個項目,而聚合服務層目前沒有提供動態客戶端代理的需求,所以可以只包含主服務和契約層。(雖然從技術角度聚合服務中契約層也不是必須單獨拿出來,但是從架構一致性和擴展性角度,我依舊推薦將契約單獨存放)。

2405921d9ad48b71af800c6d6d3e61e8.gif

聚合服務層和基礎服務層業務服務依賴關系如下圖:

a04ee0cef1e44ec2f1cdb2e98eb3e4c0.png

2a99cfccd3952dbfdcf90e9c3d50f87d.png

在整個微服務架構中,身份管理基礎服務比較特殊,由于我們的授權中心依賴身份管理服務的EntityFrameworkCore,如果采用單層架構,則發現EntityFrameworkCore項目必須獨立出來,而EntityFrameworkCore依賴于Domain層,則Domain層也需要獨立,此時我們發現這個項目已經違背了單層應用的初衷。所以身份管理的基礎服務我們依舊采用之前的方式來構建。

另外身份認證服務和網關本身就是單類庫項目,也不需要做調整。

框架搭建

1

基礎服務層

fe6ba3cd3f46670b0ee07a85705a6c35.gif

基礎服務我們命名為NotificationManager,通過以下ABP CLI命令,我們可以構建基礎服務的主服務,這里我們選擇無UI模板,MySQL數據庫

abp new Demo.NotificationManager -t app-nolayers -u none -dbms mysql

將該服務添加至主解決方案service/notificationmanger解決方案文件夾下,并在同目錄下分別創建契約層類庫?Demo.NotificationManager.Contracts?和動態客戶端代理類庫?Demo.NotificationManager.Client?。創建后結果如下圖:

3cc9707e8286b9ab0d8fbbf9c336f120.png

99e234115cc327a6e87d9415a262d684.gif

由于我們沒有使用多語言,所以直接將主項目中Localization文件夾所有內容刪除。

這里我打算使用另一種對象映射框架,所以刪除主項目中的ObjectMapping文件夾,如果準備繼續使用AutoMapper框架則保留該文件夾。

移除主項目中Services文件夾中的Dtos子文件夾,DTO不存放在該項目中而是在契約層。

由于我們這邊不涉及前端,所以刪除wwwroot文件夾和package.json文件。

刪除主服務Data文件夾下的IdentityServerDataSeedContributor.cs文件。

刪除后主服務項目結構如下:

ca1e3adbdb199e44381a18bc4e56bcc9.png

53d13d97fc04ee646f393b1f5ab84c6d.gif

編輯主項目的Demo.NotificationManager.csproj文件,刪除從??<ItemGroup> <PackageReference Include="Volo.Abp.Account.Application"?Version="5.3.4"?/>??到??<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded"?Version="6.0.5"?/> </ItemGroup>?的所有引用及AutoMapper引用,保留如下內容:

<Project Sdk="Microsoft.NET.Sdk.Web"><PropertyGroup><TargetFramework>net6.0</TargetFramework><ImplicitUsings>enable</ImplicitUsings><GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest></PropertyGroup><ItemGroup><PackageReference Include="Serilog.AspNetCore" Version="5.0.0" /><PackageReference Include="Serilog.Sinks.Async" Version="1.5.0" /></ItemGroup><ItemGroup><PackageReference Include="Volo.Abp.AspNetCore.Mvc" Version="5.3.4" /><PackageReference Include="Volo.Abp.Autofac" Version="5.3.4" /><PackageReference Include="Volo.Abp.Swashbuckle" Version="5.3.4" /><PackageReference Include="Volo.Abp.AspNetCore.Authentication.JwtBearer" Version="5.3.4" /><PackageReference Include="Volo.Abp.AspNetCore.Serilog" Version="5.3.4" /><PackageReference Include="Volo.Abp.EntityFrameworkCore.MySQL" Version="5.3.4" /></ItemGroup><ItemGroup><PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="6.0.5" /></ItemGroup><ItemGroup><PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.5"><IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets><PrivateAssets>compile; contentFiles; build; buildMultitargeting; buildTransitive; analyzers; native</PrivateAssets></PackageReference></ItemGroup><ItemGroup><Compile Remove="Logs\**" /><Content Remove="Logs\**" /><EmbeddedResource Remove="Logs\**" /><None Remove="Logs\**" /></ItemGroup><ItemGroup><ProjectReference Include="..\..\..\common\Demo.Abp.Extension\Demo.Abp.Extension.csproj" /><ProjectReference Include="..\Demo.NotificationManager.Contracts\Demo.NotificationManager.Contracts.csproj" /></ItemGroup>
</Project>

47fc7b07c7e5d94d21a781ccc776d95b.gif

刪除主服務Data文件夾下NotificationManagerDbContext類中所有報錯的行,保留如下內容:

using Demo.NotificationManager.Entities.Notifications;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;namespace Demo.NotificationManager.Data;public class NotificationManagerDbContext : AbpDbContext<NotificationManagerDbContext>
{    public NotificationManagerDbContext(DbContextOptions<NotificationManagerDbContext> options): base(options){}protected override void OnModelCreating(ModelBuilder builder){base.OnModelCreating(builder);}
}

44319a0af541c910ad7fc08b2bd03a0b.gif

修改Data文件夾下NotificationManagerDbMigrationService類改為以下代碼(這里因為我們沒使用多租戶和初始化數據,所以我移除了相關內容):

using System.Diagnostics;
using System.Runtime.InteropServices;
using Microsoft.Extensions.Logging.Abstractions;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;namespace Demo.NotificationManager.Data;public class NotificationManagerDbMigrationService : ITransientDependency
{public ILogger<NotificationManagerDbMigrationService> Logger { get; set; }private readonly IDataSeeder _dataSeeder;private readonly NotificationManagerEFCoreDbSchemaMigrator _dbSchemaMigrator;private readonly ICurrentTenant _currentTenant;public NotificationManagerDbMigrationService(IDataSeeder dataSeeder,NotificationManagerEFCoreDbSchemaMigrator dbSchemaMigrator,ICurrentTenant currentTenant){_dataSeeder = dataSeeder;_dbSchemaMigrator = dbSchemaMigrator;_currentTenant = currentTenant;Logger = NullLogger<NotificationManagerDbMigrationService>.Instance;}public async Task MigrateAsync(){var initialMigrationAdded = AddInitialMigrationIfNotExist();if (initialMigrationAdded){return;}Logger.LogInformation("Started database migrations...");await MigrateDatabaseSchemaAsync();Logger.LogInformation("Successfully completed all database migrations.");Logger.LogInformation("You can safely end this process...");}private async Task MigrateDatabaseSchemaAsync(){await _dbSchemaMigrator.MigrateAsync();}private bool AddInitialMigrationIfNotExist(){try{if (!DbMigrationsProjectExists()){return false;}}catch (Exception){return false;}try{if (!MigrationsFolderExists()){AddInitialMigration();return true;}else{return false;}}catch (Exception e){Logger.LogWarning("Couldn't determinate if any migrations exist : " + e.Message);return false;}}private bool DbMigrationsProjectExists(){return Directory.Exists(GetEntityFrameworkCoreProjectFolderPath());}private bool MigrationsFolderExists(){var dbMigrationsProjectFolder = GetEntityFrameworkCoreProjectFolderPath();return Directory.Exists(Path.Combine(dbMigrationsProjectFolder, "Migrations"));}private void AddInitialMigration(){Logger.LogInformation("Creating initial migration...");string argumentPrefix;string fileName;if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || RuntimeInformation.IsOSPlatform(OSPlatform.Linux)){argumentPrefix = "-c";fileName = "/bin/bash";}else{argumentPrefix = "/C";fileName = "cmd.exe";}var procStartInfo = new ProcessStartInfo(fileName,$"{argumentPrefix} \"abp create-migration-and-run-migrator \"{GetEntityFrameworkCoreProjectFolderPath()}\" --nolayers\"");try{Process.Start(procStartInfo);}catch (Exception){throw new Exception("Couldn't run ABP CLI...");}}private string GetEntityFrameworkCoreProjectFolderPath(){var slnDirectoryPath = GetSolutionDirectoryPath();if (slnDirectoryPath == null){throw new Exception("Solution folder not found!");}return Path.Combine(slnDirectoryPath, "Demo.NotificationManager");}private string GetSolutionDirectoryPath(){var currentDirectory = new DirectoryInfo(Directory.GetCurrentDirectory());while (Directory.GetParent(currentDirectory.FullName) != null){currentDirectory = Directory.GetParent(currentDirectory.FullName);if (Directory.GetFiles(currentDirectory.FullName).FirstOrDefault(f => f.EndsWith(".sln")) != null){return currentDirectory.FullName;}}return null;}
}

9372b59b69fbb293d814e27673b5174b.gif

將主服務模塊類修改為以下內容:

using Demo.NotificationManager.Contracts;
using Microsoft.OpenApi.Models;
using Demo.NotificationManager.Data;
using Volo.Abp;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Serilog;
using Volo.Abp.Autofac;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore.MySQL;
using Volo.Abp.Modularity;
using Volo.Abp.Swashbuckle;namespace Demo.NotificationManager;[DependsOn(// ABP Framework packagestypeof(AbpAspNetCoreMvcModule),typeof(AbpAutofacModule),typeof(AbpEntityFrameworkCoreMySQLModule),typeof(AbpSwashbuckleModule),typeof(AbpAspNetCoreSerilogModule),typeof(NotificationManagerContractsModule)
)]
public class NotificationManagerModule : AbpModule
{#region 私有方法#region 配置動態webapiprivate void ConfigureAutoApiControllers(){Configure<AbpAspNetCoreMvcOptions>(options =>{options.ConventionalControllers.Create(typeof(NotificationManagerModule).Assembly);});}#endregion#region 配置swaggerprivate void ConfigureSwagger(IServiceCollection services){services.AddAbpSwaggerGen(options =>{options.SwaggerDoc("v1", new OpenApiInfo { Title = "NotificationManager API", Version = "v1" });options.DocInclusionPredicate((_, _) => true);options.CustomSchemaIds(type => type.FullName);});}#endregion#region 設置EFprivate void ConfigureEfCore(ServiceConfigurationContext context){context.Services.AddAbpDbContext<NotificationManagerDbContext>(options =>{/* You can remove "includeAllEntities: true" to create* default repositories only for aggregate roots* Documentation: https://docs.abp.io/en/abp/latest/Entity-Framework-Core#add-default-repositories*/options.AddDefaultRepositories(includeAllEntities: true);});Configure<AbpDbContextOptions>(options =>{options.Configure(configurationContext =>{configurationContext.UseMySQL();});});}#endregion#endregionpublic override void ConfigureServices(ServiceConfigurationContext context){ConfigureSwagger(context.Services);ConfigureAutoApiControllers();ConfigureEfCore(context);}public override void OnApplicationInitialization(ApplicationInitializationContext context){var app = context.GetApplicationBuilder();app.UseRouting();app.UseUnitOfWork();app.UseSwagger();app.UseSwaggerUI(options =>{options.SwaggerEndpoint("/swagger/v1/swagger.json", "NotificationManager API");});app.UseAbpSerilogEnrichers();app.UseConfiguredEndpoints();}
}

6a9c9c430455653ce50a454a43fed814.gif

?在主服務中的appsettings.json中刪除額外配置項保留如下內容

{"ConnectionStrings": {"Default": "Server=localhost;Port=3306;Database=NotificationManager;Uid=root;Pwd=123456;"},"urls": "http://*:5003"
}

fe6c706faa223dee90e14d6c1e9ec751.gif

刪除契約層中的Class1.cs,并添加模塊類NotificationManagerContractsModule如下:

using Volo.Abp.Application;
using Volo.Abp.Modularity;namespace Demo.NotificationManager.Contracts;[DependsOn(typeof(AbpDddApplicationContractsModule)
)]
public class NotificationManagerContractsModule : AbpModule
{}

0e056abbc85002ac2c4ee7d8a2c1f7c2.gif

在契約層添加NotificationManagerRemoteServiceConsts類如下:

namespace Demo.NotificationManager.Contracts;public class NotificationManagerRemoteServiceConsts
{public const string RemoteServiceName = "NitificationManager";public const string ModuleName = "nitificationManager";
}

9181cebcb468d8a9b47021c31cacdae6.gif

刪除動態客戶端代理層的Class1.cs文件,添加模塊類NotificationManagerClientModule如下:

using Demo.Abp.Extension;
using Demo.NotificationManager.Contracts;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Http.Client;
using Volo.Abp.Modularity;
using Volo.Abp.Timing;
using Volo.Abp.VirtualFileSystem;namespace Demo.NotificationManager.Client;[DependsOn(typeof(NotificationManagerContractsModule),   typeof(AbpHttpClientModule))]public class NotificationManagerClientModule : AbpModule
{public override void ConfigureServices(ServiceConfigurationContext context){context.Services.AddTransient<AddHeaderHandler>();context.Services.AddHttpClient(NotificationManagerRemoteServiceConsts.RemoteServiceName).AddHttpMessageHandler<AddHeaderHandler>();context.Services.AddHttpClientProxies(typeof(NotificationManagerContractsModule).Assembly,NotificationManagerRemoteServiceConsts.RemoteServiceName);Configure<AbpVirtualFileSystemOptions>(options =>{options.FileSets.AddEmbedded<NotificationManagerClientModule>();});Configure<AbpClockOptions>(options => { options.Kind = DateTimeKind.Local; });}
}

8c79174e863c26c9104c9cc515702cb8.png

完成以上修改后,運行項目并用瀏覽器訪問http://localhost:5003,可出現Swagger頁面則基礎服務配置成功。

d33d01dedc7d7b8d6940bb03eae905d2.png

未完待續

087391b1b35c83a31a05f40292cde3a6.jpeg

79ed1d02b74fa4d5cc6d3314088b3d39.png

關注我獲得

更多精彩

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/282333.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/282333.shtml
英文地址,請注明出處:http://en.pswp.cn/news/282333.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

MyBatis Plus輕松實現數據讀寫分離

在現代應用程序中,數據庫是至關重要的組成部分。為了提高性能和可用性,常見的數據庫優化策略之一是將數據庫讀和寫操作分離,以降低數據庫服務器的負載。MyBatis Plus是一個流行的Java持久化框架,它提供了讀寫分離的支持,結合Spring Boot 集成多數據源的特性可以幫助你輕松…

javascript基礎修煉(4)——UMD規范的代碼推演

javascript基礎修煉(4)——UMD規范的代碼推演 1. UMD規范 地址&#xff1a;https://github.com/umdjs/umd UMD規范&#xff0c;就是所有規范里長得最丑的那個&#xff0c;沒有之一&#xff01;&#xff01;&#xff01;它是為了讓模塊同時兼容AMD和CommonJs規范而出現的&#x…

Missing artifact log4j:log4j:bundle:1.2.17

為什么80%的碼農都做不了架構師&#xff1f;>>> maven引入log4jjar包出現Missing artifact log4j:log4j:bundle:1.2.17&#xff0c;解決方法是去掉bundle&#xff0c;其他的解決方案可以參考maven log4j.jar問題 Maven使用log4j可能會有協議上的問題 如果log4j的版…

PHPStorm 配置遠程服務器文件夾在本地windows鏡像,實現代碼自動同步(類似于Samba架構文件同步功能)

場景介紹&#xff1a; 這是一種類似samba架構&#xff0c;也和 filezillaxshell 模式相類似的代碼文件同步的模式&#xff0c;但是卻更加優雅&#xff0c;也更加方便簡潔。環境介紹&#xff1a; 本地windows端&#xff1a;編輯器phpstorm 遠程Linux端&#xff1a;centos&#x…

bzoj1143/2718 祭祀river(最大獨立集)

[CTSC2008]祭祀river Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2175 Solved: 1098[Submit][Status][Discuss]Description 在遙遠的東方&#xff0c;有一個神秘的民族&#xff0c;自稱Y族。他們世代居住在水面上&#xff0c;奉龍王為神。每逢重大慶典&#xff0c; Y族…

反向ajax實現

在過去的幾年中&#xff0c;web開發已經發生了很大的變化。現如今&#xff0c;我們期望的是能夠通過web快速、動態地訪問應用。在這一新的文章系列中&#xff0c;我們學習如何使用反 向Ajax&#xff08;Reverse Ajax&#xff09;技術來開發事件驅動的web應用&#xff0c;以此來…

linux系統啟動流程及常見問題的解決

一、前言計算機開機是一個神秘的過程。我們只是按了開機鍵&#xff0c;就看到屏幕上的進度條或者一行行的輸出&#xff0c;直到我們到達登錄界面。然而&#xff0c;計算機開機又是個異常脆弱的過程&#xff0c;我們滿心期望的登錄界面可能并不會出現&#xff0c;而是一個命令行…

使用.NET開發一個屏幕OCR工具

本文將介紹使用.NET開發的一款桌面截圖 OCR 工具&#xff0c;軟件已開源&#xff0c;地址&#xff1a;https://github.com/sangyuxiaowu/Snipping_OCR背景因為不同地方人們的使用習慣不同&#xff0c;國內可能截圖更多的是使用QQ&#xff0c;微信等即時聊天工具提供的截圖功能。…

segnet 編譯與測試

segnet 編譯與測試參考&#xff1a;http://sunxg13.github.io/2015/09/10/caffe/http://m.blog.csdn.net/lemianli/article/details/76687508http://blog.h5min.cn/u010069760/article/details/75258539&#xff08;注意&#xff1a;nakefile而非makefile.config&#xff09;1、…

Linux開啟fileinfo擴展

在項目初始部署環境的時候&#xff0c;可能考慮的并不全面&#xff0c;就會少裝一些擴展&#xff0c;這里講解如何添加fileinfo擴展1、找到php安裝的壓縮包2、將壓縮包cp到 /data目錄下&#xff0c;并解壓 cp php-7.0.30.tar.gz /data cd /data tar -zxvf php-7.0.30.tar.gz…

TemplateBinding與Binding區別,以及WPF自定義控件開發的遭遇

在上一次的文章WPF OnApplyTemplate 不執行 或者執行滯后的疑惑談到怎么正確的開發自定義控件&#xff0c;我們控件的樣式中&#xff0c;屬性的綁定一般都是用TemplateBinding來完成,如下一個基本的按鈕樣式&#xff1a; <Style x:Key"SimpleButton" TargetType&q…

Layui版本的WPF開源控件庫-Layui-WPF

大家好&#xff0c;我是沙漠盡頭的狼。今天介紹一款Layui風格的WPF開源控件庫&#xff0c;倉庫信息如下&#xff1a;倉庫地址&#xff1a;https://github.com/Layui-WPF-Team/Layui-WPF倉庫截圖&#xff1a;Layui-WPF關于Layui請點擊此鏈接[1]了解&#xff0c;本文不做介紹&…

Mycat 之 通過Keepalived 實現高可用

一、系統拓撲圖 一、操作方法 參考本博客的Nginx Keepalived 實現高可用轉載于:https://blog.51cto.com/12965094/2164485

Nginx使用upstream實現動靜分離

一、為什么要進行動靜分離 分離資源&#xff0c;減少不必要到的請求消耗&#xff0c;減少請求延時。 注&#xff1a;我這里&#xff0c;是nginx處理靜態資源&#xff0c;apache處理動態資源。 場景分析&#xff1a; 1、未分離之前的場景步驟 &#xff08;1&#xff09;客戶…

HMAC

HMAC 的用途 HMAC 算法主要應用于身份驗證&#xff0c;用法如下&#xff1a; 1.客戶端發出登錄請求2.服務器返回一個隨機值&#xff0c;在會話記錄中保存這個隨機值3.客戶端將該隨機值作為密鑰&#xff0c;用戶密碼進行 hmac 運算&#xff0c;遞交給服務器4.服務器讀取數據庫中…

JS的原型鏈和繼承

原型和原型鏈 原型prototype&#xff0c;在創建新函數的時候&#xff0c;會自動生成&#xff0c;而prototype中也會有一個constructor&#xff0c;回指創建該prototype的函數對象。 __proto__是對象或者實例中內置的[[prototype]]&#xff0c;其指向的是產生該對象的對象的prot…

Android 的滑動分析以及各種實現

一、滑動效果的產生滑動一個View&#xff0c;本質區別就是移動一個View。改變當前View所在的坐標&#xff0c;原理和動畫相似不斷改變坐標位置實現。實現View的滑動就必須監聽滑動的事件&#xff0c;并且根據事件傳入的坐標&#xff0c;動態且不斷改變View的坐標&#xff0c;從…

微軟產品 .NET 6 遷移之旅

“.NET性能不行&#xff01;”“.NET有什么像樣的產品嗎&#xff01;&#xff1f;”“升級到.NET 6有什么好處&#xff01;&#xff1f;”……聽人扯淡還不如看看微軟自己是怎么做的。本文將匯總一下微軟的開發博客——這些博客均涉及微軟將產品和服務遷移到.NET 6的成果。博客…

Navicat 連接 RDS數據庫

場景介紹&#xff1a; 隨著業務量的逐漸增加&#xff0c;公司的數據庫壓力也會逐漸增大&#xff0c;使用自己購買的esc創建的mysql的話&#xff0c;還得考慮相應的dba維護&#xff0c;也比較繁瑣&#xff0c;說不定還做的并不完美&#xff0c;這時&#xff0c;RDS就派上用場了&…

bzoj1045 糖果傳遞

Description 有n個小朋友坐成一圈&#xff0c;每人有ai個糖果。每人只能給左右兩人傳遞糖果。每人每次傳遞一個糖果代價為1。 Input 第一行一個正整數nn<1000000&#xff0c;表示小朋友的個數&#xff0e;接下來n行&#xff0c;每行一個整數ai&#xff0c;表示第i個小朋友得…