案例实战:实现互联网验证码保护服务
通过对前面的线程池理论的学习,我们通过一步一图配合源码,层层递进的方式对线程池进行了抽丝剥茧式的剖析。想必你对线程池已经建立了深入全面的认识,并且想要在实战中应用线程池解决实际问题了。那么我们本节就满足你的想法,让我们利用线程池实现互联网验证码保护服务。
业务背景与实现思路
首先介绍一下业务背景,假设我们的系统是一个短视频播放网站,每个新加入的用户都需要注册账号并绑定手机号。为了验证用户身份的可靠性实现手机号绑定,我们的系统会发送一条验证码到用户注册时填写的手机上,用户在有效期内填写验证码进行认证,通过认证之后即绑定该手机号到用户注册的账号上。完整的业务流程如图1所示。
图1
当用户注册账户成功之后,需要发送短信验证码,因此账户注册流程中会调用验证码发送模块提供的验证码发送服务。因此我们实现一个名为AsyncSmsVerificationCodePusher的服务,对外提供验证码生成和响应的短信下发能力。最终调用第三方的短信推送服务,触达用户。这里要注意的是,对接第三方短信推送服务,需要提供接收短信的用户手机号、验证码内容等信息,如图2所示。
图2
由于用户注册流程中,不止发送短信,还可能执行其他的业务流程。并且发送短信本身属于跨网络服务调用,本质上是一种网络I/O操作,因此如果直接在业务主线程上直接同步阻塞式的调用验证码发送模块的发送短信接口,会影响到整个业务流程的处理效率,如果单位时间内大量用户涌入,会造成注册接口响应缓慢。这种情况肯定是会引起大量客诉的,这对于一个处于用户拉新阶段的视频网站来说是一个比较严重的事件,需要极力去避免。同步方式发送短信验证码的业务流程如图3所示。
图3
因此我们考虑通过异步方式去进行验证码发送,在AsyncSmsVerificationCodePusher类中通过定义一个专门的验证码发送线程池来实现验证码短信的发送。为了提高效率,我们定义一个专门的验证码发送任务SmsVerificationCodeTask来实现验证码生成、以及发送业务。代码调用过程如图4所示。
图4
对流程熟悉了之后,我们就开始编写代码实现这个业务流程吧。首先定义验证码短信发送线程池,命名为SMS_SEND_THREAD_POOL,如图5所示。
图5
上图5中,我们定义了一个自定义线程池,设置核心线程数为CPU个数,最大线程数为50,这么设置的原因在于发送短信是一个I/O密集型的业务。
我们还定义了方法sendSmsVerificationCode,通过线程池提交短信验证码发送任务SmsVerificationCodeTask。接着看一下SmsVerificationCodeTask的代码实现。
图6
图6中SmsVerificationCodeTask实现了Runnable接口,在run方法中,我们实现了验证码发送业务逻辑:
首先通过ThreadLocalRandom线程安全方式生成6位随机数,然后格式化为字符串;然后通过sendMessage方法将短信发送至对应的手机号,并进行日志打印。
我们接着编写业务代码调用短信发送服务模拟发送短信验证码,代码如图7所示。
图7
我们先创建了一个AsyncSmsVerificationCodePusher实例对象,然后生成了3个SmsVerificationCodeTask验证码发送任务,最后通过调用asyncSmsVerificationCodePusher对象引用的sendSmsVerificationCode方法通过自定义线程池提交了短信验证码发送任务。日志打印如图8所示。
图8
到此为止,我们就通过线程池实现了发送互联网短信验证码保护服务。核心就是通过自定义线程池,异步提交验证码发送任务,实现了业务流程与验证码发送流程的解耦,这种开发方式在实战中极为常用,希望你能够掌握并灵活运用。