ABP启动流程分析
添加服务与注册中间件
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();
}
ABP启动流程分析的更多相关文章
- u-boot启动流程分析(2)_板级(board)部分
转自:http://www.wowotech.net/u-boot/boot_flow_2.html 目录: 1. 前言 2. Generic Board 3. _main 4. global dat ...
- u-boot启动流程分析(1)_平台相关部分
转自:http://www.wowotech.net/u-boot/boot_flow_1.html 1. 前言 本文将结合u-boot的“board—>machine—>arch—> ...
- Cocos2d-x3.3RC0的Android编译Activity启动流程分析
本文将从引擎源代码Jni分析Cocos2d-x3.3RC0的Android Activity的启动流程,以下是具体分析. 1.引擎源代码Jni.部分Java层和C++层代码分析 watermark/2 ...
- Netty 拆包粘包和服务启动流程分析
Netty 拆包粘包和服务启动流程分析 通过本章学习,笔者希望你能掌握EventLoopGroup的工作流程,ServerBootstrap的启动流程,ChannelPipeline是如何操作管理Ch ...
- Uboot启动流程分析(转载)
最近一段时间一直在做uboot移植相关的工作,需要将uboot-2016-7移植到单位设计的ARMv7的处理器上.正好元旦放假三天闲来无事,有段完整的时间来整理下最近的工作成果.之前在学习uboot时 ...
- Storm集群启动流程分析
Storm集群启动流程分析 程序员 1.客户端运行storm nimbus时,会调用storm的python脚本,该脚本中为每个命令编写了一个方法,每个方法都可以生成一条相应的Java命令. 命令格式 ...
- 【转】Netty 拆包粘包和服务启动流程分析
原文:https://www.cnblogs.com/itdragon/archive/2018/01/29/8365694.html Netty 拆包粘包和服务启动流程分析 通过本章学习,笔者希望你 ...
- ubuntu为什么没有/etc/inittab文件? 深究ubuntu的启动流程分析
Linux 内核启动 init ,init进程ID是1,是所有进程的父进程,所有进程由它控制. Ubuntu 的启动由upstart控制,自9.10后不再使用/etc/event.d目录的配置文件,改 ...
- imx6 uboot启动流程分析
参考http://blog.csdn.net/skyflying2012/article/details/25804209 这里以imx6平台为例,分析uboot启动流程对于任何程序,入口函数是在链接 ...
随机推荐
- Unix环境高级编程第三版中实例代码如何在自己的linux上运行的问题
学习Linux已经有2个月了,最近被期末考试把进度耽误了,前几天把Unix环境高级编程看了两章,感觉对Linux的整体有了一些思路,今天尝试着对第一章涉及到的一个简单的交互式shell编译运行一下,结 ...
- python中装饰器你真的理解吗?
def w1(func): print('装饰器1....') def w1_in(): print('w1_in.....') func() return w1_in def w2(func): p ...
- vue 后台交互数据-编辑页面
思路~点击编辑按钮,需要获取当前列的id,然后根据id请求后台当前id的数据 1.~~ 2.接收id,并请求页面 获取数据
- 九度OJ 1059:abc (基础题)
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:3642 解决:2869 题目描述: 设a.b.c均是0到9之间的数字,abc.bcc是两个三位数,且有:abc+bcc=532.求满足条件的 ...
- Tomcat学习笔记【2】--- Tomcat安装、环境变量配置、启动和关闭
本文主要讲Tomcat的安装和配置. 一 Tomcat安装 1.1 下载 下载地址:http://tomcat.apache.org/ 1.2 安装 Tomcat是不需要安装的,解压压缩包即可. 在安 ...
- 【题解】[CJOI2019]Cipher
[题解][CJOI2019]Cipher 题目描述 给定你\(p\)进制数\(s\),\(p \le 9+26\),求对于十进制数\(k\),求\(k^s \equiv ? \mod m\) 数据范围 ...
- centos设置固定IP方法
首先网络模式设为桥接 [root@centos64 ~]# vi /etc/sysconfig/network-scripts/ifcfg-eth0 DEVICE=eth0HWADDR=00:0C:2 ...
- Java for LeetCode 112 Path Sum
Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all ...
- Swift 烧脑体操(四) - map 和 flatMap
前言 Swift 其实比 Objective-C 复杂很多,相对于出生于上世纪 80 年代的 Objective-C 来说,Swift 融入了大量新特性.这也使得我们学习掌握这门语言变得相对来说更加困 ...
- Python环境问题
http://installion.co.uk/ubuntu/precise/main/p/python3.2/uninstall/index.html