Commit 71edd900 authored by 阿星Plus's avatar 阿星Plus

Modules

parent 90d4996a
using System;
namespace Plus.Modules
{
/// <summary>
/// 用于定义模块间的依赖关系
/// </summary>
public class DependsOnAttribute : Attribute
{
public Type[] DependedModuleTypes { get; private set; }
public DependsOnAttribute(params Type[] dependedModuleTypes)
{
DependedModuleTypes = dependedModuleTypes;
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
namespace Plus.Modules
{
/// <summary>
/// 模块管理接口
/// </summary>
public interface IPlusModuleManager
{
PlusModuleInfo StartupModule { get; }
IReadOnlyList<PlusModuleInfo> Modules { get; }
void Initialize(Type startupModule);
void StartModules();
void ShutdownModules();
}
}
\ No newline at end of file
using Castle.Core.Logging;
using Plus.Collections;
using Plus.Configuration.Startup;
using Plus.Dependency;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Plus.Modules
{
public abstract class PlusModule
{
protected internal IIocManager IocManager { get; internal set; }
protected internal IPlusStartupConfiguration Configuration { get; internal set; }
public ILogger Logger { get; set; }
protected PlusModule()
{
Logger = NullLogger.Instance;
}
/// <summary>
/// 启动时初始化事件,在依赖注入注册之前运行。
/// </summary>
public virtual void PreInitialize()
{
}
/// <summary>
/// 用于注册此模块的依赖项
/// </summary>
public virtual void Initialize()
{
}
/// <summary>
/// 最后在应用程序启动时调用此方法
/// </summary>
public virtual void PostInitialize()
{
}
/// <summary>
/// 在关闭应用程序时调用此方法
/// </summary>
public virtual void Shutdown()
{
}
public virtual Assembly[] GetAdditionalAssemblies()
{
return new Assembly[0];
}
public static bool IsPlusModule(Type type)
{
var typeInfo = type.GetTypeInfo();
return
typeInfo.IsClass &&
!typeInfo.IsAbstract &&
!typeInfo.IsGenericType &&
typeof(PlusModule).IsAssignableFrom(type);
}
/// <summary>
/// 查找模块的依赖模块
/// </summary>
public static List<Type> FindDependedModuleTypes(Type moduleType)
{
if (!IsPlusModule(moduleType))
{
throw new PlusInitializationException("This type is not an Plus module: " + moduleType.AssemblyQualifiedName);
}
var list = new List<Type>();
if (moduleType.GetTypeInfo().IsDefined(typeof(DependsOnAttribute), true))
{
var dependsOnAttributes = moduleType.GetTypeInfo().GetCustomAttributes(typeof(DependsOnAttribute), true).Cast<DependsOnAttribute>();
foreach (var dependsOnAttribute in dependsOnAttributes)
{
foreach (var dependedModuleType in dependsOnAttribute.DependedModuleTypes)
{
list.Add(dependedModuleType);
}
}
}
return list;
}
public static List<Type> FindDependedModuleTypesRecursivelyIncludingGivenModule(Type moduleType)
{
var list = new List<Type>();
AddModuleAndDependenciesRecursively(list, moduleType);
list.AddIfNotContains(typeof(PlusLeadershipModule));
return list;
}
private static void AddModuleAndDependenciesRecursively(List<Type> modules, Type module)
{
if (!IsPlusModule(module))
{
throw new PlusInitializationException("This type is not an Plus module: " + module.AssemblyQualifiedName);
}
if (modules.Contains(module))
{
return;
}
modules.Add(module);
var dependedModules = FindDependedModuleTypes(module);
foreach (var dependedModule in dependedModules)
{
AddModuleAndDependenciesRecursively(modules, dependedModule);
}
}
}
}
\ No newline at end of file
using Plus.Collections;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Plus.Modules
{
/// <summary>
/// 将对象存储为字典
/// </summary>
public class PlusModuleCollection : List<PlusModuleInfo>
{
public Type StartupModuleType { get; }
public PlusModuleCollection(Type startupModuleType)
{
StartupModuleType = startupModuleType;
}
public TModule GetModule<TModule>() where TModule : PlusModule
{
var plusModuleInfo = this.FirstOrDefault((PlusModuleInfo x) => x.Type == typeof(TModule));
if (plusModuleInfo == null)
{
throw new PlusException("Can not find module for " + typeof(TModule).FullName);
}
return (TModule)plusModuleInfo.Instance;
}
public List<PlusModuleInfo> GetSortedModuleListByDependency()
{
var sortedModules = this.SortByDependencies(x => x.Dependencies);
EnsureKernelModuleToBeFirst(sortedModules);
EnsureStartupModuleToBeLast(sortedModules, StartupModuleType);
return sortedModules;
}
public static void EnsureKernelModuleToBeFirst(List<PlusModuleInfo> modules)
{
var kernelModuleIndex = modules.FindIndex(m => m.Type == typeof(PlusLeadershipModule));
if (kernelModuleIndex <= 0)
{
return;
}
var kernelModule = modules[kernelModuleIndex];
modules.RemoveAt(kernelModuleIndex);
modules.Insert(0, kernelModule);
}
public static void EnsureStartupModuleToBeLast(List<PlusModuleInfo> modules, Type startupModuleType)
{
var startupModuleIndex = modules.FindIndex(m => m.Type == startupModuleType);
if (startupModuleIndex >= modules.Count - 1)
{
return;
}
var startupModule = modules[startupModuleIndex];
modules.RemoveAt(startupModuleIndex);
modules.Add(startupModule);
}
public void EnsureKernelModuleToBeFirst()
{
EnsureKernelModuleToBeFirst(this);
}
public void EnsureStartupModuleToBeLast()
{
EnsureStartupModuleToBeLast(this, StartupModuleType);
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Reflection;
namespace Plus.Modules
{
public class PlusModuleInfo
{
public Assembly Assembly { get; }
public Type Type { get; }
public PlusModule Instance { get; }
public bool IsLoadedAsPlugIn { get; }
public List<PlusModuleInfo> Dependencies { get; }
public PlusModuleInfo(Type type, PlusModule instance)
{
Type = type;
Instance = instance;
Assembly = Type.GetTypeInfo().Assembly;
Dependencies = new List<PlusModuleInfo>();
}
public PlusModuleInfo(Type type, PlusModule instance, bool isLoadedAsPlugIn)
{
Type = type;
Instance = instance;
IsLoadedAsPlugIn = isLoadedAsPlugIn;
Assembly = Type.GetTypeInfo().Assembly;
Dependencies = new List<PlusModuleInfo>();
}
public override string ToString()
{
return Type.AssemblyQualifiedName ?? Type.FullName;
}
}
}
\ No newline at end of file
using Castle.Core.Logging;
using Plus.Configuration.Startup;
using Plus.Dependency;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
namespace Plus.Modules
{
/// <summary>
/// 模块管理
/// </summary>
public class PlusModuleManager : IPlusModuleManager
{
public PlusModuleInfo StartupModule { get; private set; }
public IReadOnlyList<PlusModuleInfo> Modules => _modules.ToImmutableList();
public ILogger Logger { get; set; }
private PlusModuleCollection _modules;
private readonly IIocManager _iocManager;
private readonly IPlusStartupConfiguration _startupConfiguration;
public PlusModuleManager(IIocManager iocManager, IPlusStartupConfiguration startupConfiguration)
{
_iocManager = iocManager;
_startupConfiguration = startupConfiguration;
Logger = NullLogger.Instance;
}
public virtual void Initialize(Type startupModule)
{
_modules = new PlusModuleCollection(startupModule);
LoadAllModules();
}
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());
}
public virtual void ShutdownModules()
{
Logger.Debug("开始关闭模块");
List<PlusModuleInfo> sortedModuleListByDependency = _modules.GetSortedModuleListByDependency();
sortedModuleListByDependency.Reverse();
sortedModuleListByDependency.ForEach(delegate (PlusModuleInfo sm)
{
sm.Instance.Shutdown();
});
Logger.Debug("模块关闭完成");
}
private void LoadAllModules()
{
Logger.Debug("加载模块...");
var moduleTypes = FindAllModuleTypes().Distinct().ToList();
Logger.Debug("找到 " + moduleTypes.Count + " 个模块.");
RegisterModules(moduleTypes);
CreateModules(moduleTypes, moduleTypes);
_modules.EnsureKernelModuleToBeFirst();
_modules.EnsureStartupModuleToBeLast();
SetDependencies();
Logger.DebugFormat("{0} 个模块已加载.", _modules.Count);
}
private List<Type> FindAllModuleTypes()
{
return PlusModule.FindDependedModuleTypesRecursivelyIncludingGivenModule(_modules.StartupModuleType);
}
private void CreateModules(ICollection<Type> moduleTypes, List<Type> plugInModuleTypes)
{
foreach (var moduleType in moduleTypes)
{
if (!(_iocManager.Resolve(moduleType) is PlusModule moduleObject))
{
throw new PlusInitializationException("从类型不是 Plus 模块: " + moduleType.AssemblyQualifiedName);
}
moduleObject.IocManager = _iocManager;
moduleObject.Configuration = _iocManager.Resolve<IPlusStartupConfiguration>();
var moduleInfo = new PlusModuleInfo(moduleType, moduleObject, plugInModuleTypes.Contains(moduleType));
_modules.Add(moduleInfo);
if (moduleType == _modules.StartupModuleType)
{
StartupModule = moduleInfo;
}
Logger.DebugFormat("加载模块: " + moduleType.AssemblyQualifiedName);
}
}
private void RegisterModules(ICollection<Type> moduleTypes)
{
foreach (Type moduleType in moduleTypes)
{
_iocManager.RegisterIfNot(moduleType);
}
}
private void SetDependencies()
{
foreach (PlusModuleInfo module in _modules)
{
module.Dependencies.Clear();
foreach (Type dependedModuleType in PlusModule.FindDependedModuleTypes(module.Type))
{
PlusModuleInfo PlusModuleInfo = _modules.FirstOrDefault((PlusModuleInfo m) => m.Type == dependedModuleType);
if (PlusModuleInfo == null)
{
throw new PlusInitializationException("无法找到依赖的模块 " + dependedModuleType.AssemblyQualifiedName + " for " + module.Type.AssemblyQualifiedName);
}
if (module.Dependencies.FirstOrDefault((PlusModuleInfo dm) => dm.Type == dependedModuleType) == null)
{
module.Dependencies.Add(PlusModuleInfo);
}
}
}
}
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment