Nacos插件实现原理

您所在的位置:网站首页 mappermap() Nacos插件实现原理

Nacos插件实现原理

#Nacos插件实现原理| 来源: 网络整理| 查看: 265

nacos插件实现原理 前言

Nacos从2.1.0版本开始,支持通过SPI的方式注入鉴权相关插件,并在application.properties 配置文件中选择某一种插件实现作为实际鉴权服务。

官方自带插件:

鉴权 配置加密 数据源 轨迹追踪 环境变量

其中映像深刻的就是数据源,遥想当初2.0版本中适配pg数据库使用起来是相当复杂,需要去修改nacos源码来适配pg数据库,还需要去考虑修改对于源代码影响程度。nacos后续如果涉及到升级还需要去修改此部门代码,痛苦程度可想而知。

nacos 2.1.0 ~ 2.2 版本中利用插件的方式完美解决了这个问题,连接方式可以通过自己去按照一定规则去进行增强,妥妥的符合开闭原则啊。nacos源码是如何实现这一操作的?

这是我目前唯一想了解的。扒源码,开干;

理想很丰满,现实却很骨感。

由于对nacos源码不太了解,导致根本找不到代码相关入口,如何加载自己写的jar包。如何让他能够起效果?

经过漫长百度无果后,发现有人在git上已经上传了nacos适配pg数据库的插件,不得不佩服强人还是很多的。转念一想,他可以适配的原因不就是利用spi加载了相关实现,并进一步进行了相关代码的实现吗?这不正是我想找的入口吗。。。。。来了

插件项目解析

从datasource-plugin-ext-base 项目中我们可以发现 service文件,如下图:

Untitled.png

com.alibaba.nacos.plugin.datasource.dialect.DefaultDatabaseDialect 复制代码

注: 这里加载会用到spi技术,这里不做说明。可从这里查看spi相关知识

Java SPI

从service文件中可以看到:DefaultDatabaseDialect 类的结构图如下:

Untitled 1.png

这样我们就可以定位到程序加载的是: DatabaseDialect 这个接口类。

