什么是spi SPI就是Service Provider Interface,是一种动态的服务发现机制。 可以基于运行时动态的加载接口的实现类。通过(接口编程 + 策略模式 + 配置文件) 实现解耦和扩展。
应用 数据库驱动 基于该接口的实现有MySQL,PostgreSQL,SqlServer等。 SLF4J日志框架 Dubbo的SPI扩展 dubbo apache shenyu spring boot starter jdbc的应用 日志的应用 apache shenyu的spi应用 dubbo的spi应用 实现方式 市面上常见的SPI的实现方式有:
JDK的SPI实现 Dubbo的SPI实现、ShenYu的 SPI Spring的SPI实现 JDK的SPI实现流程为
在类路径的META-INF/services目录创建一个以接口全限定名称命名的文件(本质是一个properties)文件,例如命名为java.sql.Driver 该文件中可以指定具体的实现类,也就是每个实现类的全类型限定名为单独一行 例如 META-INF/services/java.sql.Driver # META-INF/services/java.sql.Driver文件内容 com.mysql.jdbc.Driver org.postgresql.Driver 最后通过java.util.ServiceLoader对该文件进行加载,实例化接口的对应实现类(这里隐含了一个约定,所有实现类必须提供无参构造函数,用来反射调用) 底层的实现涉及到类加载、双亲委派等内容,这里不展开。基于这种设计思路,很多主流框架实现了一套SPI扩展,例如Dubbo的SPI扩展模块,就是读取类路径 下META-INF/services/dubbo目录的文件内容进行类加载。ShenYu-SPI模块也是沿用类似的设计思路。
JDK SPI 的代码示例 接口定义 public interface Search { public List<String> searchDoc(String keyword); } 实现类 public class FileSearch implements Search{ @Override public List<String> searchDoc(String keyword) { System.out.println("文件搜索 "+keyword); return null; } } public class DatabaseSearch implements Search{ @Override public List<String> searchDoc(String keyword) { System.
dubbo是否有对文件上传下载导入导出的支持 项目当前架构: HTTP请求 -> 网关SpringCloudGateway -> 网关路由匹配 -> 网关dubbo泛化调用 -> dubbo服务 但与文件相关的操作,还是需要以Controller的形式暴露服务,因为涉及HttpServletResponse、ModelAndView、MultipartFile这些对象,如: @PostMapping("/upload") public Result uploadFile(@RequestParam("file") MultipartFile file) { ...... } **问题:**请问dubbo可支持文件类型的操作,向外暴露服务,从而去除掉controller ? 对于大文件类型的操作,我们建议在首次接收到 MultipartFile 请求之后将文件存储到 HDFS 或者 OSS 等存储介质上,然后在后端传递的时候直接通过一个标识符传递。对于小文件,将 file 转换成 byte 数组传递就行。 这个想的有点大,dubbo专注于分布式式RPC框架,如果把MVC功能,或者消息堆积之类的功能都实现了,就不太好专注于RPC,想的大一些其实可以考虑一些子项目Dubbo-MVC, Dubbo-MQ ,Dubbo-Framework 😄 dubbo是否有对文件上传下载导入导出的支持
打包常用的命令 # example打包 ./mvnw -B clean install -Pexample -DskipTests -f ./shenyu-examples/shenyu-examples-springcloud/pom.xml ./mvnw -B clean install -Pexample -DskipTests -f ./shenyu-examples/shenyu-examples-dubbo/pom.xml ./mvnw -B clean install -Pexample -DskipTests -f ./shenyu-examples/shenyu-examples-http/pom.xml ./mvnw -B clean install -DskipTests -f ./shenyu-client/pom.xml ./mvnw -B clean install -Pexample -DskipTests -f ./shenyu-examples/pom.xml ./mvnw -B clean install -Prelease -DskipTests -f ./shenyu-dist/pom.xml ./mvnw -B clean install -Pdocker -DskipTests -f ./shenyu-dist/pom.xml # 集成测试打包 ./mvnw -B clean install -Pit -DskipTests -f ./shenyu-integrated-test/shenyu-integrated-test-spring-cloud/pom.xml ./mvnw -B clean install -Pit -DskipTests -f .
这里是Markdown 正文 hello world
非正规集成测试和性能测试 6月份公司最重要的续费活动就要开始了,期间功能方面的改动不是特别大。但需要做性能测试和全部数据方面的验证。 基于以上(全部数据的验证、性能测试)目的,于是需要对接口进行性能测试。
1、工具调研 在工具调研方面,市面上常见的性能测试工具有以下。
JMeter Apache Bench TestNG LoadRunner 基于熟悉上手和对公司业务数据的了解程度,最后选择了TestNG。原因有:
编码方便,灵活 数据驱动方式还不错 灵活的设置线程数 基于TestNG可以很灵活的设计一样宽表来保存结果集。 最后设计的表结构如下 create table renewalintegrationtesting.t_2023_renewal_list ( id bigint auto_increment primary key, student_num varchar(128) null, student_id varchar(36) null, phone varchar(255) null, customer_id varchar(500) null, app_token varchar(255) null, authorization varchar(255) null, step1_url varchar(500) null comment '步骤一的接口地址', step1_request text null, step1_response text null, step1_success tinyint default 0 not null comment '步骤一执行结果0-不成功1-成功', step2_url varchar(500) null comment '步骤二的接口地址', step2_request text null, step2_response text null, step2_success tinyint default 0 not null comment '步骤二执行结果0-不成功1-成功', step3_url varchar(500) null comment '步骤3的接口地址', step3_request text null, step3_response text null, step3_success tinyint default 0 not null comment '步骤3执行结果0-不成功1-成功', step4_url varchar(500) null comment '步骤4的接口地址', step4_request text null, step4_response text null, step4_success tinyint default 0 not null comment '步骤4执行结果0-不成功1-成功', step5_url varchar(500) null comment '步骤5的接口地址', step5_request text null, step5_response text null, step5_success tinyint default 0 not null comment '步骤5执行结果0-不成功1-成功', step6_url varchar(500) null comment '步骤6的接口地址', step6_request text null, step6_response text null, step6_success tinyint default 0 not null comment '步骤6执行结果0-不成功1-成功', step7_url varchar(500) null comment '步骤7的接口地址', step7_request text null, step7_response text null, step7_success tinyint default 0 not null comment '步骤7执行结果0-不成功1-成功', step8_url varchar(500) null comment '步骤8的接口地址', step8_request text null, step8_response text null, step8_success tinyint default 0 not null comment '步骤8执行结果0-不成功1-成功', step9_url varchar(500) null comment '步骤9的接口地址', step9_request text null, step9_response text null, step9_success tinyint default 0 not null comment '步骤9执行结果0-不成功1-成功', step10_url varchar(500) null comment '步骤10的接口地址', step10_request text null, step10_response text null, step10_success tinyint default 0 not null comment '步骤10执行结果0-不成功1-成功' ); 2、测试用例的编写 示例测试用例代码如查看订单列表
重构AbstractShenyuPlugin.execute()方法 原来的执行流程 initMatchCacheConfig(); String pluginName = named(); PluginData pluginData = BaseDataCache.getInstance().obtainPluginData(pluginName); if (Objects.nonNull(pluginData) && pluginData.getEnabled()) { final String path = exchange.getRequest().getURI().getPath(); SelectorData selectorData = obtainSelectorDataCacheIfEnabled(exchange); if (Objects.isNull(selectorData)) { List<SelectorData> selectors = BaseDataCache.getInstance().obtainSelectorData(pluginName); if (CollectionUtils.isEmpty(selectors)) { return handleSelectorIfNull(pluginName, exchange, chain); } Pair<Boolean, SelectorData> matchSelectorData = matchSelector(exchange, selectors); selectorData = matchSelectorData.getRight(); if (Objects.isNull(selectorData)) { if (matchCacheConfig.getSelectorEnabled() && matchSelectorData.getLeft()) { selectorData = new SelectorData(); selectorData.setPluginName(named()); cacheSelectorData(path, selectorData); } return handleSelectorIfNull(pluginName, exchange, chain); } else { if (matchCacheConfig.