添加服务与注册中间件
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();
}