Service 层需要实现接口吗
前几天看技术交流群的话题,又刷到了「Service 层和 Dao 层真的有必要每个类都加上接口吗?」这个问题,之前简单回答了一波,给出的观点是「看情况」
现在结合我参与的项目以及阅读的一些项目源码来看,如果项目中使用了像 Spring 这样的依赖注入框架,那可以不用接口!
先来说说为什么使用了依赖注入框架以后,可以不使用接口。
前几天看技术交流群的话题,又刷到了「Service 层和 Dao 层真的有必要每个类都加上接口吗?」这个问题,之前简单回答了一波,给出的观点是「看情况」
现在结合我参与的项目以及阅读的一些项目源码来看,如果项目中使用了像 Spring 这样的依赖注入框架,那可以不用接口!
先来说说为什么使用了依赖注入框架以后,可以不使用接口。
在前面的章节,并发操作要么发生在单个应用内,一般使用基于 JVM 的 lock 解决并发问题,要么发生在数据库,可以考虑使用数据库层面的锁,而在分布式场景下,需要保证多个应用实例都能够执行同步代码,则需要做一些额外的工作,一个最典型分布式同步方案便是使用分布式锁。
分布式锁由很多种实现,但本质上都是类似的,即依赖于共享组件实现锁的询问和获取,如果说单体式应用中的 Monitor 是由 JVM 提供的,那么分布式下 Monitor 便是由共享组件提供,而典型的共享组件大家其实并不陌生,包括但不限于:Mysql,Redis,Zookeeper。同时他们也代表了三种类型的共享组件:数据库,缓存,分布式协调组件。基于 Consul 的分布式锁,其实和基于 Zookeeper 的分布式锁大同小异,都是借助于分布式协调组件实现锁,大而化之,这三种类型的分布式锁,原理也都差不多,只不过,锁的特性和实现细节有所差异。
控制并发的方法很多,从最基础的 synchronized,juc 中的 lock,到数据库的行级锁,乐观锁,悲观锁,再到中间件级别的 redis,zookeeper 分布式锁。特别是初级程序员,对于所谓的锁一直都是听的比用的多,第一篇文章不深入探讨并发,更多的是一个入门介绍,适合于初学者,主题是“根据并发出现的具体业务场景,使用合理的控制并发手段”。
由一个大家都了解的例子引入我们今天的主题:并发
上一篇文章《浅析 Spring 中的事件驱动机制》简单介绍了 Spring 对事件的支持。Event 的整个生命周期,从 publisher 发出,经过 applicationContext 容器通知到 EventListener,都是发生在单个 Spring 容器中,而在分布式场景下,有些时候一个事件的产生,可能需要被多个实例响应,本文主要介绍分布式场景下的事件驱动机制,由于使用了 Redis,ActiveMQ,也可以换一个名词来理解:分布式下的发布订阅模式。
在日常项目开发中,我们或多或少的发现一些包一些类位于 java 或 javax 中,他们主要提供抽象类,接口,提供了一种规范,如 JPA,JSR,JNDI,JTA,JMS,他们是由 java 指定的标准规范,一流企业做标准、二流企业做品牌、三流企业做产品,虽然有点调侃的意味,但也可以见得它的重要意义。而 JMS 就是 java 在消息服务上指定的标准
The Java Message Service (JMS) API is a messaging standard that allows application components based on the Java Platform Enterprise Edition (Java EE) to create, send, receive, and read messages. It enables distributed communication that is loosely coupled, reliable, and asynchronous.
JMS(JAVA Message Service,java 消息服务)API 是一个消息服务的标准或者说是规范,允许应用程序组件基于 JavaEE 平台创建、发送、接收和读取消息。它使分布式通信耦合度更低,消息服务更加可靠以及异步性。
消息中间件有非常多的实现,如 ActiveMQ,RabbitMQ,RocketMQ,而他们同一遵循的接口规范,便是 JMS。在下文中即将出现的 ConnectionFactory,Destination,Connection,Session,MessageListener,Topic,Queue 等等名词,都是 JMS 核心的接口,由于本文的初衷并不是讲解 MQ&JMS,所以这些机制暂且跳过。
在上一个项目中,我们对接了外网的 http 接口,而安全性的保障则是交给 OAuth2 来完成,作为 OAuth2 的客户端,我们需要获取服务端返回的 token,而 token 接口的获取次数每个月是有限制的,于是我们选择使用 Redis 来保存,定时刷新。由于每次发起请求时都要携带 token,为了更高的性能减少一次 redis io,我们在 TokenService 中使用了本地变量缓存 token。于是形成如下的 token 获取机制:
这个图并不复杂,只是为了方便描述需求:首先去本地变量中加载 token,若 token==null,则去 Redis 加载,若 Redis 未命中(token 过期了),则最终调用外部的 http 接口获取实时的 token,同时存入 redis 中和本地变量中。
这个需求设计到这样一个问题:大多数情况下是单个实例中发现 redis 中的 token 为空,而它需要同时获取最新 token,并通知其他的实例也去加载最新的 token,这个时候事件广播就可以派上用场了。
由于 token 缓存在了 Redis 中,我们首先介绍 Redis 的发布订阅机制。
今天来简单地聊聊事件驱动,其实写这篇文章挺令我挺苦恼的,因为事件驱动这个名词,我没有找到很好的定性解释,担心自己的表述有误,而说到事件驱动可能立刻联想到如此众多的概念:观察者模式,发布订阅模式,消息队列 MQ,消息驱动,事件,EventSourcing… 为了不产生歧义,笔者把自己所了解的这些模棱两可的概念都列了出来,再开始今天的分享。
Update your browser to view this website correctly.&npsb;Update my browser now