我们如果要实现自己的后台工作者,只需要继承该类,实现 DoWork() 方法即可。
public class TestWorker : PeriodicBackgroundWorkerBase { public TestWorker(AbpTimer timer) : base(timer) { // 每五分钟执行一次。 timer.Period = (int)TimeSpan.FromMinutes(5).TotalMilliseconds; } protected override void DoWork() { Console.WriteLine("后台工作者被执行了。"); } }然后在我们自己模块的 OnPreApplicationInitialization() 方法内解析出后台作业管理器(IBackgroundWorkerManager),调用它的 Add() 方法,将我们定义的 TestWorker 添加到管理器当中即可。
2.2.2 后台工作者管理器所有的后台工作者都是通过 IBackgroundWorkerManager 进行管理的,它提供了 StartAsync()、StopAsync()、Add() 方法。前面两个方法就是 IRunnable 接口定义的,后台工作者管理器直接集成了该接口,后面的 Add() 方法就是用来动态添加我们的后台工作者。
后台工作者管理器的默认实现是 BackgroundWorkerManager 类型,它内部做的事情很简单,就是维护一个后台工作者集合。每当调用 StartAsync() 或 StopAsync() 方法的时候,都从这个集合遍历后台工作者,执行他们的启动和停止方法。
这里值得注意的一点是,当我们调用 Add() 方法添加了一个后台工作者之后,后台工作者管理器就会启动这个后台工作者。
public class BackgroundWorkerManager : IBackgroundWorkerManager, ISingletonDependency, IDisposable { protected bool IsRunning { get; private set; } private bool _isDisposed; private readonly List<IBackgroundWorker> _backgroundWorkers; public BackgroundWorkerManager() { _backgroundWorkers = new List<IBackgroundWorker>(); } public virtual void Add(IBackgroundWorker worker) { _backgroundWorkers.Add(worker); // 如果当前后台工作者管理器还处于运行状态,则调用工作者的 StartAsync() 方法启动。 if (IsRunning) { AsyncHelper.RunSync( () => worker.StartAsync() ); } } public virtual void Dispose() { if (_isDisposed) { return; } _isDisposed = true; //TODO: ??? } // 启动,则遍历集合启动。 public virtual async Task StartAsync(CancellationToken cancellationToken = default) { IsRunning = true; foreach (var worker in _backgroundWorkers) { await worker.StartAsync(cancellationToken); } } // 停止, 则遍历集合停止。 public virtual async Task StopAsync(CancellationToken cancellationToken = default) { IsRunning = false; foreach (var worker in _backgroundWorkers) { await worker.StopAsync(cancellationToken); } } }上述代码其实存在一个问题,即后台工作者被释放以后,是否还能执行 Add() 操作。参考我 之前的文章 ,其实当对象被释放之后,就应该抛出 ObjectDisposedException 异常。
2.3 后台作业比起后台工作者,我们执行一次性任务的时候,一般会使用后台作业进行处理。比起只能设置固定周期的 PeriodicBackgroundWorkerBase ,集成了 Hangfire 的后台作业管理器,能够让我们使用 Cron 表达式,更加灵活地设置任务的执行周期。
2.3.1 模块的构造关于后台作业的模块,我们需要说道两处。第一处是位于 Volo.Abp.BackgroundJobs.Abstractions 项目的 AbpBackgroundJobsAbstractionsModule ,第二出则是位于 Volo.Abp.BackgroundJobs 项目的 AbpBackgroundJobsModule 。
AbpBackgroundJobsAbstractionsModule 的主要行为是将符合条件的后台作业,添加到 AbpBackgroundJobOptions 配置当中,以便后续进行使用。
public override void PreConfigureServices(ServiceConfigurationContext context) { RegisterJobs(context.Services); } private static void RegisterJobs(IServiceCollection services) { var jobTypes = new List<Type>(); // 如果注册的类型符合 IBackgroundJob<> 泛型,则添加到集合当中。 services.OnRegistred(context => { if (ReflectionHelper.IsAssignableToGenericType(context.ImplementationType, typeof(IBackgroundJob<>))) { jobTypes.Add(context.ImplementationType); } }); services.Configure<AbpBackgroundJobOptions>(options => { // 将数据赋值给配置类。 foreach (var jobType in jobTypes) { options.AddJob(jobType); } }); }Volo.Abp.BackgroundJobs 内部是 ABP vNext 为我们提供的 默认后台作业管理器,这个后台作业管理器 本质上是一个后台工作者。