AFNetworking2.0源码解析<三>

本篇说说安全相关的AFSecurityPolicy模块,AFSecurityPolicy用于验证HTTPS请求的证书,先来看看HTTPS的原理和证书相关的几个问题。

HTTPS

HTTPS连接建立过程大致是,客户端和服务端建立一个连接,服务端返回一个证书,客户端里存有各个受信任的证书机构根证书,用这些根证书对服务端 返回的证书进行验证,经验证如果证书是可信任的,就生成一个pre-master  secret,用这个证书的公钥加密后发送给服务端,服务端用私钥解密后得到pre-master secret,再根据某种算法生成master  secret,客户端也同样根据这种算法从pre-master secret生成master secret,随后双方的通信都用这个master  secret对传输数据进行加密解密。

以上是简单过程,中间还有很多细节,详细过程和原理已经有很多文章阐述得很好,就不再复述,推荐一些相关文章:
关于非对称加密算法的原理:RSA算法原理<一><二>
关于整个流程:HTTPS那些事<一><二><三>
关于数字证书:浅析数字证书

这里说下一开始我比较费解的两个问题:

1.证书是怎样验证的?怎样保证中间人不能伪造证书?

首先要知道非对称加密算法的特点,非对称加密有一对公钥私钥,用公钥加密的数据只能通过对应的私钥解密,用私钥加密的数据只能通过对应的公钥解密。

我们来看最简单的情况:一个证书颁发机构(CA),颁发了一个证书A,服务器用这个证书建立https连接。客户端在信任列表里有这个CA机构的根证书。

首先CA机构颁发的证书A里包含有证书内容F,以及证书加密内容F1,加密内容F1就是用这个证书机构的私钥对内容F加密的结果。(这中间还有一次hash算法,略过。)

建立https连接时,服务端返回证书A给客户端,客户端的系统里的CA机构根证书有这个CA机构的公钥,用这个公钥对证书A的加密内容F1解密得 到F2,跟证书A里内容F对比,若相等就通过验证。整个流程大致是:F->CA私钥加密->F1->客户端CA公钥解密->F。 因为中间人不会有CA机构的私钥,客户端无法通过CA公钥解密,所以伪造的证书肯定无法通过验证。

2.什么是SSL Pinning?

可以理解为证书绑定,是指客户端直接保存服务端的证书,建立https连接时直接对比服务端返回的和客户端保存的两个证书是否一样,一样就表明证书 是真的,不再去系统的信任证书机构里寻找验证。这适用于非浏览器应用,因为浏览器跟很多未知服务端打交道,无法把每个服务端的证书都保存到本地,但CS架 构的像手机APP事先已经知道要进行通信的服务端,可以直接在客户端保存这个服务端的证书用于校验。

为什么直接对比就能保证证书没问题?如果中间人从客户端取出证书,再伪装成服务端跟其他客户端通信,它发送给客户端的这个证书不就能通过验证吗?确 实可以通过验证,但后续的流程走不下去,因为下一步客户端会用证书里的公钥加密,中间人没有这个证书的私钥就解不出内容,也就截获不到数据,这个证书的私 钥只有真正的服务端有,中间人伪造证书主要伪造的是公钥。

为什么要用SSL  Pinning?正常的验证方式不够吗?如果服务端的证书是从受信任的的CA机构颁发的,验证是没问题的,但CA机构颁发证书比较昂贵,小企业或个人用户 可能会选择自己颁发证书,这样就无法通过系统受信任的CA机构列表验证这个证书的真伪了,所以需要SSL Pinning这样的方式去验证。

AFSecurityPolicy

NSURLConnection已经封装了https连接的建立、数据的加密解密功能,我们直接使用NSURLConnection是可以访问 https网站的,但NSURLConnection并没有验证证书是否合法,无法避免中间人攻击。要做到真正安全通讯,需要我们手动去验证服务端返回的 证书,AFSecurityPolicy封装了证书验证的过程,让用户可以轻易使用,除了去系统信任CA机构列表验证,还支持SSL  Pinning方式的验证。使用方法:


1

2

3

4

5

6

7

//把服务端证书(需要转换成cer格式)放到APP项目资源里,AFSecurityPolicy会自动寻找根目录下所有cer文件

AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey];

securityPolicy.allowInvalidCertificates = YES;

[AFHTTPRequestOperationManager manager].securityPolicy = securityPolicy;

[manager GET:@"https://example.com/" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {

}];

AFSecurityPolicy分三种验证模式:

AFSSLPinningModeNone

这个模式表示不做SSL pinning,只跟浏览器一样在系统的信任机构列表里验证服务端返回的证书。若证书是信任机构签发的就会通过,若是自己服务器生成的证书,这里是不会通过的。

