spring-boot集成spring-brick实现动态插件

2023-10-27

spring-boot集成spring-brick实现动态插件

项目结构 & 需求实现

提示:本文的集成说明,是针对完成此设计、此需求进行的

项目结构

demo
│ 
├─application # 主应用
│                  
└─plugin-api
    │  
    ├─plugin-qwer # plugin-qwer-api的实现示例1(注:也可以是单独的一个项目,继承不继承plugin-api均可)
    │                                              
    ├─plugin-qwer2 # plugin-qwer-api的实现示例2(注:也可以是单独的一个项目,继承不继承plugin-api均可)
    │                                          
    ├─plugin-qwer-api  # 插件qwer-api
    │                                          
    ├─plugin-xyz  # plugin-xyz-api的实现示例(注:也可以是单独的一个项目,继承不继承plugin-api均可)
    │                                          
    └─plugin-xyz-api # 插件xyz-api

需求实现

  • 主应用(application)、各个插件的实现(plugin-qwer、plugin-qwer2、plugin-xyz)均可单独启动
  • 主应用(application)启动后,可动态插拔各插件(plugin-qwer、plugin-qwer2、plugin-xyz)
  • 在plugin-api中,定义各种接口、及相关的pojo,这些接口由具体的插件实现去完成,主应用(application)面向plugin-api编程即可

spring-boot集成spring-brick

环境说明

  • spring-boot:2.6.13
  • spring-brick:3.1.1

1. 主程序集成spring-brick

第一步:引入相关依赖

更多详见here

<dependency>
    <groupId>com.gitee.starblues</groupId>
    <artifactId>spring-brick</artifactId>
    <version>3.1.1</version>
</dependency>
第二步:修改程序入口方法

更多详见here

import com.gitee.starblues.loader.launcher.SpringBootstrap;
import com.gitee.starblues.loader.launcher.SpringMainBootstrap;
import com.ideaaedi.commonspring.annotation.EnableParameterRecorder;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * main-application start class
 */
@SpringBootApplication
public class MainApplication implements SpringBootstrap {
    public static void main(String[] args) {
        // 这里使用 SpringMainBootstrap 引导启动
        SpringMainBootstrap.launch(MainApplication.class, args);
    }
    
    @Override
    public void run(String[] args) throws Exception {
        // 这里的写法和SpringBoot 启动保持一致
        SpringApplication.run(MainApplication.class, args);
    }
}
第三步:编写配置

更多配置详见here

plugin:
  # 运行模式, 开发环境: dev; 生产环境: prod
  runMode: prod
  # 主程序包名, 包名建议设置到范围最大级别,能包含主程序所有类的包名范围
  mainPackage: com.example.springbrick.application
  # 插件的路径, 可配置多个, 开发环境下配置为插件模块上级目录; 生产环境下配置到插件jar包存放目录。
  # 可使用~符号表示相对目录,比如:~/plugins,开发环境相对于开发根目录,生产环境下相对于主程序jar所在目录
  pluginPath:
    - C:/Users/Administrator/Desktop/plugin
第四步:设置maven插件
<!-- 本人引入此插件后,去除了spring-boot自身的打包插件 -->
<plugin>
    <groupId>com.gitee.starblues</groupId>
    <artifactId>spring-brick-maven-packager</artifactId>
    <version>3.1.1</version>
    <configuration>
        <mode>main</mode>
        <mainConfig>
            <!-- 指定main -->
            <mainClass>com.example.springbrick.application.MainApplication</mainClass>
            <packageType>jar</packageType>
        </mainConfig>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>repackage</goal>
            </goals>
        </execution>
    </executions>
</plugin>

2. 准备plugin-api

第一步:引入相关依赖
<dependency>
    <groupId>com.gitee.starblues</groupId>
    <artifactId>spring-brick</artifactId>
    <version>3.1.1</version>
    <!-- 这里指定为provided即可,主程序中已经存在此artifact了  -->
    <scope>provided</scope>
</dependency>
第二步:引入相关依赖

注意:各plugin-api的包名,应该处于主程序包名(本人这里为plugin.mainPackage=com.example.springbrick.application)的子集。如果不这样设置的话,主程序和插件实现程序加载plugin-api中的类时,将被类加载器隔离

根据自己业务需要,定义业务接口及相关pojo即可,如:

在这里插入图片描述

3. 实现plugin-api

提示:各plugin-api的实现程序,继承不继承父类plugin-api都可以

第一步:引入相关依赖

