不会把Controller单独放一起。
Maven的打包,其实不是单纯的打包问题,更是一个微服务的架构问题。
先把架构的问题解决了,再去看目录的情况。
首先。Home和Service是必须要分开的两层。
通常而言,都会有home,admin,Service三个基本的环节。
先解释一下,为什么会有这三个基本的模块。
举一个K12的在线教育为例。
Home一般就是主页,延袭了之前PC端的传统,现在的App时代和SPA的时候,也可以通用,一般都是通指前台WEB。
Service就是各种服务,用户,视频,直播,支付,SMS,公告,班级,评分,老师等等等等。
Admin就是后台的管理,通常包括角色,用户,权限等。
再说一下用到的基本术语:
前端:指运行在用户端的JS,CSS和Html。
后端:指运行在服务器端的各种语言,Java,Go,Python什么的都可以。
前台:指的就是Home。
后台:指的是Admin。
假设现在都是在做SPA(其实无所谓),那么,当说到前台的时候,同样包含有Java和JS,后台同理。
这些术语我们先明确了,接下来就好交流沟通。
Maven的项目管理,一般而言,都是指后端的,现在举的例子也是以Java为例。
刚刚说过了。正常来说,有Home,有Service,有Admin。
第一个问题,为什么要拆分出来这三个模块呢?
先不考虑Home和Service的性能问题,单纯说Admin如果要更新发布怎么办?
如果我需要重启Admin怎么办?
Admin是必须要单纯拆出来的,无论多小的项目,如果你是一个准备提供给用户试用的,把Admin拆出来始终会一个好的原则。
这算什么原则我说不好。也可是说是单一职责,也可以说是为了解耦,也可以说是为了最简原则。
保留一个可以随意拆解的,可以随意重启的Admin,减少对线上服务的依赖,就已经可以解决掉很多问题了。
也许解决问题的最好方式就是尽量减少问题发生的可能性(跟很多找Bug的感受一样,大多数时间,之所以出现问题,是因为用了错误的方式去解决问题,方法正确了,很多问题都可以迎刃而解)。
所以这是Admin从Home中拆解出来的重要原因,它的一些通用和基本的功能,大部分时间都是和Home无关的。保持一个相对独立的环境,给一个配置相对比较低的机器,独立的版本发布,都是一个最佳实践。
那么再看,为什么要把Service从Home里拆出来。
这个时候完全是可以只要有一个Home和admin么?
Maven上两个Module,解决!
Home和Admin可能都需要调用用户服务?那就用Dao包呗。
Lib包搞定一切,反正更新的时候也可以同步更新。
这个问题,其实就是为什么要有Service的重要原因。
一般而言,最好的解答方式就是解决分布式的问题。
原则上来说,像我刚刚提到的,视频,支付,短信,公告,教材等,都最好是独立的一个Service。
不同的服务,承担的负载是不一样的。
比如说,支付可能就很低频,不需要分配那么多台服务器。
而用户功能比较重,可能会配置4台~10台服务器,还有可能快速增加。
这是拆解成Service的一个理由,否则你就要把Home这些东西全部部署一套了。
另外一个理由一样的,也是为了保证Service之间的升级,不会对其他模块有影响。
比如说,我的SMS切换了通道,我的支付增加了新的支付方式。这些,我都希望能够对其他的依赖到最小,我只重启我可以做到的最小范围。
拆解Service通常是一个很有味道的过程 ,也是架构过程中的一部分。
有经验的过程师,通常会基于以下几个原则去做:
1。有没有高频访问或者是写入的模块,有的话,拆出来,不影响别人,不拖跨别的机器和服务。
2。有没有需求变更比较快的模块,分频繁发布,导致不断重启。
3。有没有业务上比较独立的,和其他服务模块没有什么影响的。
4。有没有可能会出问题的,经常会挂掉的,或者是不重要的,就算是挂了也无所谓,但是不能因为自己挂了导致别人挂的。
5。有哪些是前后台分开使用的~~
这些原则放在一起,加上你对业务的熟悉程度,和其他的一些需求(不同项目的公用需求),构成了Service的拆解。
所以现在,我们的基本的服务架构就是这样的。
Home用来给线上的用户使用。
Service用来承担各种业务逻辑和处理。
Admin用来给后台管理人员使用。
再来看一下,关于性能和负载的问题。
正常来说,Home是可以无限水平扩展的。LVS就可以解决这个问题。
所以,如果Home有瓶颈,是能够解决的。
Service借助于一些SCA的工具,是可以解决掉的。
比如我们特别喜爱的Tuscany(但是配置文件太多是诟病,对服务的监控不够完善没有全家桶是一个遗憾,一直要基于Tuscany自己来)。
Admin一般而言不会有太大的用户量,正常来说,不用太考虑负载的问题。真的有了,解决方案也很简单,和Home一样。
好了,现在看起来已经有了一个大概的结构了。Home,Service和Admin。
那么对应在Maven的结构中,应该就是这么区分了么?
比这个更细致一些。
一般而言,Project下面会分成三大模块。framework,common,app。
这是参考之前我们在白社会做的时候的想法,有明显的SNS的痕迹。
Frameswork是系统的核心功能,包括用户,好友,Feed,日志之类的等等。
Common是一些公共的功能,包括SMS,权限等等,一般而言,都是和系统无关的服务。
App是一些可扩展,可插拔的功能模块。
这套体系,就算你不做一个开放平台,也可以参考。
所以,第一层结构就是Framework,Common和App,三个大的组织模块。
然后,每一个Module下面,再去细分home,admin,service。
除此之外,我们还做了一些约定。
这里的Type,也就是几个主要的目录结构的分解,先看一下这些目录结构包括什么,再来看看怎么打包,以及原因。
model:就是Pojo的对象,贫血模型。
Service:就是暴露的接口。在Service的时代,真不需要加上IF来表示接口了。
Service.Impl:各种服务的实现类。
Controller:就是Home里的Controller。
util:各种工具类
Constant:常量类(我们现在更推荐,Constant写入到Model里去,不然各种Constant的管理太复杂了)
好了。再看一下怎么分解到Maven的Module里去。
Home里应该有Controller和少量的Util和Contant,和少量的VO(原则上我们不推荐有任何的VO,VO就应该是在JSP里去组装和生成JSON,当然现在很多人更喜欢直接从Model转JSON,但我们谨慎的保留使用Json Tag-lib来生成JSON的方式,并且暂未发现有太多不好的地方)
还有就是引用的Service的Model。
这和RPC的方式有关,一般而言,JMS,Json,ProtocolBuffer,RMI都是可以的选择,但是在Java的世界里,还是首推RMI,够简单,又足以支持多数的应用场景。
所以在这里需要引用Service里的Interface和Model,我们还愿意把Util和Constant放到这里。
这里,我们把它统一叫做core包。
这是的Core,其实就是Service对外暴露的核心,可能会有人愿意给他起名字叫做api之类的,但是从我们的角度来看,Core称之为一个Service的核心没什么问题,怎么实现的反而没那么重要。
那么,现在的Module就应该是这样的:
framework-user-core
framework-user-service
所以可能你看到的目录应该是这样的。
framework-home
framework-admin-home
framework-user-core
framework-user-service
framework-user-etl
其实还想花更多的时间来讲一下,怎么勉强Service和Service之间的混乱调用。
这是微服务架构的地狱,坦白说,JS的回调地狱和Serivce与Service之间的混乱调用地狱是没有办法比的。
在之前,我们有90多个Service。
你有想象得出来互相之前调用的关系有多复杂么?
会有人说,我要加监控,加图形化的展示方式,加上服务的治理。
但是想一下我们之前说到的一句话:有没有办法不让这个问题发生?
另外关于Service中是否应该合适Dao,应该有一个还是多个Dao的问题,也是一个非常有意思的讨论。
等我吃完饭之后,看心情,心情好就讲一下我们对这个事情是怎么看的。