public interface DatabaseDialect { /** * get database type. * @return return database type name */ public String getType(); /** * get frist index page param. * @param page current pageNo * @param pageSize current pageSize * @return offset val or maxRange */ public int getPagePrevNum(int page, int pageSize); 复制代码

查询到getType() 方法调用者来看,我们跟踪线到了 DatabaseDialectManager 这个类。 根据现在已有知识来说这个manager类 从命名来说应该是管理数据源相关工具类,具体代码如下: 删除一些不重要代码

public class DatabaseDialectManager { private static final DatabaseDialectManager INSTANCE = new DatabaseDialectManager(); private static final Map SUPPORT_DIALECT_MAP = new ConcurrentHashMap(); private DatabaseDialectManager() { } static { //加载多种数据库方言为映射信息 Collection dialectList = NacosServiceLoader.load(DatabaseDialect.class); for (DatabaseDialect dialect : dialectList) { SUPPORT_DIALECT_MAP.put(dialect.getType(), dialect); } if (SUPPORT_DIALECT_MAP.isEmpty()) { LOGGER.warn("[DatasourceDialectManager] Load DatabaseDialect fail, No DatabaseDialect implements"); } } public DatabaseDialect getDialect(String databaseType) { DatabaseDialect databaseDialect = SUPPORT_DIALECT_MAP.get(databaseType); if (databaseDialect == null) { return new DefaultDatabaseDialect(); } return databaseDialect; } public static DatabaseDialectManager getInstance() { return INSTANCE; } } 复制代码

知识点:

利用单例模式进行类的创建 通过静态代码块的形式+spi模式将DatabaseDialect接口类的所有实现类均加载出来并存放在map中

代码跟踪到这发现线路断了,好像这边跟nacos没有什么结合的地方。nacos又是如何将他加载到系统中的?如何做到替换成pg数据?好像一个问题都没解决掉,不过我们也学习到了其他知识。

emo…… 线索断了就需要我们在重新梳理下;

nacos通过spi加载 ——> 插件项目一定在service文件中编写相关接口 目标不错的话就不会有太大问题。

继续查看插件项目代码

终于:在 nacos-postgresql-datasource-plugin-ext 项目中,看到关键性信息

Untitled 2.png

查看这个Mapper文件:这不就是我所需要的连接点吗。。。。 Mapper类

com.alibaba.nacos.plugin.datasource.impl.postgresql.ConfigInfoAggrMapperByPostgresql com.alibaba.nacos.plugin.datasource.impl.postgresql.ConfigInfoBetaMapperByPostgresql com.alibaba.nacos.plugin.datasource.impl.postgresql.ConfigInfoMapperByPostgresql com.alibaba.nacos.plugin.datasource.impl.postgresql.ConfigInfoTagMapperByPostgresql com.alibaba.nacos.plugin.datasource.impl.postgresql.ConfigTagsRelationMapperByPostgresql com.alibaba.nacos.plugin.datasource.impl.postgresql.HistoryConfigInfoMapperByPostgresql com.alibaba.nacos.plugin.datasource.impl.postgresql.TenantInfoMapperByPostgresql com.alibaba.nacos.plugin.datasource.impl.postgresql.TenantCapacityMapperByPostgresql com.alibaba.nacos.plugin.datasource.impl.postgresql.GroupCapacityMapperByPostgresql 复制代码

ps:

若能直接点到这个项目能省很多事情,但干程序这一行就是需要折腾,这样你才能从中学习到知识。

Nacos项目解析 连接点 Mapper接口 位于 com.alibaba.nacos.plugin.datasource.mapper.Mapper 下,plugin 插件包 datasource 下。项目中同样有service文件,这样也能确定上面的猜想。 com.alibaba.nacos.plugin.datasource.impl.mysql.ConfigInfoAggrMapperByMySql com.alibaba.nacos.plugin.datasource.impl.mysql.ConfigInfoBetaMapperByMySql com.alibaba.nacos.plugin.datasource.impl.mysql.ConfigInfoMapperByMySql com.alibaba.nacos.plugin.datasource.impl.mysql.ConfigInfoTagMapperByMySql com.alibaba.nacos.plugin.datasource.impl.mysql.ConfigTagsRelationMapperByMySql com.alibaba.nacos.plugin.datasource.impl.mysql.HistoryConfigInfoMapperByMySql com.alibaba.nacos.plugin.datasource.impl.mysql.TenantInfoMapperByMySql com.alibaba.nacos.plugin.datasource.impl.mysql.TenantCapacityMapperByMySql com.alibaba.nacos.plugin.datasource.impl.mysql.GroupCapacityMapperByMysql com.alibaba.nacos.plugin.datasource.impl.derby.ConfigInfoAggrMapperByDerby com.alibaba.nacos.plugin.datasource.impl.derby.ConfigInfoBetaMapperByDerby com.alibaba.nacos.plugin.datasource.impl.derby.ConfigInfoMapperByDerby com.alibaba.nacos.plugin.datasource.impl.derby.ConfigInfoTagMapperByDerby com.alibaba.nacos.plugin.datasource.impl.derby.ConfigInfoTagsRelationMapperByDerby com.alibaba.nacos.plugin.datasource.impl.derby.HistoryConfigInfoMapperByDerby com.alibaba.nacos.plugin.datasource.impl.derby.TenantInfoMapperByDerby com.alibaba.nacos.plugin.datasource.impl.derby.TenantCapacityMapperByDerby com.alibaba.nacos.plugin.datasource.impl.derby.GroupCapacityMapperByDerby 复制代码 项目中很明显也可以看到有个manager类。MapperManager ,依照惯例,这个类不能放过 public class MapperManager { private static final Logger LOGGER = LoggerFactory.getLogger(MapperManager.class); public static final Map MAPPER_SPI_MAP = new HashMap(); private static final MapperManager INSTANCE = new MapperManager(); private boolean dataSourceLogEnable; private MapperManager() { loadInitial(); } /** * Get the instance of MapperManager. * @return The instance of MapperManager. */ public static MapperManager instance(boolean isDataSourceLogEnable) { INSTANCE.dataSourceLogEnable = isDataSourceLogEnable; return INSTANCE; } /** * The init method. */ public void loadInitial() { Collection mappers = NacosServiceLoader.load(Mapper.class); for (Mapper mapper : mappers) { Map mapperMap = MAPPER_SPI_MAP.getOrDefault(mapper.getDataSource(), new HashMap(16)); mapperMap.put(mapper.getTableName(), mapper); MAPPER_SPI_MAP.put(mapper.getDataSource(), mapperMap); LOGGER.info("[MapperManager] Load Mapper({}) datasource({}) tableName({}) successfully.", mapper.getClass(), mapper.getDataSource(), mapper.getTableName()); } } } 复制代码 Collection mappers = NacosServiceLoader.load(Mapper.class); 这行代码已经可以说明一些问题了,插件jar包就是通过这边给nacos增强连接pg的功能,再通过配置文件选择pg数据库这样就能完整的一条线 结尾

目前是大概了解了nacos是通过怎样的方式把外部插件进行连接,但目前仍然有一些问题需要进一步深挖的:

nacos如何初始化的数据库连接 所有好的框架代码代码都有看名知意,包、类、方法划分清楚的有点,无论nacos源码还是插件源码都可以看到 彩蛋

插件项目为啥 DefaultDatabaseDialect 类管理 数据源? 其实一开始就项目介绍中就有相关体现。此项目最终目的是可以集成对所有数据库的支撑;

三、其他数据库插件开发

可参考nacos-postgresql-datasource-plugin-ext工程,新创建Maven项目,实现AbstractDatabaseDialect类,重写相关的分页操作逻辑与方法,并创建相应的mapper实现,减少了适配的成本。

目前对于Oracle、达梦数据库,仍然需要修改Nacos2.2的主分支代码,因为要兼容默认的命名空间ID为空的查询情况,社区官网未处理。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3