应用启动
随着应用各种接入第三方 SDK 与自身服务的增多,启动流程也越来复杂,难以管理与监控。因此会有这些问题:
- 服务的列表,我们不知道有哪些服务
- 服务的依赖问题,有些服务会依赖另一个前置服务
- 服务的异步执行,为了启动的性能优化
- 服务的条件执行,有时候服务的启动需要符合一些条件
- 服务的启动耗时 ,我们不知道启动这个服务的启动耗时
我们应该如何管理启动流程?将启动过程看做多个任务的执行过程。通过对启动任务的管理达到管理启动流程的目的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| @interface MPIBootTask : NSObject
/** 启动任务的名字。 */ @property (nonatomic, copy, readonly) NSString *name;
/** 启动任务需要在哪个阶段执行。 */ @property (nonatomic, assign, readonly) MPIBootPhase bootPhase;
/** 启动任务执行的优先级,优先级越高的越早执行。 注意:优先级只有当 task 的 bootPhase 相同时才有意义。 */ @property (nonatomic, assign, readonly) NSInteger priority;
/** 是否能够异步执行。 */ @property (nonatomic, assign, readonly) BOOL asynchronous;
/** * 如果asynchronous为YES,可以指定priority设置异步启动服务的线程优先级。取值为dispatch_get_global_queue的优先级取值。 * DISPATCH_QUEUE_PRIORITY_HIGH * DISPATCH_QUEUE_PRIORITY_DEFAULT * DISPATCH_QUEUE_PRIORITY_LOW * DISPATCH_QUEUE_PRIORITY_BACKGROUND */ @property (nonatomic, assign, readonly) long dispatchQueuePriority;
/** 是否执行过。 */ @property (nonatomic, assign, readonly, getter=isExecuted) BOOL executed;
- (instancetype)initWithName:(NSString *)name bootPhase:(MPIBootPhase)bootPhase priority:(NSInteger)priority asynchronous:(BOOL)asynchronous dispatchQueuePriority:(long)dispatchQueuePriority;
/** 是否能够执行 task。 */ - (BOOL)canExecute;
/** 执行 task。 */ - (void)execute;
/** 需要执行的内容。 */ - (void)main;
@end
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @interface MPIBootLoader : NSObject
- (void)appendTask:(MPIBootTask *)task;
- (void)appendTasks:(NSArray<MPIBootTask *> *)tasks;
- (void)executeTasksWithBootPhase:(MPIBootPhase)bootPhase;
- (void)executeAllTasks;
- (nullable MPIBootTask *)taskForName:(NSString *)name;
- (void)executeTaskWithName:(NSString *)name;
@end
|
通过 MPIBootLoader
持有及管理 Task
,继而通过 Task
来定义执行阶段、优先级、是否异步执行等。值得注意的是,每个 Task
只会被执行一次。
应用服务
这里先说明一个概念问题,Task
!= Service
。 Task
定义的是时机,通过 Task
来启动 Service
。 Service
是可以在整个应用生命周期都存在(当然也可以中途被销毁),但是 Task
不会有副作用,执行过后就代表已经完成和结束。
举一个以前的错误例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @implementation MPIBootTestTask
- (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; }
- (void)main { [Foo start]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveNotification:) name:MPITestNotification object:nil]; }
#pragma mark - Notification
- (void)didReceiveNotification:(NSNotification *)notification { [Foo update]; }
@end
|
这个例子中,我们在 Task
中监听了通知,等于执行完 Task
后会产生副作用,并且假如以后需要移出通知,那就需要为 Task
增加移出通知的方法,这就违背了 Task
的职责。
因此我们引申出 Service
的概念,通过 Service
来追踪应用状态的改变。下面是 Service
的头文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| typedef NSString *MPIServiceName;
/** * \code MPIMicroService 代表一个服务。 */ @protocol MPIService <NSObject>
@required
/** * 启动一个服务。框架在完成初始化操作后,会调用该方法。 * * 如果一个服务要启动一个应用,必须在该法被调用之后,才能启动其它的应用。 */ - (void)start;
@optional
/** * 服务已经完成创建。 */ - (void)didCreate;
/** * 服务即将释放。 */ - (void)willDestroy;
@end
|
当然 Service
的作用不止于此,我们也可以通过 Service
做模块化处理。
1 2 3 4 5
| @protocol DemoService <MPIService>
- (void)doTask;
@end
|
1 2
| id<DemoService> service = MPIApplicationGetServiceByName(@"DemoService"); [service doTask];
|
总结
通过 Task
管理及监控启动流程,使用 Service
追踪应用状态改变和模块化处理。
参考资料
mPaaS 框架介绍