4.3 Oinone的分布式体验

在oinone的体系中分布式比较独特,boot工程中启动模块中包含就走本地,不包含就走远程,本文带您体验下分布式部署以及分布式部署需要注意点。

看下面例子之前先把话术统一下:启动或请求SecondModule代表启动或请求pamirs-second-boot工程,启动或请求DemoModule代表启动或请求pamirs-demo-boot工程,并没有严格意义上启动哪个模块之说,只有启动工程包含哪个模块。

一、构建SecondModule模块

Step1 构建模块工程

参考3.2.1【构建第一个Module】一文,利用脚手架工具构建一个SecondModule,记住需要修改脚本。

脚本修改如下:

#!/bin/bash

# 项目生成脚手架
# 用于新项目的构建

# 脚手架使用目录
# 本地 local
# 本地脚手架信息存储路径 ~/.m2/repository/archetype-catalog.xml
archetypeCatalog=local

# 以下参数以pamirs-second为例

# 新项目的groupId
groupId=pro.shushi.pamirs.second

# 新项目的artifactId
artifactId=pamirs-second

# 新项目的version
version=1.0.0-SNAPSHOT

# Java包名前缀
packagePrefix=pro.shushi

# Java包名后缀
packageSuffix=pamirs.second

# 新项目的pamirs platform version
pamirsVersion=4.6.0

# Java类名称前缀
javaClassNamePrefix=Second

# 项目名称 module.displayName
projectName=OinoneSecond

# 模块 MODULE_MODULE 常量
moduleModule=second_core

# 模块 MODULE_NAME 常量
moduleName=SecondCore

# spring.application.name
applicationName=pamirs-second

# tomcat server address
serverAddress=0.0.0.0

# tomcat server port
serverPort=8090

# redis host
redisHost=127.0.0.1

# redis port
redisPort=6379

# 数据库名
db=demo

# zookeeper connect string
zkConnectString=127.0.0.1:2181

# zookeeper rootPath
zkRootPath=/second

mvn archetype:generate \
  -DinteractiveMode=false \
  -DarchetypeCatalog=${archetypeCatalog} \
  -DarchetypeGroupId=pro.shushi.pamirs.archetype \
  -DarchetypeArtifactId=pamirs-project-archetype \
  -DarchetypeVersion=4.6.0 \
  -DgroupId=${groupId} \
  -DartifactId=${artifactId} \
  -Dversion=${version} \
  -DpamirsVersion=${pamirsVersion} \
  -Dpackage=${packagePrefix}.${packageSuffix} \
  -DpackagePrefix=${packagePrefix} \
  -DpackageSuffix=${packageSuffix} \
  -DjavaClassNamePrefix=${javaClassNamePrefix} \
  -DprojectName="${projectName}" \
  -DmoduleModule=${moduleModule} \
  -DmoduleName=${moduleName} \
  -DapplicationName=${applicationName} \
  -DserverAddress=${serverAddress} \
  -DserverPort=${serverPort} \
  -DredisHost=${redisHost} \
  -DredisPort=${redisPort} \
  -Ddb=${db} \
  -DzkConnectString=${zkConnectString} \
  -DzkRootPath=${zkRootPath}

图4-3-1 构建一个名为SecondModule的模块

脚步执行生成工程如下:

image.png

图4-3-2 SecondModule的工程结构

Step2 调整配置

修改application-dev.yml文件

修改SecondModule的application-dev.yml的内容

  1. base库换成与DemoModule一样的配置,配置项为:pamirs.datasource.base
pamirs:
  datasource:   
        base:
      driverClassName: com.mysql.cj.jdbc.Driver
      type: com.alibaba.druid.pool.DruidDataSource
      url: jdbc:mysql://127.0.0.1:3306/demo_base?useSSL=false&allowPublicKeyRetrieval=true&useServerPrepStmts=true&cachePrepStmts=true&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&autoReconnect=true&allowMultiQueries=true
      username: root # 数据库用户
      password: oinone # 数据库用户对应的密码
      initialSize: 5
      maxActive: 200
      minIdle: 5
      maxWait: 60000
      timeBetweenEvictionRunsMillis: 60000
      testWhileIdle: true
      testOnBorrow: false
      testOnReturn: false
      poolPreparedStatements: true
      asyncInit: true

图4-3-3 base库换成与DemoModule一样的配置

  1. 修改后端Server的启动端口号为9091
server:
  address: 0.0.0.0
  port: 9091
  sessionTimeout: 3600

图4-3-4 修改后端Server的启动端口号为9091

修改bootstrap.yml文件

  1. 设置dubbo序列化方式为pamirs,记得DemoModule也要改。
spring:
  profiles:
    active: dev
  application:
    name: pamirs-second

pamirs:
  default:
    environment-check: true
    tenant-check: true

---
spring:
  profiles: dev
  cloud:
    config:
      enabled: false
      uri: http://127.0.0.1:7001
      label: master
      profile: dev
    nacos:
      server-addr: http://127.0.0.1:8848
      discovery:
        enabled: false
        namespace:
        prefix: application
        file-extension: yml
      config:
        enabled: false
        namespace:
        prefix: application
        file-extension: yml

