0%

应用启动与应用服务

应用启动

随着应用各种接入第三方 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 != ServiceTask 定义的是时机,通过 Task 来启动 ServiceService 是可以在整个应用生命周期都存在(当然也可以中途被销毁),但是 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 框架介绍