协议的加载与解析流程

88 阅读3分钟

本篇文档主要用于介绍 jetlinks 平台下 协议管理中 协议上传以及上传的协议生效的业务和源码流程

1、流程源码解析

  1.1、主动触发流程

通过前端页面操作属于主动触发流程。在 “运维管理” ——> “协议管理” 菜单下进行统一管理。通过 新增 ——> 上传jar包——>确认 ,之后一个网络协议就可以使用了。下面来对每一步的操作进行分解

  1.1.1、上传jar包并确认流程

当“上传jar包” 完成之后,点击“确认”,请求到 “org.hswebframework.web.crud.web.reactive.ReactiveServiceSaveController#add(reactor.core.publisher.Mono)” 其中 ProtocolSupportController 继承 ReactiveServiceSaveController 。 并最终 执行到 “org.hswebframework.ezorm.rdb.mapping.defaults.DefaultRepository#doInsert(java.util.Collection)”

继续走到 “org.hswebframework.ezorm.rdb.mapping.events.EventResultOperator#create” ,在这个方法里会通过 “tableMetadata.fireEvent” 进行 实体变更消息发布流程

继续进入这个方法,会首先加载系统里的 EventListener ,实际上真正执行业务逻辑的是 EntityEventListener里

进入 EntityEventListener#onEvent() 里,继续走 handleBatchOperation 方法 ,可以看到最终通过 Spring 的 ApplicationEventPublisher组件发布了 一个afterEvent事件

当Spring event事件发布完成之后 ,ProtocolSupportHandler#handleCreated 监听器 方法会被触发

然后通过 reloadProtocol 方法对协议进行重新加载 ,并最终进入到 SpringProtocolSupportLoader#load 方法对协议进行加载

因为上传的是jar包,所以最终的加载会通过 AutoDownloadJarProtocolSupportLoader#load 进行加载

会根据jar包地址 “location -> http://127.0.0.1:5173/api/file/9e9e7fcc9d657829c1bbfad2883a6340?accessKey=4a66c71c3c4a6e93d7690b8dca185456” 转换成本地文件 “.\data\protocols\1823190889886220288_e1cb05f2db466ff3c095b43a603ffdfd.jar” 如果没找到会先通过http的方式进行远程下载到 /data/protocols 目录下 ,然后走父类 JarProtocolSupportLoader#load 再次进行加载

之后通过创建自定义classloader -> ProtocolClassLoader , 通过自定义classloader 加载 协议包里 ProtocolSupportProvider 协议提供者的具体实现 JetLinksProtocolSupportProvider , JetLinksProtocolSupportProvider#create 创建具体的消息协议实体 CompositeProtocolSupport

加载完成之后存储协议

1.2、项目启动重新加载协议流程

  1.2.1、通过spring自动配置相应的加载启动类

程序启动时加载配置类 ProtocolAutoConfiguration 中配置信息,配置类中使用Spring框架的ObjectProvider获取 ProtocolSupportLoaderProvider 接口的实现类实例,并将这些实例缓存到SpringProtocolSupportLoader 里的Map集合中,以便后续通过 SpringProtocolSupportLoader 根据不同的协议类型(jar 或者 file )方式进行协议的加载


@Configuration(proxyBeanMethods = false)
@AutoConfigureBefore(DeviceClusterConfiguration.class)
public  class  ProtocolAutoConfiguration {

//    @Bean
//    public ProtocolSupportManager protocolSupportManager(ClusterManager clusterManager) {
//        return new ClusterProtocolSupportManager(clusterManager);
//    }

    @Bean
 public ServiceContext serviceContext(ApplicationContext applicationContext) {
        return  new SpringServiceContext(applicationContext);
    }

    // 这个bean 实现并 CommandLineRunner 会在spring容器启动完成之后执行run触发协议组件的加载
     @Bean
 public LazyInitManagementProtocolSupports managementProtocolSupports(EventBus eventBus,
                                                                         ClusterManager clusterManager,
                                                                         ProtocolSupportLoader loader) {
        return new LazyInitManagementProtocolSupports(eventBus, clusterManager, loader);
    }

    @Bean
 @Primary
 public LazyProtocolSupports protocolSupports() {
        return  new LazyProtocolSupports();
    }

     @Bean
 public AutoDownloadJarProtocolSupportLoader autoDownloadJarProtocolSupportLoader(WebClient.Builder builder, FileManager fileManager) {
        return new AutoDownloadJarProtocolSupportLoader(builder, fileManager);
    }

    //自动注入ProtocolSupportLoaderProvider实现到 SpringProtocolSupportLoader中
     @Bean
 public ProtocolSupportLoader protocolSupportLoader(EventBus eventBus,
                                                       ObjectProvider<ProtocolSupportLoaderProvider> providers) {
        SpringProtocolSupportLoader loader = new SpringProtocolSupportLoader(eventBus);
        providers.forEach(loader::register);
        return loader;
    }

    @Bean
 public ProtocolSupports inSpringProtocolSupports(EventBus eventBus,
                                                     ObjectProvider<ProtocolSupport> supports) {
        StaticProtocolSupports protocolSupports = new StaticProtocolSupports();
        for (ProtocolSupport protocol : supports) {
            protocolSupports.register(
                new RenameProtocolSupport(
                    protocol.getId(),
                    protocol.getName(),
                    protocol.getDescription(),
                    protocol,
                    eventBus
)
            );
        }
        return protocolSupports;
    }

    @Bean
 @Profile( "dev" )
    public LocalProtocolSupportLoader localProtocolSupportLoader(ServiceContext context) {
        return  new LocalProtocolSupportLoader(context);
    }
}

  1.2.2、自动配置加载组件走自动加载协议组件流程

  在1.2.1中已经通过 SpringProtocolSupportLoader 收集了系统中所有的协议加载组件包括 AutoDownloadJarProtocolSupportLoader 和 LocalProtocolSupportLoader 。 这些协议加载组件的关系如下

之后由于 LazyInitManagementProtocolSupports 实现 CommandLineRunner , 会执行其 run 方法,run方法会执行其父类 DefaultProtocolSupportManager#init(ProtocolSupportDefinition) , 在方法内会委托 ProtocolSupportLoader (SpringProtocolSupportLoader) #load 走加载协议流程了, 并最终通过

AutoDownloadJarProtocolSupportLoader#load 找到最终的 ProtocolSupportProvider 实现类 JetLinksProtocolSupportProvider (其实是一个协议创建工厂) ,最终通过 JetLinksProtocolSupportProvider#create 创建 ProtocolSupport 实现类 CompositeProtocolSupport

AutoDownloadJarProtocolSupportLoader#load 相关执行流程如下:

2、总结

  2.1、整体前后端代码加载流程如下

whiteboard_exported_image.png

参考:hanta.yuque.com/px7kg1/nn1g…