JAR包:如果我依赖你,那劝你别依赖我。
一、技术视野
1、背景描述
在分布式系统搭建的初期,对于组件的选型是需要慎重考虑的,特别是对于同一个场景但是有多个不同组件可选项时,需要经过一定的调研再去确定最终选择,从而尽量避免后期业务发展引起核心组件的替换问题。
不同的技术选型,意味着不同的依赖包和版本,作为工程的基础,复杂的系统中管理庞大的依赖,需要具备体系化的思维。
2、开源体系
从个人习惯上来看,在核心的技术组件选型上,优先考虑从Spring和Apache两个生态中寻找,所以要对这两套开源体系下的组件有广泛的了解,以及相关配套的集成工具,在开发过程中有很多复杂的技术实现都是有对应的封装包来解决,更多的时候是不熟悉或没注意到;
再者就是很多热门的开源项目,这里理解为针对某个场景可以提供更好的解决方案,比如缓存或者任务调度等,在这个选择中可以优先关注大厂的开源组件,经过复杂业务的考验会相对成熟和稳定。
大部分情况下技术需求基于现有开源生态都是可以寻到相应的解决方案,所以定期关注开源组件的发布更新,对于开阔思路和视野有极大的帮助。这里从广泛的角度看开源体系,实际的项目中是有很多轻量级的工具包,可以简化代码和提升效率。
二、框架层面
1、JDK版本
对于核心框架的依赖,除了选型这个方面,还要考虑的就是版本问题,对于很多小厂来说更多的是处在一种"等待"的状态,等待开源市场给出更合理的选择。
就从JDK的选择来看,作为Java工程中最底层的依赖,很多项目都是从JDK5直接跳跃到JDK8的,多数开源组件的最低依赖也需要JDK8,从版本的发布上看也就算个中间版。
所以在核心依赖上优先考虑使用最多的版本,至于后续要升级到什么版本,稍微留心注意下就会知道。如果版本过旧会和大多数组件冲突,如果版本过新要适配突发的问题,从选择上看不算特别明智。
2、核心框架
核心框架依赖的选择,需要遵守一个体系的原则,例如在Java工程中必选的Spring体系,在微服务的架构设计中,对于服务注册发现,通信请求,网关路由等功能组件,都可以围绕SpringCloud的相关集成去做选择,这样可以有效减少技术带来的负担,并且具有活跃的社区和详细的文档支撑。
三、单工程分层
微服务的架构中,针对单服务的工程代码也会分包管理,不同分层的包管理特定性质的代码文件,除了各个服务依赖公共包core
(常见命名)之外,通常至少划分bean、feign、serve
三层:
- core:各个服务依赖的基础包,封装技术层面的解决方法,或业务的复用功能;
- bean:工程对象(入参出参)和常量管理,一般不包括数据表的映射对象;
- feign:服务交互的接口层封装,工程间通信的核心依赖;
- serve:服务中具体业务实现层,控制层与feign接口层对应;
这样分层分包管理工程,服务之间的依赖就会清晰许多,也极大的保证了代码的复用性,版本升级时弃用的代码标记为过期,同时指向新的代码路径,其他服务升级时再跟随升级,最终彻底剔除过时代码,以此避免业务发展导致代码工程的混乱。
四、中间件
中间件在服务中是必不可少的业务支撑,例如开发中最常用的几个:缓存管理、消息队列、任务调度等;
消息队列:可以通过模式封装,实现消息的统一总线管理,避免消息混乱;例如之前总结过的消息中间件改造方案:
缓存管理:每个服务都或多或少存在缓存需求,缓存机制也具有一定的共性;
任务调度:通常会将任务调度的组件集成在单个服务中,实现调度管理的基本能力,然后采用服务间通信机制(例如Feign接口),去触发待任务执行;
中间件并不仅仅是引入依赖然后各种API的调用,基于什么策略和设计模式去管理,会给工程带来不同的影响。
五、轻量工具
许多项目下都会有一个util
分包,用来存放常用的工具代码文件,如果是在复杂的分布式项目中,通常打成独立的jar
包,后来这些基础的工具类被汇聚到开源项目中,极大的降低维护成本,并且可以标准化的使用工具:
对于工具包中提供哪些核心能力,经常查阅相关文档即可,像一些:日期、字符串、集合、JSON、Http、文件流等常见功能,都会封装相应的处理方法。lombok
插件可以高度简化Java对象中代码,以及对象的使用。
工具型的组件,更倾向于在开发过程中明确规定使用哪一个,尽量避免混搭使用,并且要熟悉工具包提供的各种能力,减少不必要的重复封装,对于类库中的常用方法也可以多阅读,被多数开发认可的代码,必然可以开阔自己的代码编写思路。
最后,很多技术栈或者开源组件的不断发展,都是为了可以更好的解决场景问题,这就需要开发人员定期关注技术的发展趋势,具备技术视野和洞察能力。
六、参考源码
应用仓库:
https://gitee.com/cicadasmile/butte-flyer-parent
组件封装:
https://gitee.com/cicadasmile/butte-frame-parent