iOS使用“注解”实现“微服务”路由

阅读本文大概需要 4.55 分钟

前言

大家知道 Objective-C 本身是没有支持注解功能的,但有时使用注解将大幅提高效率,同时让代码更简单易懂。特别是今天要介绍的一个关于“微服务”注册的场景。

什么是“微服务”

微服务是目前后端提的比较多的一个东西,从广义上来说就是一个去中心化的开发模式,通过各个组件的自注册,达到服务分发的效果。

那么跟客户端有什么关系呢?有一个很具体的例子就是“界面路由”。这也是近期大家谈的比较多的一个事(包括我最近也在做),相信很多同学并不陌生。具体的做法就是,我们会对各个界面定义一个ID,比如首页-main、详情页-detail、关于页-about等等,然后通过路由管理器来分发,从而展示指定的Controller。

路由方案一

一个比较简单的做法是建立ID到Controller的映射表,然后根据Controller类名创建对象,进行push操作:

NSString *controllerClazz = [routeConfig clazzForID:@"main"];
Class controllerClass = NSClassFromString(controllerClazz);
// check the controller class...
UIViewController *controller = [[controllerClass alloc] init];
// initialize parameters...
[topVC pushViewController:controller animated:YES];

这种做法的好处是足够简单,但是规则太过于死板,无法根据业务做定制。
一种改进的方案是做一个分发器,建立ID到展示界面方法的映射。

路由方案二

@implement RouterDispatcher

- (void)dispatchMain {
    // 定制
    [topVC pushViewController:mainViewController animated:YES];
}

- (void)dispatchDetail {
    // 定制
    [topVC pushViewController:detailViewController animated:YES];
}

@end

这个方案增加了一层中转,方便业务的定制,不过缺点也是明显的,大量的代码都堆砌在了 RouterDispatcher 类里。这意味着每次新增界面或者修改业务都需要改动到这个类,显然作为一个底层核心库,我们希望最大限度地剥离业务以避免改动与保障稳定性。如何去掉这个中心化,就利用到了我们前文所提的“微服务”思想。

微服务路由

作为底层框架,我们不想关心一个ID具体是如何被路由的,我们只提供这种分发能力,具体的业务通过上层注册来实现。以下面的代码为例:

@implement RouterDispatcher

static NSMutableDictionary<NSString */*page*/, NSString */*dispatcherClazz*/> kPages;

+ (void)registerPage:(NSString *)pageID {
    if (kPages == nil) {
        kPages = [[NSMutableDictionary alloc] init];
    }
    kPages[page] = NSStringFromClass([self class]);
}

+ (void)dispatchPage:(NSString *)pageID {
    NSString *dispatcherClazz = kPages[pageID];
    if (dispatcherClazz == nil) {
        return;
    }
    Class dispatcherClass = NSClassFromString(dispatcherClazz);
    RouterDispatcher dispatcher = [[dispatcherClass alloc] init];
    [dispatcher dispatch];
}

@end

我们只提供了 registerPage 注册方法以及 dispatchPage 分发方法。dispatchPage方法的实现很简单:根据已注册的分发器做转发。

那么如何以“微服务”的形式做注册呢?

我们注意到了 NSObjectload 方法,这个方法会在类被加载的时候执行,显然用来做服务注册是再合适不过了——类被加载了意味着这个类可用,与此同时注册上服务意味着服务也是可用的。这也符合“微服务”启动自注册的理念。

终上,要完成对 "main" 的路由,只需要以下 3 个步骤:

  1. 继承 RouterDispatcher 实现 MainRouterDispatcher
  2. 使用 load 来注册 "main" 服务
  3. 实现 dispatch 完成路由分发
@implement MainRouterDispatcher

+ (void)load {
    [self registerPage:@"main"];
}

- (void)dispatch {
    // 业务逻辑
    [topVC pushViewController:mainViewController animated:YES];
}

@end

好了,现在底层框架基本OK了,但是对于一线开发来说,重复的写 + (void) load 显然是件很啰嗦的事,而且看上去不够醒目,容易被忽略。那么这个时候就是“注解”一展身手的时候了。

使用注解

最终的效果是:


@page(@"main")
- (void)dispatch {
    // Do stuff...
}

首先,注解的基本格式为 @annotation(attr),官方常见的一些 @ 打头的关键字包括:

  • @property
  • @synthesize
  • @dynamic
  • @interface
  • @implement