更多详见here

  • 架构级依赖

    <!-- 引入要实现的plugin-api -->
    <dependency>
        <groupId>com.example</groupId>
        <artifactId>plugin-xyz-api</artifactId>
        <version>1.0.0</version>
    </dependency>
    
    <!-- 引入spring-brick-bootstrap以完成插件的引导 -->
    <dependency>
        <groupId>com.gitee.starblues</groupId>
        <artifactId>spring-brick-bootstrap</artifactId>
        <version>3.1.1</version>
    </dependency>
    
    <!-- 和主程序引入同样的spring-brick,不过这里需要设置为provided -->
    <dependency>
        <groupId>com.gitee.starblues</groupId>
        <artifactId>spring-brick</artifactId>
        <version>3.1.1</version>
        <scope>provided</scope>
    </dependency>
    
  • 业务级依赖

    <!-- spring-boot-starter依赖 -->
    <!--建议将spring-boot-starter依赖放到第一个位置, 以防止出现依赖冲突导致无法启动插件-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
        <version>2.6.13</version>
    </dependency>
    
    <!-- spring-boot-starter-web依赖. 当插件需要独立启动时,需要引入此插件。但是当要打包成插件前,需要去除此依赖(因为主程序中已经存在此依赖了) -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>2.6.13</version>
        <scope>test</scope>
    </dependency>
            
    ...... 其他依赖
    
第二步:修改程序入口方法

更多详见here

import com.gitee.starblues.bootstrap.SpringPluginBootstrap;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * plugin start class
 */
@SpringBootApplication
public class PluginXyzApplication extends SpringPluginBootstrap {
    public static void main(String[] args) {
        new PluginXyzApplication().run(args);
    }
}
第三步:设置maven插件

更多详见here

<!-- 本人引入此插件后,去除了spring-boot自身的打包插件 -->
<plugin>
    <groupId>com.gitee.starblues</groupId>
    <artifactId>spring-brick-maven-packager</artifactId>
    <version>3.1.1</version>
    <configuration>
        <!--当前打包模式为: 开发模式-->
        <mode>prod</mode>
        <!--插件信息定义-->
        <pluginInfo>
            <!--插件id-->
            <id>plugin-xyz</id>
            <!--插件入口类, 定义说明见: 定义插件入口类-->
            <bootstrapClass>com.example.springbrick.plugin.xyz.PluginXyzApplication</bootstrapClass>
            <!--插件版本号-->
            <version>1.0.0</version>
        </pluginInfo>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>repackage</goal>
            </goals>
        </execution>
    </executions>
</plugin>

4. 测试验证