dubbo:
  application:
    name: pamirs-second
    version: 1.0.0
  registry:
    address: zookeeper://127.0.0.1:2181
  protocol:
    name: dubbo
    port: -1
    serialization: pamirs
  scan:
    base-packages: pro.shushi
  cloud:
    subscribed-services:

---
spring:
  profiles: test
  cloud:
    config:
      enabled: false
      uri: http://127.0.0.1:7001
      label: master
      profile: test
    nacos:
      server-addr: http://127.0.0.1:8848
      discovery:
        enabled: false
        namespace:
        prefix: application
        file-extension: yml
      config:
        enabled: false
        namespace:
        prefix: application
        file-extension: yml

dubbo:
  application:
    name: pamirs-second
    version: 1.0.0
  registry:
    address: zookeeper://127.0.0.1:2181
  protocol:
    name: dubbo
    port: -1
    serialization: pamirs
  scan:
    base-packages: pro.shushi
  cloud:
    subscribed-services:

图4-3-5 修改bootstrap.yml文件

Step3 构建一个RemoteTestModel

package pro.shushi.pamirs.second.api.model;

import pro.shushi.pamirs.meta.annotation.Field;
import pro.shushi.pamirs.meta.annotation.Model;
import pro.shushi.pamirs.meta.base.common.CodeModel;

@Model.model(RemoteTestModel.MODEL_MODEL)
@Model(displayName = "远程测试模型",labelFields = "name")
public class RemoteTestModel extends CodeModel {

    public static final String MODEL_MODEL="second.RemoteTestModel";

    @Field(displayName = "name")
    private String name;

}

新建RemoteTestModel模型,用于远程调用体验:

图4-3-6 构建一个RemoteTestMode

Step4 新增SecondSessionHook

@Hook(module= SecondModule.MODULE_MODULE), 规定只有增对SecondModule模块访问的请求该拦截器才会生效,不然其他模块的请求都会被SecondSessionHook拦截。

package pro.shushi.pamirs.second.core.hook;

import org.springframework.stereotype.Component;
import pro.shushi.pamirs.meta.annotation.Hook;
import pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j;
import pro.shushi.pamirs.meta.api.core.faas.HookBefore;
import pro.shushi.pamirs.meta.api.dto.fun.Function;
import pro.shushi.pamirs.second.api.SecondModule;

@Component
@Slf4j
public class SecondSessionHook implements HookBefore {
    @Override
    @Hook(priority = 1,module= SecondModule.MODULE_MODULE)
    public Object run(Function function, Object... args) {
        log.info("second hook");
        return function;
    }
}

图4-3-7 新增SecondSessionHook

Step5 新建RemoteTestModelAction

在SecondModule中新建RemoteTestModelAction,自定义RemoteTestModel模型的queryPage函数。方便debug,看看效果

package pro.shushi.pamirs.second.core.action;

import pro.shushi.pamirs.meta.annotation.Function;
import pro.shushi.pamirs.meta.annotation.Model;
import pro.shushi.pamirs.meta.api.dto.condition.Pagination;
import pro.shushi.pamirs.meta.api.dto.wrapper.IWrapper;
import pro.shushi.pamirs.meta.constant.FunctionConstants;
import pro.shushi.pamirs.meta.enmu.FunctionOpenEnum;
import pro.shushi.pamirs.meta.enmu.FunctionTypeEnum;
import pro.shushi.pamirs.second.api.model.RemoteTestModel;

@Model.model(RemoteTestModel.MODEL_MODEL)
public class RemoteTestModelAction {

    @Function.Advanced(type= FunctionTypeEnum.QUERY)
    @Function.fun(FunctionConstants.queryPage)
    @Function(openLevel = {FunctionOpenEnum.API})
    public Pagination<RemoteTestModel> queryPage(Pagination<RemoteTestModel> page, IWrapper<RemoteTestModel> queryWrapper){
        return new RemoteTestModel().queryPage(page,queryWrapper);
    }

}

图4-3-8 新建RemoteTestModelAction

Step6 boot工程需要引入Oinone的RPC包

  1. 父pom的依赖管理中先加入pamirs-distribution-faas的依赖
<dependency>
  <groupId>pro.shushi.pamirs.distribution</groupId>
  <artifactId>pamirs-distribution-faas</artifactId>
  <version>${pamirs.boot.version}</version>
</dependency>

图4-3-9 父pom的依赖管理中先加入pamirs-distribution-faas的依赖

  1. 在pamirs-second-boot中增加入pamirs-distribution-faas的依赖
<dependency>
  <groupId>pro.shushi.pamirs.distribution</groupId>
  <artifactId>pamirs-distribution-faas</artifactId>
</dependency>

图4-3-10 在pamirs-second-boot中增加入pamirs-distribution-faas的依赖

  1. 为SecondApplication类增加类注解@EnableDubbo
@EnableDubbo
public class SecondApplication {
}

