添加服務與注冊中間件
public IServiceProvider ConfigureServices(IServiceCollection services)
{
// Configure Abp and Dependency Injection
return services.AddAbp<MyStudyWebHostModule>(
// Configure Log4Net logging
options => options.IocManager.IocContainer.AddFacility<LoggingFacility>(
f => f.UseAbpLog4Net().WithConfig("log4net.config")
)
);
}
先來看看startup這個類的ConfigureServices方法,注意這個方法的返回值,我們知道使用vs創建的項目 返回值為void,但是使用abp的話 返回值是IServiceProvider ,這是因為這里有個AddAbp()方法,這就是我們的入口點,主要做的就是將ABP集成到Asp.Net Core其返回值就是IServiceProvider,因為ABP有自己的第三方IOC框架(CastleWindsor),所以它接管了.net core自帶的容器,至於為什么,其實在WebHost的Initialize(初始化)方法中做的第一件事就是找到StartUP類,執行ConfigureServices()方法
private void EnsureApplicationServices()
{
if (_applicationServices == null)
{
EnsureStartup();
_applicationServices = _startup.ConfigureServices(_applicationServiceCollection);
}
}
private void EnsureStartup()
{
if (_startup != null)
{
return;
}
_startup = _hostingServiceProvider.GetService<IStartup>();
if (_startup == null)
{
hrow new InvalidOperationException($"No startup configured. Please specify startup via WebHostBuilder.UseStartup, WebHostBuilder.Configure, injecting {nameof(IStartup)} or specifying the startup assembly via {nameof(WebHostDefaults.StartupAssemblyKey)} in the web host configuration.");
}
}
這里的 _hostingServiceProvider(IServiceProvider), _applicationServiceCollection(IServiceCollection) ,其實是WebHostBuilder在創建WebHost時通過ctor傳遞給webhost的,以后也就是我們程序的根容器,以后每次有請求過來時,我們的根容器都會創建出一個子容器,並交給我們的HttpContext對象
(AutoRequestServicesStartupFilter(StartupFilter類型)會在startup類的Configure方法執行前執行,注冊我們的RequestServicesContainerMiddleware中間件,該中間件會把子容器交給我們的HttpContext對象,實現了該子容器線程內唯一,這里不再展開了,有興趣的可以搜下Asp.net Core DI原理)
好了,不小心扯遠了.回到正題.
startup類中還有個Configure方法,注冊中間件.
app.UseAbp(options => { options.UseAbpRequestLocalization = false; })
添加服務
來到AddAbp方法內部,AddAbpBootstrapper內部其實是調用了Create方法,
public static IServiceProvider AddAbp<TStartupModule>(this IServiceCollection services, [CanBeNull] Action<AbpBootstrapperOptions> optionsAction = null)
where TStartupModule : AbpModule
{
var abpBootstrapper = AddAbpBootstrapper<TStartupModule>(services, optionsAction);
ConfigureAspNetCore(services, abpBootstrapper.IocManager);
return WindsorRegistrationHelper.CreateServiceProvider(abpBootstrapper.IocManager.IocContainer, services);
}
private static AbpBootstrapper AddAbpBootstrapper<TStartupModule>(IServiceCollection services, Action<AbpBootstrapperOptions> optionsAction)
where TStartupModule : AbpModule
{
var abpBootstrapper = AbpBootstrapper.Create<TStartupModule>(optionsAction);
services.AddSingleton(abpBootstrapper);
return abpBootstrapper;
}
可以看到AddAbpBootstrapper方法就是創建了AbpBootstrapper 並且以單例的形式注冊到我們的ioc根容器
在來看看ConfigureAspNetCore方法
private static void ConfigureAspNetCore(IServiceCollection services, IIocResolver iocResolver)
{
//See https://github.com/aspnet/Mvc/issues/3936 to know why we added these services.
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.TryAddSingleton<IActionContextAccessor, ActionContextAccessor>();
//Use DI to create controllers
services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());
//Use DI to create view components
services.Replace(ServiceDescriptor.Singleton<IViewComponentActivator, ServiceBasedViewComponentActivator>());
//Change anti forgery filters (to work proper with non-browser clients)
services.Replace(ServiceDescriptor.Transient<AutoValidateAntiforgeryTokenAuthorizationFilter, AbpAutoValidateAntiforgeryTokenAuthorizationFilter>());
services.Replace(ServiceDescriptor.Transient<ValidateAntiforgeryTokenAuthorizationFilter, AbpValidateAntiforgeryTokenAuthorizationFilter>());
//Add feature providers
var partManager = services.GetSingletonServiceOrNull<ApplicationPartManager>();
partManager?.FeatureProviders.Add(new AbpAppServiceControllerFeatureProvider(iocResolver));
//Configure JSON serializer
services.Configure<MvcJsonOptions>(jsonOptions =>
{
jsonOptions.SerializerSettings.ContractResolver = new AbpMvcContractResolver(iocResolver)
{
NamingStrategy = new CamelCaseNamingStrategy()
};
});
//Configure MVC
services.Configure<MvcOptions>(mvcOptions =>
{
mvcOptions.AddAbp(services);
});
//Configure Razor
services.Insert(0,
ServiceDescriptor.Singleton<IConfigureOptions<RazorViewEngineOptions>>(
new ConfigureOptions<RazorViewEngineOptions>(
(options) =>
{
options.FileProviders.Add(new EmbeddedResourceViewFileProvider(iocResolver));
}
)
)
);
}
內部主要是做了與asp.net core相關的配置,其中 mvcOptions.AddAbp(services); 內部執行AddFilters方法添加abp自己的過濾器
private static void AddFilters(MvcOptions options)
{
options.Filters.AddService(typeof(AbpAuthorizationFilter));
options.Filters.AddService(typeof(AbpAuditActionFilter));
options.Filters.AddService(typeof(AbpValidationActionFilter));
options.Filters.AddService(typeof(AbpUowActionFilter));
options.Filters.AddService(typeof(AbpExceptionFilter));
options.Filters.AddService(typeof(AbpResultFilter));
}
然后在看看WindsorRegistrationHelper.CreateServiceProvider(abpBootstrapper.IocManager.IocContainer, services);
里面注冊了一堆ioc相關的服務並創建實現了IServiceProvider的實例類型,接管Asp.net core默認的ServerCollection.
注冊中間件
我們再來看看Configure中的UseABP方法,來到其內部
public static void UseAbp([NotNull] this IApplicationBuilder app, Action<AbpApplicationBuilderOptions> optionsAction)
{
Check.NotNull(app, nameof(app));
var options = new AbpApplicationBuilderOptions();
optionsAction?.Invoke(options);
if (options.UseCastleLoggerFactory)
{
app.UseCastleLoggerFactory();
}
InitializeAbp(app);
if (options.UseAbpRequestLocalization)
{
//TODO: This should be added later than authorization middleware!
app.UseAbpRequestLocalization();
}
if (options.UseSecurityHeaders)
{
app.UseAbpSecurityHeaders();
}
}
其中InitializeAbp(app);主要是從Ioc容器中獲取之前單例注冊的abpBootstrapper並執行其初始化方法,並且還獲取了一個生命周期對象,並注冊了一個事件,當程序停止的時候執行我們abpBootstrapper的Dispose方法
private static void InitializeAbp(IApplicationBuilder app)
{
var abpBootstrapper = app.ApplicationServices.GetRequiredService<AbpBootstrapper>();
abpBootstrapper.Initialize();
var applicationLifetime = app.ApplicationServices.GetService<IApplicationLifetime>();
applicationLifetime.ApplicationStopping.Register(() => abpBootstrapper.Dispose());
}
在來看看abpBootstrapper的Initialize初始化方法
public virtual void Initialize()
{
ResolveLogger();
try
{
RegisterBootstrapper();
IocManager.IocContainer.Install(new AbpCoreInstaller());
IocManager.Resolve<AbpPlugInManager>().PlugInSources.AddRange(PlugInSources);
IocManager.Resolve<AbpStartupConfiguration>().Initialize();
_moduleManager = IocManager.Resolve<AbpModuleManager>();
_moduleManager.Initialize(StartupModule);
_moduleManager.StartModules();
}
catch (Exception ex)
{
_logger.Fatal(ex.ToString(), ex);
throw;
}
}
框架啟動之后的初始化操作都存放在 AbpBootstrapper 當中,包括框架內部的各種基礎設施的注入與所有模塊加載操作
框架初始化
注入基礎設施
可以看到上述代碼中 IocManager.IocContainer.Install(new AbpCoreInstaller());這里其實就是在注冊一些基礎設施
internal class AbpCoreInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<IUnitOfWorkDefaultOptions, UnitOfWorkDefaultOptions>().ImplementedBy<UnitOfWorkDefaultOptions>().LifestyleSingleton(),
Component.For<INavigationConfiguration, NavigationConfiguration>().ImplementedBy<NavigationConfiguration>().LifestyleSingleton(),
Component.For<ILocalizationConfiguration, LocalizationConfiguration>().ImplementedBy<LocalizationConfiguration>().LifestyleSingleton(),
Component.For<IAuthorizationConfiguration, AuthorizationConfiguration>().ImplementedBy<AuthorizationConfiguration>().LifestyleSingleton(),
Component.For<IValidationConfiguration, ValidationConfiguration>().ImplementedBy<ValidationConfiguration>().LifestyleSingleton(),
Component.For<IFeatureConfiguration, FeatureConfiguration>().ImplementedBy<FeatureConfiguration>().LifestyleSingleton(),
Component.For<ISettingsConfiguration, SettingsConfiguration>().ImplementedBy<SettingsConfiguration>().LifestyleSingleton(),
Component.For<IModuleConfigurations, ModuleConfigurations>().ImplementedBy<ModuleConfigurations>().LifestyleSingleton(),
Component.For<IEventBusConfiguration, EventBusConfiguration>().ImplementedBy<EventBusConfiguration>().LifestyleSingleton(),
Component.For<IMultiTenancyConfig, MultiTenancyConfig>().ImplementedBy<MultiTenancyConfig>().LifestyleSingleton(),
Component.For<ICachingConfiguration, CachingConfiguration>().ImplementedBy<CachingConfiguration>().LifestyleSingleton(),
Component.For<IAuditingConfiguration, AuditingConfiguration>().ImplementedBy<AuditingConfiguration>().LifestyleSingleton(),
Component.For<IBackgroundJobConfiguration, BackgroundJobConfiguration>().ImplementedBy<BackgroundJobConfiguration>().LifestyleSingleton(),
Component.For<INotificationConfiguration, NotificationConfiguration>().ImplementedBy<NotificationConfiguration>().LifestyleSingleton(),
Component.For<IEmbeddedResourcesConfiguration, EmbeddedResourcesConfiguration>().ImplementedBy<EmbeddedResourcesConfiguration>().LifestyleSingleton(),
Component.For<IAbpStartupConfiguration, AbpStartupConfiguration>().ImplementedBy<AbpStartupConfiguration>().LifestyleSingleton(),
Component.For<IEntityHistoryConfiguration, EntityHistoryConfiguration>().ImplementedBy<EntityHistoryConfiguration>().LifestyleSingleton(),
Component.For<ITypeFinder, TypeFinder>().ImplementedBy<TypeFinder>().LifestyleSingleton(),
Component.For<IAbpPlugInManager, AbpPlugInManager>().ImplementedBy<AbpPlugInManager>().LifestyleSingleton(),
Component.For<IAbpModuleManager, AbpModuleManager>().ImplementedBy<AbpModuleManager>().LifestyleSingleton(),
Component.For<IAssemblyFinder, AbpAssemblyFinder>().ImplementedBy<AbpAssemblyFinder>().LifestyleSingleton(),
Component.For<ILocalizationManager, LocalizationManager>().ImplementedBy<LocalizationManager>().LifestyleSingleton()
);
}
}
可以看到有工作單元,緩存,審計日志....等一系列的基礎設施,都是在這里被注冊的.
模塊初始化
加載模塊
_moduleManager = IocManager.Resolve<AbpModuleManager>();
_moduleManager.Initialize(StartupModule);
通過AbpModuleManager的Initialize方法加載所有的模塊
public virtual void Initialize(Type startupModule)
{
_modules = new AbpModuleCollection(startupModule);
LoadAllModules();
}
可以看到,直接初始化了AbpModuleCollection集合,它本質就是個集合,只不過有些“自定義”的排序方法
- EnsureStartupModuleToBeLast 確保啟動模塊是最后一個
- EnsureKernelModuleToBeFirst 確保最核心的模塊是第一個
下面的LoadAllModules 則是真正的加載所有模塊
private void LoadAllModules()
{
Logger.Debug("Loading Abp modules...");
List<Type> plugInModuleTypes;
var moduleTypes = FindAllModuleTypes(out plugInModuleTypes).Distinct().ToList();
Logger.Debug("Found " + moduleTypes.Count + " ABP modules in total.");
RegisterModules(moduleTypes);
CreateModules(moduleTypes, plugInModuleTypes);
_modules.EnsureKernelModuleToBeFirst();
_modules.EnsureStartupModuleToBeLast();
SetDependencies();
Logger.DebugFormat("{0} modules loaded.", _modules.Count);
}
首先在FindAllModuleTypes方法內部通過啟動模塊上面的[DependsOn]標簽來從最外層加載插件形式的模塊與內部模塊
之后將通過RegisterModules所有模塊單例注入到 Ioc 容器內部
public static bool RegisterIfNot(this IIocRegistrar iocRegistrar, Type type, DependencyLifeStyle lifeStyle=DependencyLifeStyle.Singleton)
{
if (iocRegistrar.IsRegistered(type))
{
return false;
}
iocRegistrar.Register(type, lifeStyle);
return true;
}
而CreateModules方法則是從ioc容器中獲取一個模塊,為模塊配置一些屬性如:IocManager以及Configuration 並包裝成AbpModuleInfo對象
private void CreateModules(ICollection<Type> moduleTypes, List<Type> plugInModuleTypes)
{
foreach (var moduleType in moduleTypes)
{
var moduleObject = _iocManager.Resolve(moduleType) as AbpModule;
if (moduleObject == null)
{
throw new AbpInitializationException("This type is not an ABP module: " + moduleType.AssemblyQualifiedName);
}
moduleObject.IocManager = _iocManager;
moduleObject.Configuration = _iocManager.Resolve<IAbpStartupConfiguration>();
var moduleInfo = new AbpModuleInfo(moduleType, moduleObject, plugInModuleTypes.Contains(moduleType));
_modules.Add(moduleInfo);
if (moduleType == _modules.StartupModuleType)
{
StartupModule = moduleInfo;
}
Logger.DebugFormat("Loaded module: " + moduleType.AssemblyQualifiedName);
}
}
- 既然有了模塊的類型,為什么還要一層包裝?
- 因為為了確保模塊按正確的順序來進行加載,所以需要擁有每個模塊的詳細信息,主要是依賴信息,正確的順序應該是核心模塊在最里層,而啟動模塊應該是在最底層的。所以還調用了AbpModuleManager的EnsureKernelModuleToBeFirst方法與EnsureStartupModuleToBeLast方法,以確保正確的加載順序
而SetDependencies方法則是來為每一個AbpModuleInfo配置正確的依賴關系。
初始化模塊
所有模塊的依賴關系與實例都已經被存放到了AbpModuleCollection里面了,下面就來啟動這些模塊了,啟動模塊的方法則是AbpBootstrapper.StartModules
ps:代碼上面貼過
public virtual void StartModules()
{
var sortedModules = _modules.GetSortedModuleListByDependency();
sortedModules.ForEach(module => module.Instance.PreInitialize());
sortedModules.ForEach(module => module.Instance.Initialize());
sortedModules.ForEach(module => module.Instance.PostInitialize());
}
/// <summary>
/// Sorts modules according to dependencies.
/// If module A depends on module B, A comes after B in the returned List.
/// </summary>
/// <returns>Sorted list</returns>
public List<AbpModuleInfo> GetSortedModuleListByDependency()
{
var sortedModules = this.SortByDependencies(x => x.Dependencies);
EnsureKernelModuleToBeFirst(sortedModules);
EnsureStartupModuleToBeLast(sortedModules, StartupModuleType);
return sortedModules;
}
可以看到StartModules中首先執行了GetSortedModuleListByDependency方法 該方法是對模塊進行最后一次排序,確保加載順序正確.排序后,則是依次調用模塊生命周期方法。
public virtual void ShutdownModules()
{
Logger.Debug("Shutting down has been started");
var sortedModules = _modules.GetSortedModuleListByDependency();
sortedModules.Reverse();
sortedModules.ForEach(sm => sm.Instance.Shutdown());
Logger.Debug("Shutting down completed.");
}
其實可以看到這里沒有調用ShutDown方法是因為這個方法只有當程序結束的時候才會調用,他被單獨包裝到了ShutdownModules方法中
而ShutdownModules則是app.UseAbp的時候,執行InitializeAbp方法時,把abpBootstrapper與IApplicationLifetime的ApplicationStopping進行綁定事件,釋放的時候會執行ShutdownModules
var applicationLifetime = app.ApplicationServices.GetService<IApplicationLifetime>();
applicationLifetime.ApplicationStopping.Register(() => abpBootstrapper.Dispose());
/// <summary>
/// Disposes the ABP system.
/// </summary>
public virtual void Dispose()
{
if (IsDisposed)
{
return;
}
IsDisposed = true;
_moduleManager?.ShutdownModules();
}