提示:本人这里进行简单验证说明,更多验证可以去文末下载源码,自己跑起来后完成验证

  • 第一步:打包所有插件实现,然后放到主程序配置文件中(plugin.pluginPath)指定的插件位置
    在这里插入图片描述

  • 第二步:启动主程序

      .   ____          _            __ _ _
     /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
    ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
     \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
      '  |____| .__|_| |_|_| |_\__, | / / / /
     =========|_|==============|___/=/_/_/_/
     :: Spring Boot ::               (v2.6.13)
    
    2023-06-07 15:27:55.223  INFO 20520 --- [       Thread-0] c.g.s.l.launcher.SpringMainBootstrap     : Starting SpringMainBootstrap using Java 17.0.3.1 on WIN-E500OMQS07D with PID 20520 (D:\maven\repository\com\gitee\starblues\spring-brick-loader\3.1.1\spring-brick-loader-3.1.1.jar started by Administrator in D:\working\demo)
    2023-06-07 15:27:55.224  INFO 20520 --- [       Thread-0] c.g.s.l.launcher.SpringMainBootstrap     : No active profile set, falling back to 1 default profile: "default"
    2023-06-07 15:27:55.430  INFO 20520 --- [       Thread-0] c.i.c.aop.ParameterRecorderRegistrar     : registry spring-bean parameterRecorder with ConstructorArg includePrefixes -> [], excludePrefixes -> [], parameterHandleMode -> USE_JSON, pretty -> true, ignoreParamTypes -> []
    2023-06-07 15:27:55.902  INFO 20520 --- [       Thread-0] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
    2023-06-07 15:27:55.909  INFO 20520 --- [       Thread-0] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
    2023-06-07 15:27:55.909  INFO 20520 --- [       Thread-0] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.68]
    2023-06-07 15:27:55.990  INFO 20520 --- [       Thread-0] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
    2023-06-07 15:27:55.990  INFO 20520 --- [       Thread-0] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 737 ms
    2023-06-07 15:27:56.246  INFO 20520 --- [       Thread-0] c.i.commonspring.aop.ParameterRecorder   : Set LocalVariableTableParameterNameDiscoverer as parameterNameDiscoverer.
    2023-06-07 15:27:56.358  INFO 20520 --- [       Thread-0] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
    2023-06-07 15:27:56.364  INFO 20520 --- [       Thread-0] c.g.s.l.launcher.SpringMainBootstrap     : Started SpringMainBootstrap in 1.377 seconds (JVM running for 1.736)
    2023-06-07 15:27:56.367  INFO 20520 --- [       Thread-0] c.g.s.i.operator.DefaultPluginOperator   : 插件加载环境: prod
    2023-06-07 15:27:56.367  INFO 20520 --- [       Thread-0] c.g.s.i.operator.DefaultPluginOperator   : 插件加载模式: isolation
    2023-06-07 15:27:56.367  INFO 20520 --- [       Thread-0] c.g.s.i.operator.DefaultPluginOperator   : 开始加载插件, 插件根路径为: 
    C:/Users/Administrator/Desktop/plugin
    2023-06-07 15:27:56.367  INFO 20520 --- [       Thread-0] c.g.s.s.web.PluginStaticResourceConfig   : 插件静态资源访问前缀配置为: /static-plugin/{pluginId}
    2023-06-07 15:27:56.382  INFO 20520 --- [       Thread-0] c.g.starblues.core.DefaultPluginManager  : 插件[plugin-qwer@1.0.0]加载成功
    2023-06-07 15:27:56.383  INFO 20520 --- [       Thread-0] c.g.starblues.core.DefaultPluginManager  : 插件[plugin-qwer2@1.0.0]加载成功
    2023-06-07 15:27:56.384  INFO 20520 --- [       Thread-0] c.g.starblues.core.DefaultPluginManager  : 插件[plugin-xyz@1.0.0]加载成功
    2023-06-07 15:27:57.446  INFO 20520 --- [       Thread-0] c.g.s.b.ConfigurePluginEnvironment       : Plugin[plugin-qwer@1.0.0]  No active profile set, falling back to default profiles : default
    2023-06-07 15:27:57.785  INFO 20520 --- [       Thread-0] c.g.starblues.core.DefaultPluginManager  : 插件[plugin-qwer@1.0.0]启动成功
    2023-06-07 15:27:58.690  INFO 20520 --- [       Thread-0] c.g.s.b.ConfigurePluginEnvironment       : Plugin[plugin-qwer2@1.0.0]  No active profile set, falling back to default profiles : default
    2023-06-07 15:27:59.033  INFO 20520 --- [       Thread-0] c.g.starblues.core.DefaultPluginManager  : 插件[plugin-qwer2@1.0.0]启动成功
    2023-06-07 15:27:59.938  INFO 20520 --- [       Thread-0] c.g.s.b.ConfigurePluginEnvironment       : Plugin[plugin-xyz@1.0.0]  No active profile set, falling back to default profiles : default
    2023-06-07 15:28:00.233  INFO 20520 --- [       Thread-0] c.g.starblues.core.DefaultPluginManager  : 插件[plugin-xyz@1.0.0]启动成功
    2023-06-07 15:28:00.234  INFO 20520 --- [       Thread-0] c.g.s.i.operator.DefaultPluginOperator   : 插件初始化完成
    
  • 访问测试类,观察控制台输出

    • 测试类长这样,访问localhost:8080/demo/hello-world接口即可

      提示:完整项目demo可去文末下载

      import com.example.springbrick.application.helper.DynamicClass;
      import com.example.springbrick.application.plugin.api.qwer.QwerService;
      import com.example.springbrick.application.plugin.api.xyz.XyzService;
      import com.example.springbrick.application.plugin.api.xyz.entity.IdInfo;
      import com.example.springbrick.application.plugin.api.xyz.entity.User;
      import com.gitee.starblues.integration.user.PluginUser;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
      
      import javax.annotation.Resource;
      import java.time.LocalDateTime;
      import java.util.Map;
      
      /**
       * 动态插件支持
       */
      @RestController
      @RequestMapping("/demo")
      public class DemoController {
          
          @Resource
          private PluginUser pluginUser;
          
          @GetMapping("hello-world")
          public void helloWorld() {
              User user = new User();
              user.setName("张三");
              user.setBirthday(LocalDateTime.now());
              IdInfo idInfo = new IdInfo();
              idInfo.setIdNumber("12345");
              idInfo.setExt("non");
              user.setIdInfo(idInfo);
              
              /* ------------------------------ 示例1 ------------------------------ */
              QwerService qwerService = pluginUser.getBeanByInterface("plugin-qwer", QwerService.class).get(0);
              System.err.println(qwerService.helloWorld());
              System.err.println(qwerService.helloWorld123("sdfsd"));
          
              XyzService xyzService = pluginUser.getBeanByInterface("plugin-xyz", XyzService.class).get(0);
              xyzService.helloWorld();
              System.err.println(xyzService.userInfo(user));
          
          
              System.err.println();
              System.err.println();
              
              /* ------------------------------ 示例2 ------------------------------ */
              Map<String, Object> pluginBean = pluginUser.getBean(QwerService.BEAN_NAME, false).getPluginBean();
              pluginBean.forEach((pluginId, springBean) -> {
                  System.err.println(pluginId + "      " + DynamicClass.exec(springBean, QwerService::helloWorld));
                  System.err.println(pluginId + "      " + DynamicClass.exec(springBean, QwerService.EMPTY_INSTANCE::helloWorld123, "123"));
              });
      
              pluginBean = pluginUser.getBean(XyzService.BEAN_NAME, false).getPluginBean();
              pluginBean.forEach((pluginId, springBean) -> {
                  DynamicClass.exec(springBean, XyzService::helloWorld);
                  System.err.println(pluginId + "      " + DynamicClass.exec(springBean, XyzService.EMPTY_INSTANCE::userInfo, user));
              });
          }
      }
      
    • 控制台输出

      在这里插入图片描述