图4-3-11 为SecondApplication类增加类注解@EnableDubbo

Step7 启动SecondModule

别忘了启动指令要为INSTALL,参考DemoModule的启动说明

Step8 Second工程本地mvn install,方便DemoModule包依赖

二、DemoModule模块准备

Step1 DemoModule引入Oinone的RPC包和Second的API包

  1. 父pom的依赖管理中先加入pamirs-second-api和pamirs-distribution-faas的依赖
<dependency>
  <groupId>pro.shushi.pamirs.second</groupId>
  <artifactId>pamirs-second-api</artifactId>
  <version>1.0.0-SNAPSHOT</version>
</dependency>

<dependency>
  <groupId>pro.shushi.pamirs.distribution</groupId>
  <artifactId>pamirs-distribution-faas</artifactId>
  <version>${pamirs.boot.version}</version>
</dependency>

图4-3-12 依赖管理增加对应依赖包配置

  1. 在pamirs-demo-api中增加入pamirs-second-api的依赖
<dependency>
  <groupId>pro.shushi.pamirs.second</groupId>
  <artifactId>pamirs-second-api</artifactId>
</dependency>

图4-3-13 增加pamirs-second-api的依赖配置

  1. 在pamirs-demo-boot中增加入pamirs-distribution-faas的依赖
<dependency>
  <groupId>pro.shushi.pamirs.distribution</groupId>
  <artifactId>pamirs-distribution-faas</artifactId>
</dependency>

图4-3-14 增加pamirs-distribution-faas的依赖配置

  1. 为DemoApplication类增加类注解@EnableDubbo
@EnableDubbo
public class DemoApplication {
}

图4-3-15 为DemoApplication类增加类注解@EnableDubbo

Step2 修改DemoModule定义

修改DemoModule的依赖注解,增加SecondModule.MODULE_MODULE

@Module(dependencies = {SecondModule.MODULE_MODULE})

图4-3-16 注解方式申明DemoModule对SecondModule的依赖

Step3 修改pamirs-demo-boot的bootstrap.yml文件

参考SecondModule修改dubbo的序列化方式为pamirs

Step4 修改pamirs-demo-boot的DemoApplication

为依赖模块配置扫描包路径,修改DemoApplication增加second的扫描包,在日常开发中小伙伴的应用肯定不是以pamirs开头,所以大家别忘了SpringBoot的基本配置。在3.2.1【构建第一个Module】一文也提到我们在启动工程中需要配置启动模块和依赖模块的扫描路径。

image.png

图4-3-17 修改DemoApplication中关于SpringBoot的扫描包路径

三、分布式部署体验

以上工作准备好以后,我们就可以通过DemoModule来远程调用SecondModule。

第一个Case(前端把请求分别打到DemoModule、SecondModule)

在日常研发中,不同模块的菜单整合也是非常常见的,比如把B模块的菜单挂在A模块中。这个Case就是在讲解如何做到跨模块的菜单整合

Step1 修改前端工程的vue.config.js

利用node的proxy,分别把DemoCore转发到8090端口,把SecondCore转发到8091端口,把默认其他模块转发到8090端口。localhost还是127.0.0.1跟浏览器地址框输入保持一致

const WidgetLoaderPlugin = require('@kunlun/widget-loader/dist/plugin.js').default;
const Dotenv = require('dotenv-webpack');

module.exports = {
  lintOnSave: false,
  configureWebpack: {
    module: {
      rules: [
        {
          test: /\.widget$/,
          loader: '@kunlun/widget-loader',
        },
      ],
    },
    plugins: [new WidgetLoaderPlugin(), new Dotenv()],
    resolveLoader: {
      alias: {
        '@kunlun/widget-loader': require.resolve('@kunlun/widget-loader'),
      },
    },
  },
  devServer: {
    port: 8080,
    disableHostCheck: true,
    progress: false,
    proxy: {
      'pamirs/DemoCore': {
        // 支持跨域
        changeOrigin: true,
        target: 'http://localhost:8090',
      },
      'pamirs/SecondCore': {
          // 支持跨域
        changeOrigin: true,
        target: 'http://localhost:8091',
      },
      pamirs: {
          // 支持跨域
        changeOrigin: true,
        target: 'http://localhost:8090',
      },
    },
  },
};

图4-3-18 修改前端工程的vue.config.js

Step2 修改DemoMenus

增加一个RemoteTestModel的管理入口,这里需要指定菜单的module为DemoModule,不然应用会切换到SecondModule

@UxMenu("远程模型")@UxRoute(model = RemoteTestModel.MODEL_MODEL,module= DemoModule.MODULE_MODULE) class RemoteTestModelMenu{}

图4-3-19 修改DemoMenus

Step3 重启前端应用看效果

  1. 点击远程模型菜单,可以正常进行增、删、改、查操作。

image.png

图4-3-20 示例效果

  1. SecondSessionHook起作用

“second hook”并打印出来,前端请求没有再进过DemoModule再远程调用SecondModule,而是直接打到了SecondModule上。