我们可以使用宏来做替换,比如定义了:

#define my_property property

就可以使用 @my_property 来替代 @property,达到一样的效果。

但是这里有一个前提,我们选用的 @xx 需要在 @implement @end 区间内部来使用,比较符合的是 @synthesize@dynamic,但缺点是其后面必须带上一个属性,比如 @synthesize title; ,如果当前类没有属性就无法定义。

这个时候,我们注意到了一个不常用的 @compatibility_alias。这个注解是用于类名兼容的,一般开发不会用到。不过在框架开发中可能派上用场。

讲到这里,顺便提下我在开发 Pbind 过程中的一个小插曲。当时Pbind内部实现了一个类 PBRequest 用来统一封装API请求,突然有一天发现 Apple 的私有库 ProtocolBuffer.framework 也有这么一个同名的类,控制台输出警告:“类名冲突,系统会选择其中一个而忽略另一个”。这就尴尬了,谁知道你哪天选哪个呢?保险起见,只能自己换掉,初步的想法是用 _ PBRequest 替换 PBRequest,但是回头想想这个类是面向开发者的,我一大波的 PB 打头类,突然碰上一个 _ PB 打头的不是很奇怪么?偶然间发现了 @compatibility_alias 神器,两步即可搞定:

  1. 修改 PBRequest 为 _PBRequest (.h 跟 .m文件)
  2. 在修改后的 _PBRequest.h 文件中加上一句:
    @compatibility_alias PBRequest _PBRequest;

于是,其他的 所有 引用到 PBRequest 的地方都不需要改动,甚至接入这个库的使用者依然可以直接使用 PBRequest,因为大家都处于同一个编译环境下。

OK,回到我们的话题上来,我们来使用这个神奇的 @compatibility_alias 完成我们的“注解”:

#define page(_pageID_) \
compatibility_alias _RouterDispatcher RouterDispatcher; \
+ (void)load { \
    [self registerPage:_pageID_]; \
}

通过上述定义,使用 @page(@"main") 时将会被展开:

@compatibility_alias _RouterDispatcher RouterDispatcher; 
+ (void)load { 
    [self registerPage:@"main"]; 
}

相比我们最初给出的代码,这里唯一添加的一句“废话”就是:@compatibility_alias _RouterDispatcher RouterDispatcher; 即允许你在当前环境下使用 _“RouterDispatcher” 类,显然你不会用到它。不过我们也不需要过多地关注它,这句代码是在编译时做的,并不会影响到运行时。

OK,现在我们可以很方便地使用这个注解在任何地方,完成各个界面的路由。更重要的是 load 方法是系统加载类时自动触发的,这意味着你可以把分发器实现在各个地方,包括你所实施的组件化的某一个 Library 或者 Framework 里。

总结

本文介绍了“微服务”的基本思想,通过 load 方法实现了 iOS 微服务组件的自注册。再结合宏与 @compatibility_alias 完成了 iOS 的“注解”功能。达到“注解”实现“微服务”路由的效果:


@page(@"main")
- (void)dispatch {
    // Do stuff...
}

Pbind 是一个支持 LiveLoad 的高度可配置化框架,以上代码实践均源自 Pbind 的开发过程,关于注解注册服务的部分还可以参考 Pbind 源码中的 PBAction 以及 PBClient 的实现。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,542评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,596评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,021评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,682评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,792评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,985评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,107评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,845评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,299评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,612评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,747评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,441评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,072评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,828评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,069评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,545评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,658评论 2 350

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,637评论 18 139
  • 1. 微服务架构介绍 1.1 什么是微服务架构? 形像一点来说,微服务架构就像搭积木,每个微服务都是一个零件,并使...
    静修佛缘阅读 6,635评论 0 39
  • 微服务最近非常流行,各大互联网公司纷纷采用微服务架构体系,微服务架构模式正在为敏捷部署以及复杂企业应用实施提供巨大...
    Sting阅读 9,069评论 0 57
  • 我们的人生,有多少自由可言。 父母一辈的人,用功读书的人,成了公务员;头脑灵活的人,成了企业家;踏实肯干的人,成了...
    普通先生阅读 636评论 2 0
  • 毫无疑问,现在对于人们来说,和手机一样必不可少的,便是装在手机里面的微信了。微信的普及,让博客与微博渐渐淡出了我们...
    默默huangjuan阅读 704评论 19 7