AFSSLPinningModeCertificate

这个模式表示用证书绑定方式验证证书,需要客户端保存有服务端的证书拷贝,这里验证分两步,第一步验证证书的域名/有效期等信息,第二步是对比服务端返回的证书跟客户端返回的是否一致。

这里还没弄明白第一步的验证是怎么进行的,代码上跟去系统信任机构列表里验证一样调用了SecTrustEvaluate,只是这里的列表换成了客户端保存的那些证书列表。若要验证这个,是否应该把服务端证书的颁发机构根证书也放到客户端里?

AFSSLPinningModePublicKey

这个模式同样是用证书绑定方式验证,客户端要有服务端的证书拷贝,只是验证时只验证证书里的公钥,不验证证书的有效期等信息。只要公钥是正确的,就能保证通信不会被窃听,因为中间人没有私钥,无法解开通过公钥加密的数据。

整个AFSecurityPolicy就是实现这这几种验证方式,剩下的就是实现细节了,详见源码。


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

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

// AFSecurity.m

//

// Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com)

//

// Permission is hereby granted, free of charge, to any person obtaining a copy

// of this software and associated documentation files (the "Software"), to deal

// in the Software without restriction, including without limitation the rights

// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

// copies of the Software, and to permit persons to whom the Software is

// furnished to do so, subject to the following conditions:

//

// The above copyright notice and this permission notice shall be included in

// all copies or substantial portions of the Software.

//

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

// THE SOFTWARE.

 

#import "AFSecurityPolicy.h"

 

// Equivalent of macro in , without causing compiler warning:

// "‘DebugAssert‘ is deprecated: first deprecated in OS X 10.8"

//这两个宏方法用于方便地处理调用各种证书方法过程中出现的错误,出现错误后用goto语句直接跳转到结束语

//关于为什么要用 __builtin_expect (x, 0) 而不直接用 x != 0,是为了CPU执行时的性能优化,见这里:

//http://stackoverflow.com/questions/7346929/why-do-we-use-builtin-expect-when-a-straightforward-way-is-to-use-if-else

#ifndef AF_Require

#define AF_Require(assertion, exceptionLabel)                \

do {                                                     \

if (__builtin_expect(!(assertion), 0)) {             \

goto exceptionLabel;                             \

}                                                    \

while (0)

#endif

 

#ifndef AF_Require_noErr

#define AF_Require_noErr(errorCode, exceptionLabel)          \

do {                                                     \

if (__builtin_expect(0 != (errorCode), 0)) {         \

goto exceptionLabel;                             \

}                                                    \

while (0)

#endif

 

#if !defined(__IPHONE_OS_VERSION_MIN_REQUIRED)

static NSData * AFSecKeyGetData(SecKeyRef key) {

    CFDataRef data = NULL;

 

    AF_Require_noErr(SecItemExport(key, kSecFormatUnknown, kSecItemPemArmour, NULL, &data), _out);

 

    return (__bridge_transfer NSData *)data;

 

_out:

    if (data) {

        CFRelease(data);

    }

 

    return nil;

}

#endif

 

static BOOL AFSecKeyIsEqualToKey(SecKeyRef key1, SecKeyRef key2) {

#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)

    return [(__bridge id)key1 isEqual:(__bridge id)key2];

#else

    return [AFSecKeyGetData(key1) isEqual:AFSecKeyGetData(key2)];

#endif

}

 

//从证书里取public key

static id AFPublicKeyForCertificate(NSData *certificate) {

    id allowedPublicKey = nil;

    SecCertificateRef allowedCertificate;

    SecCertificateRef allowedCertificates[1];

    CFArrayRef tempCertificates = nil;

    SecPolicyRef policy = nil;

    SecTrustRef allowedTrust = nil;

    SecTrustResultType result;

 

    //取证书SecCertificateRef -> 生成证书数组 -> 生成SecTrustRef -> 从SecTrustRef取PublicKey

    allowedCertificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificate);

    AF_Require(allowedCertificate != NULL, _out);

 

    allowedCertificates[0] = allowedCertificate;

    tempCertificates = CFArrayCreate(NULL, (const void **)allowedCertificates, 1, NULL);

 

    policy = SecPolicyCreateBasicX509();

    AF_Require_noErr(SecTrustCreateWithCertificates(tempCertificates, policy, &allowedTrust), _out);

    AF_Require_noErr(SecTrustEvaluate(allowedTrust, &result), _out);

 

    allowedPublicKey = (__bridge_transfer id)SecTrustCopyPublicKey(allowedTrust);

 

_out:

    if (allowedTrust) {

        CFRelease(allowedTrust);

    }

 

    if (policy) {

        CFRelease(policy);

    }

 

    if (tempCertificates) {

        CFRelease(tempCertificates);

    }

 

    if (allowedCertificate) {

        CFRelease(allowedCertificate);

    }

 

    return allowedPublicKey;

}

 

static BOOL AFServerTrustIsValid(SecTrustRef serverTrust) {

    BOOL isValid = NO;

    SecTrustResultType result;

    AF_Require_noErr(SecTrustEvaluate(serverTrust, &result), _out);

 

    //kSecTrustResultUnspecified:证书通过验证,但用户没有设置这些证书是否被信任

    //kSecTrustResultProceed:证书通过验证,用户有操作设置了证书被信任,例如在弹出的是否信任的alert框中选择always trust

    isValid = (result == kSecTrustResultUnspecified || result == kSecTrustResultProceed);

 

_out:

    return isValid;

}

 

//取出服务端返回的所有证书

static NSArray * AFCertificateTrustChainForServerTrust(SecTrustRef serverTrust) {

    CFIndex certificateCount = SecTrustGetCertificateCount(serverTrust);

    NSMutableArray *trustChain = [NSMutableArray arrayWithCapacity:(NSUInteger)certificateCount];

 

    for (CFIndex i = 0; i < certificateCount; i++) {

        SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, i);

        [trustChain addObject:(__bridge_transfer NSData *)SecCertificateCopyData(certificate)];

    }

 

    return [NSArray arrayWithArray:trustChain];

}

 