image.png

图4-3-21 SecondSessionHook对应日志

第二个Case(跨模块代理,自动走远程)

Step1 新建RemoteTestModelProxy

在DemoModule中新建RemoteTestModelProxy代理继承RemoteTestModel

package pro.shushi.pamirs.demo.api.proxy;

import pro.shushi.pamirs.meta.annotation.Model;
import pro.shushi.pamirs.meta.enmu.ModelTypeEnum;
import pro.shushi.pamirs.second.api.model.RemoteTestModel;

@Model.model(RemoteTestModelProxy.MODEL_MODEL)
@Model.Advanced(type = ModelTypeEnum.PROXY)
@Model(displayName = "远程模型的代理",summary="远程模型的代理")
public class RemoteTestModelProxy extends RemoteTestModel {

    public static final String MODEL_MODEL="demo.RemoteTestModelProxy";

}

图4-3-22 新建RemoteTestModelProxy

Step2 修改DemoMenus

增加一个RemoteTestModelProxy的管理入口

@UxMenu("远程代理")@UxMenu.route(RemoteTestModelProxy.MODEL_MODEL) class RemoteTestModelProxyMenu{}

图4-3-23 增加一个RemoteTestModelProxy的管理入口

Step3 重启看效果

  1. 点击菜单【远程代理】

image.png

图4-3-24 示例效果

  1. 在SecondModule的RemoteTestModelAction中debug,会发现DemoModule会自动调用RemoteTestModel模型的queryPage。

image.png

图4-3-25 DemoModule远程调用RemoteTestModel模型的queryPage

  1. 但不走SecondSessionHook

“second hook”并没有打印出来,为什么?在3.4.3.2【面向切面-拦截器】一文中介绍到“不是前端直接发起的请求不会生效”,可能小伙伴有疑问,我不是前端点击的吗?是的,但经过DemoModule再调用SecondModule,系统会判定为后端调用。

第三个Case(远程调用自定义函数)

Step1 新增函数RemoteTestModelService和RemoteTestModelServiceImpl

SecondModule定义RemoteTestModelService,用于DemoModule的调用。SecondModule记得再次mvn install

package pro.shushi.pamirs.second.api.service;

import pro.shushi.pamirs.meta.annotation.Fun;
import pro.shushi.pamirs.meta.annotation.Function;
import pro.shushi.pamirs.meta.api.dto.condition.Pagination;
import pro.shushi.pamirs.meta.api.dto.wrapper.IWrapper;
import pro.shushi.pamirs.second.api.model.RemoteTestModel;

@Fun(RemoteTestModelService.FUN_NAMESPACE)
public interface RemoteTestModelService {

    String FUN_NAMESPACE ="second.RemoteTestModelService";
    @Function
    Pagination<RemoteTestModel> queryPage(Pagination<RemoteTestModel> page, IWrapper<RemoteTestModel> queryWrapper);
    @Function
    String hello(String name);
    @Function
    String remoteTest(RemoteTestModel remoteTest);
}

图4-3-26 新增RemoteTestModelService接口类

package pro.shushi.pamirs.second.core.service;

import org.springframework.stereotype.Component;
import pro.shushi.pamirs.meta.annotation.Fun;
import pro.shushi.pamirs.meta.annotation.Function;
import pro.shushi.pamirs.meta.api.dto.condition.Pagination;
import pro.shushi.pamirs.meta.api.dto.wrapper.IWrapper;
import pro.shushi.pamirs.second.api.model.RemoteTestModel;
import pro.shushi.pamirs.second.api.service.RemoteTestModelService;

@Fun(RemoteTestModelService.FUN_NAMESPACE)
@Component
public class RemoteTestModelServiceImpl implements RemoteTestModelService {

    @Override
    @Function
    public Pagination<RemoteTestModel> queryPage(Pagination<RemoteTestModel> page, IWrapper<RemoteTestModel> queryWrapper) {
        return new RemoteTestModel().queryPage(page,queryWrapper);
    }
    @Override
    @Function
    public String hello(String name) {
        return "hello" + name ;
    }

    @Override
    @Function
    public String remoteTest(RemoteTestModel remoteTest) {
        return "remoteTest" + remoteTest.getName() ;
    }
}

图4-3-27 新增RemoteTestModelServiceImpl实现类

Step2 新增RemoteTestModelProxyAction

  1. 新增RemoteTestModelProxyAction,并定义queryPage、hello、remoteTest等Action,方便前端点击测试

  2. 引入RemoteTestModelService,分别调用queryPage、hello、remoteTest方法

