前些日子,设计了一套为原业务系统提供数据权限控制的中间件应用。由于原系统基于Mybatis实现数据层,权限系统就利用Mybatis拦截器实现,通过修改原系统执行查询的SQL达到权限修改的目的,操作SQL的配置数据信息通过独立的web页面配置,配置页面展示的数据和用户信息需要原系统提供。
需求希望权限系统与原系统相互独立(代码和业务),分别开发好后,原系统再通过jar包依赖引入权限系统,因此采用了服务提供者框架模式,权限系统提供数据信息获取接口,原系统实现接口,这样可以做到代码业务相互解耦,系统架构图见图1。
图1 数据权限系统架构图
权限系统使用Maven + Spring Boot搭建,能够独立运行和测试。按照架构图创建的模块架构图见图2。
图2 数据权限系统模块架构图
module core
封装SQL处理、页面数据查询处理
、交互接口
(对应图1红色和绿色部分)。module web
封装数据权限配置界面
(对应图1右上方蓝色部分)。module starter
封装系统的运行组件(Spring Boot组件)以及系统测试组件,不需要引入到原系统中的模块。class Impl
为原系统对交互接口
的实现(对应图1左面天蓝色部分),开发权限系统过程中先按照接口建立模拟实现类。这个实现体现了服务提供框架模式。
原系统引入权限系统只需要将module web
的jar包引入即可,maven管理会自动引入module core
,这样原系统就集成好权限系统了。考虑到原系统使用Mybatis作为数据层实现,当前版本设计的权限系统是通过jar包引入到原系统,和原系统一起部署运行,那么权限系统的web模块也设计为使用Mybatis作为数据层。
此时,必须考虑一个问题,Mybatis用来标注Dao接口的注解在3.4.0之前的版本是需要开发者自定义的,而3.4.0之后Mybatis新增了@Mapper
注解。现在原系统使用的Mybatis版本为3.2.8,因此原系统自定义了Dao接口注解@Symbol
。如果希望权限系统集成到原系统中后,能够使用原系统配置的Mybatis,那么权限系统有可能要使用原系统的Dao接口注解,再查看了Spring-Mybatis的配置类org.mybatis.spring.mapper.MapperScannerConfigurer
,发现annotationClass
的类型只能是Class<? extends Annotation>
,而并非一个数组,这样权限系统就必须使用原系统的Dao接口注解了,即@Symbol
,这样模块架构图将变成图3所示。
图3 数据权限系统模块架构图
从图3的架构图可以看到,模块间出现了循环引用,Host Project
(原系统)需要引入Project
(权限系统),而Project
又需要引入Host Project
的class Symbol
,这样做无论从设计或者代码模块方面来看,都是没解耦的,而Spring-Mybatis配置annotationClass
只支持一个Dao接口注解,个人认为也是不合理的,可能是Spring-Mybatis的疏忽吧。
再仔细分析,@Symbol
只在编译Dao接口的class文件时需要,那么可以在权限系统中引入一个provide模块,将同名的Symbol
注解放到模块中,**并设置模块<dependance>
的<scope>
为provide
就可以解决maven模块循环引用配置问题,即<scope>provide</scope>
**。配置<scope>
为provide
可以让provide模块在编译时有效,但provide模块的jar包不会被引入到运行环境中,即原系统引入web模块时不会引入provide模块。这时模块架构图如图4所示。
图4 数据权限系统模块架构图
可以看到,模块循环引用已经解决,但是权限系统要使用原系统的@Symbol
注解依然是不合理的。如果需求希望权限系统独立,与原系统解耦,那么此时并没有做到,假如原系统的Dao接口注解更改,那么权限系统的provide模块也需要更改,这不合理。
在第一版的权限系统中并没有想到好的解决办法,后面才想到可以利用特殊方式直接动态增加class文件,class代表的接口继承所有没有标注Dao接口注解的Dao接口,并添加上Dao注解(需要额外配置),这个操作需要在spring启动组件扫描前进行。本文完成前这个想法已经变成了现实,使用ASM动态新增接口的class文件可以做到,但并不在本文的描述范围内,暂不表。
将交互接口
的模拟实现类的模块添加上,完整的数据权限系统模块架构就如图5所示。
图5 数据权限系统模块架构图
模块架构完成,最后还有一个依赖传递的问题,权限系统是基于Spring Boot开发的,理所当然的引入了Spring Boot的依赖包,那么原系统在引入moduel web
的时候,会因为依赖传递将Spring Boot的依赖包也引入,这是没有必要的,也是可能造成jar包冲突的地方,因此在权限系统的pom.xml
中,需要对Spring Boot的jar包依赖配置<optional>true</optional>
,以保证moduel web
被引入到其他系统中时不会将其依赖包传递引入。
PS:当前的权限系统架构也算不上完全解耦的中间件系统,后面又设计了第二个版本,比上个版本多了通信的模块,原系统引入通信和拦截器控制模块的jar包,权限系统本身的核心部件和web页面单独部署,这样就达到了与原系统真正的解耦的目的了。系统架构图见图6。
图6 数据权限系统架构图