//取出服务端返回证书里所有的public key

static NSArray * AFPublicKeyTrustChainForServerTrust(SecTrustRef serverTrust) {

    SecPolicyRef policy = SecPolicyCreateBasicX509();

    CFIndex certificateCount = SecTrustGetCertificateCount(serverTrust);

    NSMutableArray *trustChain = [NSMutableArray arrayWithCapacity:(NSUInteger)certificateCount];

    for (CFIndex i = 0; i  生成证书数组 -> 生成SecTrustRef -> 从SecTrustRef取PublicKey

        SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, i);

 

        SecCertificateRef someCertificates[] = {certificate};

        CFArrayRef certificates = CFArrayCreate(NULL, (const void **)someCertificates, 1, NULL);

 

        SecTrustRef trust;

        AF_Require_noErr(SecTrustCreateWithCertificates(certificates, policy, &trust), _out);

 

        SecTrustResultType result;

        AF_Require_noErr(SecTrustEvaluate(trust, &result), _out);

 

        [trustChain addObject:(__bridge_transfer id)SecTrustCopyPublicKey(trust)];

 

    _out:

        if (trust) {

            CFRelease(trust);

        }

 

        if (certificates) {

            CFRelease(certificates);

        }

 

        continue;

    }

    CFRelease(policy);

 

    return [NSArray arrayWithArray:trustChain];

}

 

#pragma mark -

 

@interface AFSecurityPolicy()

@property (readwrite, nonatomic, strong) NSArray *pinnedPublicKeys;

@end

 

@implementation AFSecurityPolicy

 

+ (NSArray *)defaultPinnedCertificates {

    //默认证书列表,遍历根目录下所有.cer文件

    static NSArray *_defaultPinnedCertificates = nil;

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{

        NSBundle *bundle = [NSBundle bundleForClass:[self class]];

        NSArray *paths = [bundle pathsForResourcesOfType:@"cer" inDirectory:@"."];

 

        NSMutableArray *certificates = [NSMutableArray arrayWithCapacity:[paths count]];

        for (NSString *path in paths) {

            NSData *certificateData = [NSData dataWithContentsOfFile:path];

            [certificates addObject:certificateData];

        }

 

        _defaultPinnedCertificates = [[NSArray alloc] initWithArray:certificates];

    });

 

    return _defaultPinnedCertificates;

}

 

+ (instancetype)defaultPolicy {

    AFSecurityPolicy *securityPolicy = [[self alloc] init];

    securityPolicy.SSLPinningMode = AFSSLPinningModeNone;

 

    return securityPolicy;

}

 

+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode {

    AFSecurityPolicy *securityPolicy = [[self alloc] init];

    securityPolicy.SSLPinningMode = pinningMode;

    securityPolicy.validatesDomainName = YES;

    [securityPolicy setPinnedCertificates:[self defaultPinnedCertificates]];

 

    return securityPolicy;

}

 

- (id)init {

    self = [super init];

    if (!self) {

        return nil;

    }

 

    self.validatesCertificateChain = YES;

 

    return self;

}

 

#pragma mark -

 