package pro.shushi.pamirs.demo.core.action;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import pro.shushi.pamirs.demo.api.proxy.RemoteTestModelProxy;
import pro.shushi.pamirs.framework.faas.utils.ArgUtils;
import pro.shushi.pamirs.meta.annotation.Action;
import pro.shushi.pamirs.meta.annotation.Function;
import pro.shushi.pamirs.meta.annotation.Model;
import pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j;–
import pro.shushi.pamirs.meta.api.dto.condition.Pagination;
import pro.shushi.pamirs.meta.api.dto.wrapper.IWrapper;
import pro.shushi.pamirs.meta.constant.FunctionConstants;
import pro.shushi.pamirs.meta.enmu.FunctionOpenEnum;
import pro.shushi.pamirs.meta.enmu.FunctionTypeEnum;
import pro.shushi.pamirs.second.api.model.RemoteTestModel;
import pro.shushi.pamirs.second.api.service.RemoteTestModelService;

@Model.model(RemoteTestModelProxy.MODEL_MODEL)
@Component
@Slf4j
public class RemoteTestModelProxyAction {
    @Autowired
    private RemoteTestModelService remoteTestModelService;

    @Function.Advanced(type= FunctionTypeEnum.QUERY)
    @Function.fun(FunctionConstants.queryPage)
    @Function(openLevel = {FunctionOpenEnum.API})
    public Pagination<RemoteTestModelProxy> queryPage(Pagination<RemoteTestModelProxy> page, IWrapper<RemoteTestModelProxy> queryWrapper){

        Pagination<RemoteTestModel> pageConvert = ArgUtils.convert(RemoteTestModelProxy.MODEL_MODEL,RemoteTestModel.MODEL_MODEL,page);
        IWrapper<RemoteTestModel> queryWrapperConvert = ArgUtils.convert(RemoteTestModelProxy.MODEL_MODEL,RemoteTestModel.MODEL_MODEL,queryWrapper);
        Pagination<RemoteTestModel> resultTmp=  remoteTestModelService.queryPage(pageConvert,queryWrapperConvert);
        Pagination<RemoteTestModelProxy> result = ArgUtils.convert(RemoteTestModel.MODEL_MODEL,RemoteTestModelProxy.MODEL_MODEL,resultTmp);
        return result;
    }

    @Action(displayName = "hello")
    public RemoteTestModelProxy hello(RemoteTestModelProxy data){
        String hello = remoteTestModelService.hello(data.getName());
        log.info(hello);
        return data;
    }
    @Action(displayName = "remoteTest")
    public RemoteTestModelProxy remoteTest(RemoteTestModelProxy data){
        RemoteTestModel s = ArgUtils.convert(RemoteTestModelProxy.MODEL_MODEL,RemoteTestModel.MODEL_MODEL,data);
        String testRemote = remoteTestModelService.remoteTest(s);
        log.info(testRemote);
        return data;
    }
}

图4-3-28 新增RemoteTestModelProxyAction

Step3 重启看效果

点击remoteTest按钮看看效果

image.png

图4-3-29 示例效果

总结一、二 、三 Case

把SecondModule模块停掉,则上面一、二 、三 Case都会报错。如果DemoModule的pamirs-demo-boot中依赖加上pamirs-second-core,同时application-dev.yml文件中pamirs.boot.modules加上second_core的配置,则DemoModule和SecondModule部署在一起,再把前端node请求代理都转发到DemoModule模块上。则只需要启动pamirs-demo-boot就可以了。这个留给小伙伴们自己实验。

分布式不分布式只是部署方式的差异,代码层面没有差异,有了体感以后再去看2.4.1【Oinone独特性之单体与分布式的灵活切换】一文可能会有更深的体会。

注意点:

  1. 【编码】远程调用服务时要确保入参和服务端定义的一样,可以用平台提供ArgUtils.convert进行转换

  2. 【部署】分布式情况下部署要用ng或其他方式进行转发,针对前端发起的请求,根据请求url中带的模块信息转发到对应有启动该模块的boot应用中

Oinone社区 作者:史, 昂原创文章,如若转载,请注明出处:https://doc.oinone.top/oio4/9310.html

访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验

(0)
史, 昂的头像史, 昂数式管理员
上一篇 2024年5月23日 am8:28
下一篇 2024年5月23日 am8:30