相关资料

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

spring-boot集成spring-brick实现动态插件 的相关文章

  • larvel 生命周期理解

    参考 https www jianshu com p 08b810b720d9 不能理解服务器容器的强烈推荐这位大佬写的 https www cnblogs com JdsyJ p 12670497 html 今天学习下laravel的生命
  • 星图按转化线索回传对接思路与示例

    一 什么是星图 二 什么是线索转化 三 对接中的一些疑问 四 如何对接开发 五 星图侧如何联调测试 一 什么是星图 抖音星图是抖音电商蓝图下 为品牌方 MCN公司和明星 达人服务并收取分成 在这可以实现订单接收 签约管理 项目汇总 数据查看
  • 数值模拟使用matlab实现案例

    好的 我来为您讲解如何使用MATLAB来进行数值模拟 首先 您需要安装并打开MATLAB软件 然后 您可以在MATLAB的命令窗口中输入您要模拟的数学方程 并使用MATLAB的内置函数和符号进行运算 例如 如果您想对于y x 2进行模拟 您
  • 探索图像处理的利器——OpenCV

    目录 引言 一 OpenCV简介 二 OpenCV的特点 三 OpenCV的应用领域 四 实际案例 结论 引言 在当今信息化的时代 图像处理已经成为了日常生活中不可或缺的一部分 从社交媒体滤镜到自动驾驶系统 图像处理技术的广泛应用正在改变着
  • OpenCV+Mediapipe手势动作捕捉与Unity引擎的结合

    OpenCV Mediapipe手势动作捕捉与Unity引擎的结合 前言 Demo演示 认识Mediapipe 项目环境 手势动作捕捉部分 实时动作捕捉 核心代码 完整代码 Hands py py代码效果 Unity 部分 建模 Unity
  • C语言编程技巧 --- C语言中左移右移与乘除法的比较

    C语言中右移与除法的比较 最近在做项目的时候 遇到了一个有趣的现象 那就是 对于除2的整数次幂的操作而言 为了加快计算速度 一般情况下 会用右移 gt gt 来替代除法 但实际上 在VS中 右移等价于matlab中的floor 地板 操作
  • 登录认证功能的统一拦截技术(过滤器)

    目录 1 前言 2 过滤器 1 说明 2 使用步骤 3 说明示例 4 具体示例 5 过滤器详细说明 3 登录校验的过滤器实现 1 实现流程 2 具体实现 1 前言 前端发起请求 每次都会在请求头中携带JWT令牌到服务端 而服务端需要统一拦截
  • JSON.PARSE() 出现UNEXPECTED END OF JSON INPUT原因是什么怎么解决

    原因 打印出来的数据当中为判断题时数据是空的 当使用JSON parse字符串转数组时 如果里面数据有空 那么就会报错 做一个判断就好了 有才取值 if value var fileList JSON parse value else va
  • zTree 树插件实现全国五级地区点击后加载

    在项目功能中需要录入户籍地和现居住地 为减少用户输入量 将使用树插件选择全国五级地区 输入框输入详细地址 这里优先使用了zTree树插件 为了以后使用学习 在这里进行相关记录 当然在实现过程中参考各大神的文章是必不可少的 可以结合了自己的实
  • RS485利用地址主动仲裁驱动

    源码下载 MAX485 主动竞争驱动 rar C文档类资源 CSDN下载 引入背景 最近在工作中使用了RS485协议 之前虽然知道怎么用 但是实际应用到工程上还是第一次 在使用过程中就涉及到RS485总线的一些架构问题 我们都知道 RS48
  • [carla]关于odometry坐标中的角度坐标系 以及 到地图的映射问题

    1 获取车辆的Odometry原始信息 在carla中 通过订阅 carla ego vecle odometry 可以查看车辆的全局位置信息 例如 gt header seq 118872 stamp secs 5946 nsecs 57
  • C++ 二维数组vector如何添加空行

    在制作BP神经网络时 需要给vector添加一个空行 自己根据直觉进行了以下试探 发现并没有问题 include
  • C++析构函数的自动调用问题

    首先要明确一点 系统只会自动释放栈内空间 而堆内空间需要用户自己维护 C 中 除了new来的空间存放在堆内 其他均存放在栈中 当单纯的创建对象的时候 对象存放在栈中 此时在程序块的 后面 系统会自动调用析构函数 释放掉栈空间 但是 如果创建
  • 简述浏览器渲染流程

    近期的项目涉及到了前端的一系列知识 所以就简单的总结一下 因为不是前端人员 相关的概念可能不会分析的很深 如果说法有问题 希望路过的大佬们多多指教 下面说的大多是自己的理解 尽可能简洁又通俗 说到浏览器渲染 一个重要前提应该就是dom do
  • Ubuntu启动ftp服务

    Ubuntu启动ftp服务 1 安装vsftpd sudo apt get install vsftpd 2 修改ftp配置文件 注意要加sudo 否则无权限更改 sudo vi etc vsftpd conf 将 local enable
  • MySQL数据库入门实战教程

    目录 前言 一 创建建数据库 创建建数据表 查看数据库 查看数据表 二 新增 修改 删除表记录 三 基础查询 where子句查询 1 基础查询 2 WHERE子句查询 3 Like模糊查询 四 分组查询 聚合函数 排序查询 4 排序查询 5
  • 子集和问题

    子集和问题 描述 Description 问题描述 子集和问题的一个实例为 S t 其中 S x1 x2 xn 是一个正整数的集合 c是一个正整数 子集和问题判定是否存在S的一个子集S1 使得子集S1和等于c 编程任务 对于给定的正整数的集
  • 【数据结构】堆的实现(简单易懂,超级详细!!!)

    目录 1 堆的概念及结构 概念 规律 2 堆的实现 2 1结构设计 2 2接口实现 2 3 初始化 2 4堆的向下调整算法 主要思想 涉及问题 代码实现 2 5建堆 思想 代码实现 建堆的时间复杂度 2 6 堆的向上调整算法 主要思想 涉及
  • PyQt5常用模块、类、控件

    一 常用模块 QtCore 包含非核心的GUI功能 此模块用于处理时间 文件和目录 各种数据类型 流 URL MIME类型 线程或进程 QtGui 包括窗口系统集成 事件处理 二维图形 基本成像 字体和文本 QtWidgets 基本控件都位