- (void)setPinnedCertificates:(NSArray *)pinnedCertificates {

    _pinnedCertificates = pinnedCertificates;

 

    if (self.pinnedCertificates) {

        //预先取出public key,用于AFSSLPinningModePublicKey方式的验证

        NSMutableArray *mutablePinnedPublicKeys = [NSMutableArray arrayWithCapacity:[self.pinnedCertificates count]];

        for (NSData *certificate in self.pinnedCertificates) {

            id publicKey = AFPublicKeyForCertificate(certificate);

            if (!publicKey) {

                continue;

            }

            [mutablePinnedPublicKeys addObject:publicKey];

        }

        self.pinnedPublicKeys = [NSArray arrayWithArray:mutablePinnedPublicKeys];

    else {

        self.pinnedPublicKeys = nil;

    }

}

 

#pragma mark -

 

- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust {

    return [self evaluateServerTrust:serverTrust forDomain:nil];

}

 

- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust

                  forDomain:(NSString *)domain

{

    NSMutableArray *policies = [NSMutableArray array];

    if (self.validatesDomainName) {

        [policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)domain)];

    else {

        [policies addObject:(__bridge_transfer id)SecPolicyCreateBasicX509()];

    }

 

    SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies);

 

    //向系统内置的根证书验证服务端返回的证书是否合法

    //若使用自签名证书,这里的验证是会不合法的,需要设allowInvalidCertificates = YES

    if (!AFServerTrustIsValid(serverTrust) && !self.allowInvalidCertificates) {

        return NO;

    }

 

    //取出服务端返回的证书

    NSArray *serverCertificates = AFCertificateTrustChainForServerTrust(serverTrust);

    switch (self.SSLPinningMode) {

        case AFSSLPinningModeNone:

            //两种情况走到这里,

            //一是通过系统证书验证,返回认证成功

            //二是没通过验证,但allowInvalidCertificates = YES,也就是说完全不认证直接返回认证成功

            return YES;

 

            //验证整个证书

        case AFSSLPinningModeCertificate: {

            NSMutableArray *pinnedCertificates = [NSMutableArray array];

            for (NSData *certificateData in self.pinnedCertificates) {

                [pinnedCertificates addObject:(__bridge_transfer id)SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData)];

            }

            //在本地证书里验证服务端返回的证书的有效性

            SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)pinnedCertificates);

            if (!AFServerTrustIsValid(serverTrust)) {

                return NO;

            }

 

            if (!self.validatesCertificateChain) {

                return YES;

            }

 

            //整个证书链都跟本地的证书匹配才给过

            NSUInteger trustedCertificateCount = 0;

            for (NSData *trustChainCertificate in serverCertificates) {

                if ([self.pinnedCertificates containsObject:trustChainCertificate]) {

                    trustedCertificateCount++;

                }

            }

 

            return trustedCertificateCount == [serverCertificates count];

        }

 

            //只验证证书的public key

        case AFSSLPinningModePublicKey: {

            NSUInteger trustedPublicKeyCount = 0;

            NSArray *publicKeys = AFPublicKeyTrustChainForServerTrust(serverTrust);

 

            //如果不用验证整个证书链,取第一个也就是真正会使用的那个证书验证就行

            if (!self.validatesCertificateChain && [publicKeys count] > 0) {

                publicKeys = @[[publicKeys firstObject]];

            }

 

            //在本地证书里搜索相等的public key,记录找到个数

            for (id trustChainPublicKey in publicKeys) {

                for (id pinnedPublicKey in self.pinnedPublicKeys) {

                    if (AFSecKeyIsEqualToKey((__bridge SecKeyRef)trustChainPublicKey, (__bridge SecKeyRef)pinnedPublicKey)) {

                        trustedPublicKeyCount += 1;

                    }

                }

            }

 

            //验证整个证书链的情况:每个public key都在本地找到算验证通过

            //验证单个证书的情况:找到一个算验证通过

            return trustedPublicKeyCount > 0 && ((self.validatesCertificateChain && trustedPublicKeyCount == [serverCertificates count]) || (!self.validatesCertificateChain && trustedPublicKeyCount >= 1));

        }

    }

 

    return NO;

}

 

#pragma mark - NSKeyValueObserving

 

+ (NSSet *)keyPathsForValuesAffectingPinnedPublicKeys {

    return [NSSet setWithObject:@"pinnedCertificates"];

}

 

@end

时间: 2024-10-11 01:26:14

AFNetworking2.0源码解析<三>的相关文章

iOS 8:AFNetworking2.0源码解析 1