相关推荐

  • 4.1.11 函数之异步执行

    异步任务是非常常见的一种开发模式,它在分布式的开发模式中有很多应用场景如: 高并发场景中,我们一般采用把长流程切短,用异步方式去掉可以异步的非关键功能,缩小主流程响应时间,提升用户体验 异构系统的集成调用,通过异步任务完成解耦与自动重试 分布式系统最终一致性的可选方案 今天我们了解oinone是如何结合Spring+TbSchedule来完成异步任务 一、TbSchedule介绍 它是一个支持分布式的调度框架,让批量任务或者不断变化的任务能够被动态的分配到多个主机的JVM中,在不同的线程组中并行执行,所有的任务能够被不重复,不遗漏的快速处理。基于ZooKeeper的纯Java实现,由Alibaba开源。在互联网和电商领域TBSchedule的使用非常广泛,目前被应用于阿里巴巴、淘宝、支付宝、京东、聚美、汽车之家、国美等很多互联网企业的流程调度系统。也是笔者早期在阿里参与设计的一款产品。 oinone的异步任务执行原理(如下图4-1-11-1所示),先做一个大致了解: 图4-1-11-1 Oinone的异步任务执行原理图 基础管理工具 下载tbSchedule的控制台jar包去除文件后缀.txt(详见本书籍【附件一】)pamirs-middleware-schedule-console-3.0.1.jar.txt(31.2 MB) 启动控制台 java -jar pamirs-middleware-schedule-console-3.0.1.jar 图4-1-11-2 控制台启动方式 访问地址 http://127.0.0.1:10014/schedule/index.jsp?manager=true 图4-1-11-3 访问地址 配置zk连接参数 图4-1-11-4 配置zk连接参数 oinone默认实现任务类型 图4-1-11-5 Oinone默认实现任务类型 baseScheduleNoTransactionTask baseScheduleTask remoteScheduleTask — 适用于pamirs-middleware-schedule独立部署场景 serialBaseScheduleNoTransactionTask serialBaseScheduleTask serialRemoteScheduleTask — 适用于pamirs-middleware-schedule独立部署场景 cycleScheduleNoTransactionTask delayMsgTransferScheduleTask deleteTransferScheduleTask 注: a. 默认情况下:所有任务的任务项都只配置了一个任务项0,只有一台机器能分配任务。 1. 如果要修改配置可以在启动项目中放置schedule.json,来修改配置 2. 人工进入控制修改任务对应任务项的配置 b. 如果想为某一个核心任务配置的独立调度器,不受其他任务执行影响。那么见独立调度的异步任务 任务表相关说明 图4-1-11-6 任务表相关说明 二、构建第一个异步任务(举例) Step1 新建PetShopService和PetShopServiceImpl 1 新建PetShopService定义updatePetShops方法 package pro.shushi.pamirs.demo.api.service; import pro.shushi.pamirs.demo.api.model.PetShop; import pro.shushi.pamirs.meta.annotation.Fun; import pro.shushi.pamirs.meta.annotation.Function; import java.util.List; @Fun(PetShopService.FUN_NAMESPACE) public interface PetShopService { String FUN_NAMESPACE = "demo.PetShop.PetShopService"; @Function void updatePetShops(List<PetShop> petShops); } 图4-1-11-7 新建PetShopService定义updatePetShops方法 PetShopServiceImpl实现PetShopService接口并在updatePetShops增加@XAsync注解 displayName = "异步批量更新宠物商店",定义异步任务展示名称 limitRetryNumber = 3,定义任务失败重试次数,,默认:-1不断重试 nextRetryTimeValue = 60,定义任务失败重试的时间数,默认:3 nextRetryTimeUnit,定义任务失败重试的时间单位,默认:TimeUnitEnum.SECOND delayTime,定义任务延迟执行的时间数,默认:0 delayTimeUnit,定义任务延迟执行的时间单位,默认:TimeUnitEnum.SECOND package pro.shushi.pamirs.demo.core.service; import org.springframework.stereotype.Component; import pro.shushi.pamirs.demo.api.model.PetShop; import pro.shushi.pamirs.demo.api.service.PetShopService; import pro.shushi.pamirs.meta.annotation.Fun; import pro.shushi.pamirs.meta.annotation.Function; import pro.shushi.pamirs.trigger.annotation.XAsync; import java.util.List; @Fun(PetShopService.FUN_NAMESPACE) @Component public class PetShopServiceImpl implements PetShopService { @Override @Function @XAsync(displayName = "异步批量更新宠物商店",limitRetryNumber = 3,nextRetryTimeValue = 60) public void updatePetShops(List<PetShop> petShops) { new PetShop().updateBatch(petShops); } } 图4-1-11-8 实现PetShopService接口并在updatePetShops增加@XAsync注解 Step2 修改PetShopBatchUpdateAction的conform方法 引入PetShopService 修改conform方法 利用ArgUtils进行参数转化,ArgUtils会经常用到。 调用petShopService.updatePetShops方法 package pro.shushi.pamirs.demo.core.action; …… 引依赖类 @Model.model(PetShopBatchUpdate.MODEL_MODEL) @Component public class PetShopBatchUpdateAction { @Autowired private PetShopService petShopService; ……其他代码 @Action(displayName = "确定",bindingType = ViewTypeEnum.FORM,contextType = ActionContextTypeEnum.SINGLE) public PetShopBatchUpdate conform(PetShopBatchUpdate data){ if(data.getPetShopList() == null || data.getPetShopList().size()==0){ throw…

    2024年5月23日
    1.1K00
  • 翻译

    翻译应用是管理翻译规则的应用,以模型为基础、维护字段的翻译值,支持导入、导出 1. 操作步骤 Step1:导出所有翻译项; Step2:线下翻译; Step3:导入翻译项; Step4:刷新远程资源; Step5:页面右上角可切换语言,查看翻译效果。 2. 新增翻译 翻译是具体到模型字段,其中需要区分出是否字典; 源语言、目标语言,是在资源中维护的语言,可在资源中维护需要翻译的语言; 翻译项则是模型字段,默认翻译项为激活状态,关闭后维护的翻译项无效。 3. 导出、导入 不勾选导出:导出所有需要翻译的翻译项,包括模块、字段,源术语、翻译值等,其中如果已经翻译过的内容,会体现在翻译值中; 勾选导出:导出勾选模型的翻译项。 导入:导入翻译项,平台会根据模型拆分为多条数据。 4. 刷新远程资源 导入翻译项后,点击“刷新远程资源”按钮。 5. 查看翻译内容 页面右上角切换语言,查看翻译效果。

    2024年6月20日
    1.1K00
  • 3.4.3.1 面向对象-继承与多态

    本节为小伙伴们介绍,Function的面向对象的特性:继承与多态; 一、继承 我们在3.4.1【构建第一个Function】一文中伴随模型新增函数和独立类新增函数绑定到模型部分都是在父模型PetShop新增了sayHello的Function,同样其子模型都具备sayHello的Function。因为我们是通过Function的namespace来做依据的,子模型在继承父模型的sayHello函数后会以子模型的编码为namespace,名称则同样为sayHello。 二、多态(举例) oinone的多态,我们只提供覆盖功能,不提供重载,因为oinone相同name和fun的情况下不会去识别参数个数和类型。 Step1 为PetShop新增hello函数 package pro.shushi.pamirs.demo.api.model; …… //import @Model.model(PetShop.MODEL_MODEL) @Model(displayName = "宠物店铺",summary="宠物店铺",labelFields ={"shopName"} ) @Model.Code(sequence = "DATE_ORDERLY_SEQ",prefix = "P",size=6,step=1,initial = 10000,format = "yyyyMMdd") public class PetShop extends AbstractDemoIdModel { public static final String MODEL_MODEL="demo.PetShop"; …… //省略其他代码 @Function(openLevel = FunctionOpenEnum.API) @Function.Advanced(type= FunctionTypeEnum.QUERY) public PetShop sayHello(PetShop shop){ PamirsSession.getMessageHub().info("Hello:"+shop.getShopName()); return shop; } @Function(name = "sayHello2",openLevel = FunctionOpenEnum.API) @Function.Advanced(type= FunctionTypeEnum.QUERY) @Function.fun("sayHello2") public PetShop sayHello(PetShop shop, String s) { PamirsSession.getMessageHub().info("Hello:"+shop.getShopName()+",s:"+s); return shop; } @Function(openLevel = FunctionOpenEnum.API) @Function.Advanced(type= FunctionTypeEnum.QUERY) public PetShop hello(PetShop shop){ PamirsSession.getMessageHub().info("Hello:"+shop.getShopName()); return shop; } } 图3-4-3-1 为PetShop新增hello函数 Step2 为PetShopProxyB新增对应的三个函数 其中PetShopProxyB新增的hello函数,在java中是重载了hello,在代码中new PetShopProxyB()是可以调用父类的sayHello单参方法,也可以调用本类的双参方法。但在oinone的体系中对于PetShopProxyB只有一个可识别的Function就是双参的sayHello package pro.shushi.pamirs.demo.api.proxy; import pro.shushi.pamirs.demo.api.model.PetCatItem; import pro.shushi.pamirs.demo.api.model.PetShop; import pro.shushi.pamirs.meta.annotation.Field; import pro.shushi.pamirs.meta.annotation.Function; import pro.shushi.pamirs.meta.annotation.Model; import pro.shushi.pamirs.meta.api.session.PamirsSession; import pro.shushi.pamirs.meta.enmu.FunctionOpenEnum; import pro.shushi.pamirs.meta.enmu.FunctionTypeEnum; import pro.shushi.pamirs.meta.enmu.ModelTypeEnum; import java.util.List; @Model.model(PetShopProxyB.MODEL_MODEL) @Model.Advanced(type = ModelTypeEnum.PROXY,inherited ={PetShopProxy.MODEL_MODEL,PetShopProxyA.MODEL_MODEL} ) @Model(displayName = "宠物店铺代理模型B",summary="宠物店铺代理模型B") public class PetShopProxyB extends PetShop { public static final String MODEL_MODEL="demo.PetShopProxyB"; @Field.one2many @Field(displayName = "萌猫商品列表") @Field.Relation(relationFields = {"id"},referenceFields = {"shopId"}) private List<PetCatItem> catItems; @Function(openLevel = FunctionOpenEnum.API) @Function.Advanced(type= FunctionTypeEnum.QUERY) public PetShop sayHello(PetShop shop){ PamirsSession.getMessageHub().info("PetShopProxyB Hello:"+shop.getShopName()); return shop; } @Function(name = "sayHello2",openLevel = FunctionOpenEnum.API) @Function.Advanced(type= FunctionTypeEnum.QUERY) @Function.fun("sayHello2") public PetShop sayHello(PetShop shop,String hello){ PamirsSession.getMessageHub().info("PetShopProxyB say:"+hello+","+shop.getShopName()); return shop; } @Function(openLevel = FunctionOpenEnum.API)…

    2024年5月23日
    1.3K00
  • 4.1.24 框架之分库分表

    随着数据库技术的发展如分区设计、分布式数据库等,业务层的分库分表的技术终将成老一辈程序员的回忆,谈笑间扯扯蛋既羡慕又自吹地说到“现在的研发真简单,连分库分表都不需要考虑了”。竟然这样为什么要写这篇文章呢?因为现今的数据库虽能解决大部分场景的数据量问题,但涉及核心业务数据真到过亿数据后性能加速降低,能给的方案都还有一定的局限性,或者说性价比不高。相对性价比比较高的分库分表,也会是现阶段一种不错的补充。言归正传oinone的分库分表方案是基于Sharding-JDBC的整合方案,所以大家得先具备一点Sharding-JDBC的知识。 一、分表(举例) 做分库分表前,大家要有一个明确注意的点就是分表字段的选择,它是非常重要的,与业务场景非常相关。在明确了分库分表字段以后,甚至在功能上都要做一些妥协。比如分库分表字段在查询管理中做为查询条件是必须带上的,不然效率只会更低。 Step1 新建ShardingModel模型 ShardingModel模型是用于分表测试的模型,我们选定userId作为分表字段。分表字段不允许更新,所以这里更新策略设置类永不更新,并在设置了在页面修改的时候为readonly package pro.shushi.pamirs.demo.api.model; import pro.shushi.pamirs.boot.base.ux.annotation.field.UxWidget; import pro.shushi.pamirs.boot.base.ux.annotation.view.UxForm; import pro.shushi.pamirs.meta.annotation.Field; import pro.shushi.pamirs.meta.annotation.Model; import pro.shushi.pamirs.meta.enmu.FieldStrategyEnum; @Model.model(ShardingModel.MODEL_MODEL) @Model(displayName = "分表模型",summary="分表模型",labelFields ={"name"} ) public class ShardingModel extends AbstractDemoIdModel { public static final String MODEL_MODEL="demo.ShardingModel"; @Field(displayName = "名称") private String name; @Field(displayName = "用户id",summary = "分表字段",immutable=true/* 不可修改 **/) @UxForm.FieldWidget(@UxWidget(readonly = "scene == 'redirectUpdatePage'"/* 在编辑页面只读 **/ )) @Field.Advanced(updateStrategy = FieldStrategyEnum.NEVER) private Long userId; } 图4-1-24-1 新建ShardingModel模型 Step2 配置分表策略 配置ShardingModel模型走分库分表的数据源pamirsSharding 为pamirsSharding配置数据源以及sharding规则 a. pamirs.sharding.define用于oinone的数据库表创建用 b. pamirs.sharding.rule用于分表规则配置 pamirs: load: sessionMode: true framework: system: system-ds-key: base system-models: – base.WorkerNode data: default-ds-key: pamirs ds-map: base: base modelDsMap: "[demo.ShardingModel]": pamirsSharding #配置模型对应的库 图4-1-24-2 指定模型对应数据源 pamirs: sharding: define: data-sources: ds: pamirs pamirsSharding: pamirs #申明pamirsSharding库对应的pamirs数据源 models: "[trigger.PamirsSchedule]": tables: 0..13 "[demo.ShardingModel]": tables: 0..7 table-separator: _ rule: pamirsSharding: #配置pamirsSharding库的分库分表规则 actual-ds: – pamirs #申明pamirsSharding库对应的pamirs数据源 sharding-rules: # Configure sharding rule ,以下配置跟sharding-jdbc配置一致 – tables: demo_core_sharding_model: #demo_core_sharding_model表规则配置 actualDataNodes: pamirs.demo_core_sharding_model_${0..7} tableStrategy: standard: shardingColumn: user_id shardingAlgorithmName: table_inline shardingAlgorithms: table_inline: type: INLINE props: algorithm-expression: demo_core_sharding_model_${(Long.valueOf(user_id) % 8)} props: sql.show: true 图4-1-24-3 分库分表规则配置 Step3 配置测试入口 修改DemoMenus类增加一行代码,为测试提供入口 @UxMenu("分表模型")@UxRoute(ShardingModel.MODEL_MODEL) class ShardingModelMenu{} 图4-1-24-4 配置测试入口 Step4 重启看效果 自行尝试增删改查 观察数据库表与数据分布 图4-1-24-5 自行尝试增删改查 图4-1-24-6 观察数据库表与数据分布 二、分库分表(举例) Step1 新建ShardingModel2模型 ShardingModel2模型是用于分库分表测试的模型,我们选定userId作为分表字段。分库分表字段不允许更新,所以这里更新策略设置类永不更新,并在设置了在页面修改的时候为readonly package pro.shushi.pamirs.demo.api.model; import pro.shushi.pamirs.boot.base.ux.annotation.field.UxWidget; import pro.shushi.pamirs.boot.base.ux.annotation.view.UxForm; import…

    2024年5月23日
    1.3K00
  • 4.5 研发辅助

    这里都是一些提升研发效率的小工具

    Oinone 7天入门到精通 2024年5月23日
    1.4K00

Leave a Reply

登录后才能评论