网页客服,欢迎咨询

服务模块化

2025-01-06 19:40:02 33
  • 收藏
  • 管理
    总篇188篇 2023年第1篇服务模块化践行2017年9月jdk 9正式发布,带来了很多新特性,其中之一便是模块化,JDK模块化的前身是项目 Jigsaw,于2008开始孵化,最早计划用于jdk7,一部分内容推迟到了jdk8,实际上在jdk9才完成了该项目全部目标,即实现一个模块系统,并以此实现jdk自身模块化。本文主要阐述模块化的概念,为什么关注模块化,基于jdk9的模块化实现原理和项目实践。1.什么是模块化模块化是个广泛的概念,用于软件编程就是将系统分解成独立且互相连接的模块的行为,拆分的模块通常需要提前定义好标准化的接口,以便让各模块独立开发情况下,还能互相调用不受影响。实际上在面向对象语言中对象之间的关注点分离与模块化的概念基本一致,在实际应用开发中,将复杂业务系统按照业务逻辑等分割成多个独立的模块,各模块提前定义好对外的服务接口,各模块独立开发,根据依赖的模块可独立完成业务模块测试、交付。Java语言并不是按照模块化思想设计的(除了package,在Java语言和虚拟机规范各版本第7章package,程序被组织为一组包。包的成员是类、接口以及子包,它们以包为编译单元声明)但是java社区早就有很多模块。一个jar,一个包,任何一个java类库,实际上都是一个模块,通常模块都附带一个版本号,以便模块升级提供新功能并不对低版本的模块产生影响。2.为什么模块化模块化有助于将应用分解为不同的模块,各个模块可以单独测试、开发、交付。类库基本上都是模块,如果你想将部分类库提供给别人使用或者使用了别人提供的类库,那么实际上你已经参与过模块化应用了。在实际项目中,一般使用构建工具(maven、gradle等)组建,明确指明了依赖的类库,以及变成类库,供他人使用。模块化的好处之一是便于模块独立测试、开发、交付。模块可按照业务核心情况或依赖顺序部分交付,以便项目逐步完成交付,节省资源,增加迭代优化空间,这个概念提别像敏捷开发,采用迭代、循序渐进的方法进行软件开发,把一个大项目分为多个相互联系,但也可独立运行的小项目,并分别完成,在此过程中软件一直处于可使用状态。模块化的另一个好处是便于升级,修复bug并提供新的服务,而版本号的存在就是为了区分模块的历史版本以及避免依赖发生错误。像guava、fastjson和fastjson2等类库证实了这点。模块化也可给项目管理带来方便,复杂业务分割成一个个独立可复用的模块,项目结构性更好,出现问题或者需要部分优化,只需要关注部分模块,对于依赖的模块由其他人提供维护即可,减少了维护和关注的成本。3.模块化的原理首先需要安装jdk9,下载地址放在文末附录。如下图1所示为安装好的jdk9,图2所示为jdk8的目录,是多个jar。图1图2以上图1和图2对比可以看到jdk9拆分成了具体模块,不再是一个个的jar,每个模块都有一个module-info.class,文件定义模块的名字、依赖的模块、对外开放的类、接口实现类等,实际上module-info就是是模块化的声明文件。除了组织形式发生变化外,真正的区别在哪里呢?图3是jdk.internal.loader.BuiltinClassLoader的loadClassOrNull方法中的代码片段,是进行类加载的方法,代码展示先查找LoadedModule (模块信息)如果有的话就进行类加载,否则的话,按照双亲委派模式向上委托进行类加载,后一步是为了向前兼容,前一步就是模块化实现的核心原理,类加载机制不再向上委托,而是根据LoadedModule限制类加载。其初始化在java.lang.System# initPhase2如图3.1,主要是虚拟机进行系统模块化的初始化,并返回ModuleLayer,称为layer(层,表示一组类加载器),有两种层,虚拟机提供的boot layer和用户自定义的layer,用于将基础模块和用户定义模块与类加载器(层)关联。图3图3.1模块的定义在Module#defineModules,详细的解释可在java9se虚拟机规范5.3.6找到,Java 虚拟机支持将类和接口组织成模块,调用defineModules,将模块与layer(类加载器)关联,设置模块可访问、开放的资源以及依赖的资源(由此限制模块的访问), 访问控制由类的运行时模块管理,不是由创建类的类加载器或类加载器服务的层管理,至此模块化的初始化和限制访问核心功能实现。也可按照以下代码理解模块化的组织和实现。BuiltinClassLoader的实现类有三个AppClassLoader,BootClassLoader,PlatformClassLoader,jdk9的类加载器。//初始化?layerModuleLayer?boot?=?ModuleLayer.boot();Configuration?configuration?=?boot.configuration();//获取解析的模块Set?modules?=?configuration.modules();modules.forEach(resolvedModule?->?{//获取模块句柄ModuleReference?reference?=?resolvedModule.reference();//模块化的名称System.out.println(reference.descriptor().name());try?(ModuleReader?reader?=?reference.open())?{//模块化下的全部资源reader.list().forEach(System.out::println);}?catch?(IOException?ioe)?{throw?new?UncheckedIOException(ioe);}});jdk9以前的类加载机制是大家熟识的双亲委派三层模型,bootstrap classloader ?transportationClass?=?(Class)Class.forName("transportservice.TransportationImpl");Transportation?transportation?=?transportationClass.getDeclaredConstructor().newInstance();return?transportation;}}模块化module,workapi可对外暴露,实现类是WorkImpl,requires 表示依赖模块, 依赖模块eat、transportation,调用了这两个模块的服务,transitive 关键字表示该依赖会被传递,引用本服务的服务也会引用transitive修饰的模块,不用在主服务中在引一次,uses表示使用模块中的具体服务。module?work?{exports?workapi;provides?workapi.Work?with?workservice.WorkImpl;requires?transitive?eat;requires?transitive?transportation;uses?eatapi.EatApi;}?4.2.4.console模块该模块调用work模块以及work transitive 的模块,模块化配置如下,依赖模块work,使用workapi.Work和eatapi.EatApimodule?console?{requires?work;uses?workapi.Work;uses?eatapi.EatApi;}day1目录下新建Main,模块Work的依赖隐式传递,最终打印出结果如图8所示。public?class?Main?{public?static?void?main(String[]?args)?throws?Exception?{//获取work?服务ServiceLoader?load?=?ServiceLoader.load(Work.class);Work?work?=?load.findFirst().get();//调用work.work();//其他服务ServiceLoader?eatLoader?=?ServiceLoader.load(EatApi.class);EatApi?eatApi?=?eatLoader.findFirst().get();eatApi.eat();eatApi.drink();//反射获取Transportation?transportation?=?getTransportation();transportation.transport();}private?static?Transportation?getTransportation()?throws?Exception?{Class?transportationClass?=?(Class)?Class.forName("transportservice.TransportationImpl");Transportation?transportation?=?transportationClass.getDeclaredConstructor().newInstance();return?transportation;}}图85.总结以上便是使用模块化生成需要jre环境和在项目中使用多模块服务的践行。模块化核心原则模块必须强封装性,隐藏部分代码,只对外提供指定服务,也就需要良好的接口定义并且显示依赖,声明式的服务依赖,不是使用了但不知道依赖来自哪里的糊涂账。可以提高模块的可读性,明确服务的入口和依赖,减少服务循环依赖,按需打包,解决反射带来的全可见危害,提高安全性。但是就目前而言模块化带来的收益远低于迁移工作,目前大家都在用spring的全家桶应用项目,使用很方便,但是真正按照模块化将其切分出来,并且能够完全理清楚项目依赖,也是有一定门槛的,不过模块化的方法和工具,jdk已然提供,模块化的思维和想法是很值得学习的,相信在不久的将来,模块化会更智能和完善。6.附录?[1]项目hello ?https://gitee.com/lifutian66/java9/tree/master/hello[2]项目java9 https://gitee.com/lifutian66/java9/tree/master/java9[3]生成hello.jmod https://gitee.com/lifutian66/java9/hello.jmod[4]生成jre ? ?https://gitee.com/lifutian66/java9/tree/master/jre[5]jdk9 地址:https://www.oracle.com/java/technologies/javase/javase9-archive-downloads.html[6]Modular Java: What Is It?https://www.infoq.com/articles/modular-java-what-is-it/[7]参考文档:java9模块化开发核心原则和实践作者简介李福田主机厂技术部-数科技术团队。2022年加入汽车之家,目前任职于数科品牌私享家后端技术团队,主要负责品牌私享家后端相关业务技术开发。阅读更多:汽车之家AutoKH混部技术实践Go语言项目实践及新特性解读线程复用助力之家出行平台运力提升的应用实践 服务模块化
    上一页:服务网格可观测性之平台化监控报警 下一页:数据库日志采集系统方案设计
    全部评论(0)