源地址:http://blog.cnbang.net/tech/2320/ 最近看AFNetworking2的源码,学习这个知名网络框架的实现,顺便梳理写下文章.AFNetworking2的大体架构和思路在这篇文章已经说得挺清楚了,就不再赘述了,只说说实现的细节.AFNetworking的代码还在不断更新中,我看的是AFNetworking2.3.1. 本篇先看看AFURLConnectionOperation,AFURLConnectionOperation继承自NSOperation,是一个

AFNetworking2.0源码解析

写在前面给大家推荐一个不错的网站 点击打开链接 本文测试例子源码下载地址 最近看AFNetworking2的源码,学习这个知名网络框架的实现,顺便梳理写下文章.AFNetworking的代码还在不断更新中,我看的是AFNetworking2.3.1. 本篇先看看AFURLConnectionOperation,AFURLConnectionOperation继承自NSOperation,是一个封装好的任务单元,在这里构建了NSURLConnection,作为NSURLConnection的del

AFNetworking2.0源码解析&lt;一&gt;

(via:bang's blog) 最近看AFNetworking2的源码,学习这个知名网络框架的实现,顺便梳理写下文章.AFNetworking的代码还在不断更新中,我看的是AFNetworking2.3.1. 本篇先看看AFURLConnectionOperation,AFURLConnectionOperation继承自NSOperation,是一个封装好的任务单元,在这里构建了NSURLConnection,作为NSURLConnection的delegate处理请求回调,做好状态切换,

AFNetworking2.0源码解析&lt;四&gt;

结构 AFURLResponseSerialization负责解析网络返回数据,检查数据是否合法,把NSData数据转成相应的对象,内置的转换器有json,xml,plist,image,用户可以很方便地继承基类AFHTTPResponseSerializer去解析更多的数据格式,AFNetworking这一套响应解析机制结构很简单,主要就是两个方法: 1.-validateResponse:data:error: 基类AFHTTPResponseSerializer的这个方法检测返回的HTTP

AFNetworking2.0源码解析&lt;二&gt;

本篇我们继续来看看AFNetworking的下一个模块 — AFURLRequestSerialization. AFURLRequestSerialization用于帮助构建NSURLRequest,主要做了两个事情: 1.构建普通请求:格式化请求参数,生成HTTP Header. 2.构建multipart请求. 分别看看它在这两点具体做了什么,怎么做的. 1.构建普通请求 A.格式化请求参数 一般我们请求都会按key=value的方式带上各种参数,GET方法参数直接加在URL上,POST方

Android事件总线(二)EventBus3.0源码解析

相关文章 Android事件总线(一)EventBus3.0用法全解析 前言 上一篇我们讲到了EventBus3.0的用法,这一篇我们来讲一下EventBus3.0的源码以及它的利与弊. 1.构造函数 当我们要调用EventBus的功能时,比如注册或者发送事件,总会调用EventBus.getDefault()来获取EventBus实例: public static EventBus getDefault() { if (defaultInstance == null) { synchroniz

EventBus3.0源码解析

本文主要介绍EventBus3.0的源码 EventBus是一个Android事件发布/订阅框架,通过解耦发布者和订阅者简化 Android 事件传递. EventBus使用简单,并将事件发布和订阅充分解耦,从而使代码更简洁. 本文主要从以下几个模块来介绍 1.EventBus使用 2.EventBus注册源码解析 3.EventBus事件分发解析 4.EventBus取消注册解析 一.EventBus使用 1.首先是注册 EventBus.getDefault().register(this)

EventBus 3.0源码解析

现在网上讲解EventBus的文章大多数都是针对2.x版本的,比较老旧,本篇文章希望可以给大家在新版本上面带来帮助. EventBus 是专门为Android设计的用于订阅,发布总线的库,用到这个库的app很多,因为它有很多的优点.比如: 它可以简单Android组件之间的通信 它可以避免了Android四大组件复杂的生命周期处理 它可以让你的代码更为简洁. 先一起了解下如何使用,然后在分析它的源码,知道它的工作原理.我们直接来使用EventBus 3.0,3.x主要的一个新的特性就是使用了注解

OpenJDK1.8.0 源码解析————HashMap的实现(一)

HashMap是Java Collection Framework 的重要成员之一.HashMap是基于哈希表的 Map 接口的实现,此实现提供所有可选的映射操作,映射是以键值对的形式映射:key-value.key——此映射所维护的键的类型,value——映射值的类型,并且允许使用 null 键和 null 值.而且HashMap不保证映射的顺序. 简单的介绍一下HashMap,就开始HashMap的源码分析. 首先简单的介绍一下HashMap里都包含的数据结构.觉得还是先贴一张图比较好,结合