随机推荐

  • Yii Framework 开发教程(33) Zii组件-Accordion示例

    Zii组件中包含了一些基于JQuery的UI组件 这些UI组件定义在包zii widgets jui中 包括CJuiAccordion CJuiAutoComplete CJuiDatePicker等 本篇介绍CJuiAccordion 显
  • ARM的37个寄存器和异常处理机制详解

    1 ARM的37个寄存器 ARM的37个寄存器中 30个寄存器是 通用 1个固定用作PC 程序控制寄存器 一个固定用作CPSR 程序状态寄存器 5个固定用作5种异常模式下的SPSR 程序状态保存寄存器 特别注意user模式和sys模式共用寄
  • SPI总线的原理

    一 简介 SPI Serial Peripheral Interface 串行外围设备接口 是Motorola公司提出的一种同步串行接口技术 是一种高速 全双工 同步通信总线 在芯片中只占用四根管脚用来控制及数据传输 广泛用于EEPROM
  • Unity PackageManager一直加载不到信息的解决方法

    关闭unity 断开网络连接 打开unity 这时候会加载出来 连接网络开始install
  • 牛客网——两数之和

    题目描述 给出一个整数数组 请在数组中找出两个加起来等于目标值的数 你给出的函数twoSum 需要返回这两个数字的下标 index1 index2 需要满足 index1 小于index2 注意 下标是从1开始的 假设给出的数组中只存在唯一
  • 解决error: subprocess-exited-with-error

    运行 pip install upgrade setuptools 即可解决
  • Playwright解决永久保存下载文件

    Playwright默认在浏览器关闭的时候 所有的临时文件都将删除 无论你是自定义位置还是默认位置 那么如何正确下载对应的文件呢 废话不多说 大家直接看以下代码即可 这里还是告诫大家一下 多研究官网的API文档 别学我慌慌张张去搞了 啥都没
  • QTP的那些事--项目实践操作案例代码--查询操作

    1 一下的代码记录的是我对于一个查询操作的自动化的思路 遗憾的是预期的结果可能需要手动输入到datatable中 以后逐步完善 将所有的预期值都自动输入到excel中 登陆系统 2 3 RunAction login loginsystem
  • HDS 存储名词解释

    DKU 扩展柜 DKC 控制柜 DKA 后端端口 CHA 前端端口 CSW 交换卡 SVP 内置服务PC 另一个含义是服务程序 CM Cache Memory数据内存 SM Share Memory共享内存 HDU Hard Disk Un
  • npoi全国计算机编程,NPOI 导入Excel

    NPOI 导入Excel public static List GetExcelToList string excelfileName List list new List ISheet sheet null PropertyInfo pr
  • Nginx进程管理

    Nginx进程管理 1 Nginx进程管理之master进程 监控进程充当整个进程组与用户的交互接口 同时对进程进行监护 它不需要处理网络事件 不负责业务的执行 只会通过管理worker进程来实现重启服务 平滑升级 更换日志文件 配置文件实
  • 利用lda对文本进行分类_使用lda进行文本分类

    利用lda对文本进行分类 LDA or Latent Dirichlet Allocation is one of the most widely used topic modelling algorithms It is scalable
  • Linux——gcc/g++以及make/Makefile的使用

    简介 在Linux的系统中 想要完成代码编译 gcc g 是不可缺少的工具 而make Makefile能否熟练应用则从一个侧面体现出一个人是否有能力独自完成一个大型工程 而本篇文章就带领大家了解一些gcc g 和make Makefile
  • 层叠上下文(stacking context)

    一 什么是层叠式上下文 层叠上下文 是HTML中的一个三维概念 如果元素具备以下任何一个条件 则该元素会创建一个新的层叠上下文 根元素 z index不为auto的定位元素 二 什么是层叠级别 同一个层叠上下文的背景色以及内部元素 谁在上谁
  • IPsec SA 创建步骤——IKE协议

    IPsec SA 创建步骤概述 IPsec SA creation steps There are two steps on the IPsec SA creation phase 1 is to creat IKE SA and phas
  • 为什么重写equals方法时必须重写hashcode方法

    文章目录 1 与 equals的区别 2 重写equals 3 为什么重写equals方法时必须重写hashcode方法 3 1 Hash算法 3 2 HashCode 相关文章 为什么重写equals方法时必须重写hashcode方法 J
  • 在vue页面中,直接展示代码及样式高亮(vue 中使用 highlight)

    参考链接 https blog csdn net u011364720 article details 90417302 前言 效果如下 想要在前端页面中 直接展示代码的样式 就像一些开发文档的源码展示一样 使用插件 highlight j
  • C++智能指针 shared_ptr,unique_ptr和weak_ptr

    1 智能指针为什么存在 因为C 没有自动回收内存的机制 因此每一次new出来的动态内存必须手动delete回去 因此智能指针可以解决这个问题 2 智能指针的大致描述是什么 智能指针 自动负责释放所指向的对象 实际上它利用了栈的机制 每一个智
  • Go语言基础知识4——依赖管理

    依赖 别人写的库 依赖其进行编译 依赖管理的三个阶段 GOPATH GOVENDOR go mod GOPATH和GOVENDOR正在向go mod迁移 一 GOPATH GOPATH是一个环境 就是一个目录 默认在 go unix lin
  • spring-boot集成spring-brick实现动态插件

    spring boot集成spring brick实现动态插件 spring boot集成spring brick实现动态插件 项目结构 需求实现 spring boot集成spring brick 环境说明 1 主程序集成spring b