1.基于Springboot对SpringEvent初步封装

news2024/11/16 19:42:54

一:前置知识

Spring Event是Spring框架提供的一种事件机制,用于处理组件之间的通信。在复杂的系统中,模块或组件之间的通信是必不可少的。Spring Event可以用于以下场景:

1.系统间解耦:模块或组件之间通过事件进行通信,而不需要相互依赖。

2.异步处理:通过事件,可以异步处理某些任务,提高系统的处理能力。

3.日志记录:通过监听事件,记录系统的运行情况,如用户登录、数据修改等

注:业务系统一定要先实现优雅关闭服务,才能使用 Spring Event,这个和MQ还是有点区别,Spring Event和 MQ 都属于订阅发布模式的应用,然而 MQ 比 SpringEvent 强大且复杂。MQ 更适合应用之间的解耦、隔离、事件通知。例如订单支付、订单完成、订单履约完成等等事件需要广播出去,通知下游其他微服务, 这种场景更适合使用 MQ 。

然而对于应用内需要订阅发布的场景更适合使用 SpringEvent。两者并不矛盾,MQ 能力更强大,技术方案也更”重“一些。Spring Event 更加小巧适合应用内订阅发布,实现业务逻辑解耦。
像我之前的公司里。订单服务内部使用的是Spring Event 进行订单内部逻辑的异步和解耦。订单服务和其他服务之间使用的是Kafka来进行的解耦合数据通信。

二:基础封装

代码层级接口见下截图
在这里插入图片描述
base包里的对象

package com.jinyi.event.base;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.springframework.context.ApplicationEvent;

import java.time.Clock;

public class BaseEvent extends ApplicationEvent {
    public BaseEvent() {
        super("");
    }
    public BaseEvent(Object source) {
        super(source);
    }

    public BaseEvent(Object source, Clock clock) {
        super(source, clock);
    }

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this);
    }
}
package com.jinyi.event.base;

import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Component
public class EventBusCenter {

    @Resource
    private ApplicationEventPublisher applicationEventPublisher;

    public void post(BaseEvent event) {
        applicationEventPublisher.publishEvent(event);
    }
}
package com.jinyi.event.base;

import com.jinyi.event.enums.OrderTrackTypeEnum;
import lombok.Data;

import java.io.Serializable;

@Data
public class OrderStatusChangeDTO implements Serializable {
    private static final long serialVersionUID = 1L;

    private Long userId;
    private Long orderNo;
    private OrderTrackTypeEnum orderStatusChange;

    public OrderStatusChangeDTO() {

    }

    public OrderStatusChangeDTO(Long orderNo, OrderTrackTypeEnum orderStatusChange) {
        this();
        this.orderNo = orderNo;
        this.orderStatusChange = orderStatusChange;
    }

    public OrderStatusChangeDTO(Long userId, Long orderNo, OrderTrackTypeEnum orderStatusChange) {
        this();
        this.orderNo = userId;
        this.orderNo = orderNo;
        this.orderStatusChange = orderStatusChange;
    }
}

业务事件里的对象

package com.jinyi.event.bizEvent;

import com.jinyi.event.base.OrderStatusChangeDTO;
import com.jinyi.event.enums.OrderTrackTypeEnum;

/**
 * 订单支付事件
 * @date 2024/4/19 15:55
 * @desc
 */
public class OrderPayEvent extends OrderStatusChangeEvent {


    public OrderPayEvent(Object source, OrderStatusChangeDTO dto) {
        super(source, dto);
        if (null == dto.getOrderStatusChange()) {
            dto.setOrderStatusChange(defaultStatus());
        }
    }

    private OrderTrackTypeEnum defaultStatus() {
        return OrderTrackTypeEnum.ORDER_PAY;
    }
}
package com.jinyi.event.bizEvent;

import com.jinyi.event.base.BaseEvent;
import com.jinyi.event.base.OrderStatusChangeDTO;
import lombok.Data;
import lombok.EqualsAndHashCode;

/**
 * 订单变化事件BaseEvent对象 :存放该事件通用的param
 *
 * @date 2024/4/19 15:46
 * @desc
 */
@Data
@EqualsAndHashCode(callSuper = true)
public class OrderStatusChangeEvent extends BaseEvent {
    private OrderStatusChangeDTO orderStatusChangeDTO;

    public OrderStatusChangeEvent(Object source, OrderStatusChangeDTO dto) {
        super(source);
        this.orderStatusChangeDTO = dto;
    }
}
package com.jinyi.event.bizEvent;

import com.jinyi.event.base.OrderStatusChangeDTO;
import com.jinyi.event.enums.OrderTrackTypeEnum;

/**
 * @date 2024/4/19 16:02
 * @desc
 */
public class OrderUserCancelEvent extends OrderStatusChangeEvent {


    public OrderUserCancelEvent(Object source, OrderStatusChangeDTO dto) {
        super(source, dto);
        if (null == dto.getOrderStatusChange()) {
            dto.setOrderStatusChange(defaultStatus());
        }
    }

    private OrderTrackTypeEnum defaultStatus() {
        return OrderTrackTypeEnum.USER_CANCEL;
    }
}
package com.jinyi.event.bizEvent;

import com.jinyi.event.base.OrderStatusChangeDTO;
import com.jinyi.event.enums.OrderTrackTypeEnum;
import lombok.Getter;

/**
 * 扣减库存事件
 * @date 2024/4/19 15:55
 * @desc
 */

public class StockReduceEvent extends OrderStatusChangeEvent{
    @Getter
    private final Long goodsId;

    public StockReduceEvent(Object source, OrderStatusChangeDTO dto, Long goodsId) {
        super(source, dto);
        this.goodsId = goodsId;
        if (null == dto.getOrderStatusChange()) {
            dto.setOrderStatusChange(defaultStatus());
        }
    }

    private OrderTrackTypeEnum defaultStatus() {
        return OrderTrackTypeEnum.STOCK_REDUCE;
    }
}

config配置包里相关信息

package com.jinyi.event.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import javax.annotation.Resource;

/**
 * 实现异步处理事件配置
 * @date 2024/4/19 15:31
 * @desc
 */
@Configuration
public class EventConfig {
    
    @Resource
    @Qualifier("asyncTaskExecutor")
    private ThreadPoolTaskExecutor taskExecutor;

    /**
     * 默认情况下,事件会被同步发送给所有监听器,这意味着如果监听器耗时较长,则会阻塞后续的监听器和发布线程.
     * @return
     */
    @Bean
    public SimpleApplicationEventMulticaster applicationEventMulticaster() {
        SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster();
        multicaster.setTaskExecutor(taskExecutor);
        return multicaster;
    }
}
package com.jinyi.event.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

@Configuration
@EnableAsync
public class ExecutorConfig {

    @Value("${executor.corePoolSize:4}")
    private Integer corePoolSize;

    @Value("${executor.queueCapacity:1000}")
    private Integer queueCapacity;

    @Value("${executor.maxPoolSize:6}")
    private Integer maxPoolSize;

    @Value("${executor.keepAliveSeconds:30}")
    private Integer keepAliveSeconds;

    @Value("${executor.threadNamePrefix:async-executor-}")
    private String threadNamePrefix;

    /**
     * 线程池
     * @return
     */
    @Bean
    public ThreadPoolTaskExecutor asyncTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setThreadNamePrefix(threadNamePrefix);
        executor.setCorePoolSize(corePoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.setMaxPoolSize(maxPoolSize);
        //线程大于coreSize,多余线程数超过30s则销毁
        executor.setKeepAliveSeconds(keepAliveSeconds);
        // 设置拒绝策略,调用当前线程执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}

事件类型枚举包

package com.jinyi.event.enums;


public enum OrderTrackTypeEnum {

    ORDER_CREATE("order_create", "用户下单"),
    ORDER_PAY("order_pay", "完成支付"),

    ORDER_FINISH("order_finish", "订单完成"),

    USER_CANCEL("user_cancel","用户取消订单"),

    STOCK_REDUCE("stock_reduce","扣减库存"),
    ;
    private String operatorType;
    private String describe;

    OrderTrackTypeEnum(String operatorType, String describe) {
        this.operatorType = operatorType;
        this.describe = describe;
    }

    public String getOperatorType() {
        return operatorType;
    }

    public String getDescribe() {
        return describe;
    }

    public static String getDescribeByHandle(String handle) {
        for (OrderTrackTypeEnum handleEnum : OrderTrackTypeEnum.values()) {
            if (handleEnum.getOperatorType().equals(handle)) {
                return handleEnum.getDescribe();
            }
        }
        return null;
    }
}

handle包

package com.jinyi.event.handle;

import com.jinyi.event.base.BaseEvent;
import org.springframework.context.ApplicationListener;

/***
 * event handle 基础类
 *
 **/
public interface IEventHandler<T extends BaseEvent> extends ApplicationListener<T> {

  @Override
    default void onApplicationEvent(T event) {
        try {
            if (support(event)) {
                handle(event);
            }
        } catch (Throwable e) {
            handleException(e);
        }
    }

    /**
     * 事件处理统一方法
     * @param event
     */
    void handle(T event);

    /**
     * 处理异常(默认不进行异常处理)
     *
     * @param exception
     */
    default void handleException(Throwable exception) {};

    /**
     * 子类重写可自定义事件支持是否开启
     * @param event
     * @return
     */
    default boolean support(T event) {
        return true;
    }
}
package com.jinyi.event.handle;

import com.jinyi.event.base.OrderStatusChangeDTO;
import com.jinyi.event.bizEvent.OrderPayEvent;
import com.jinyi.event.bizEvent.OrderStatusChangeEvent;
import com.jinyi.event.bizEvent.OrderUserCancelEvent;
import com.jinyi.event.enums.OrderTrackTypeEnum;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

/**
 * 订单支付事件
 *
 * @author huangchong
 * @date 2024/4/19 15:55
 * @desc
 */
@Component
public class OrderPayEventHandle implements IEventHandler<OrderStatusChangeEvent> {

    /**
     * 订单支付事件处理
     *
     * @param event
     */
    @Override
    public void handle(OrderStatusChangeEvent event) {
        if (event instanceof OrderPayEvent){
            OrderStatusChangeDTO changeDTO = event.getOrderStatusChangeDTO();
            OrderTrackTypeEnum orderStatusChange = changeDTO.getOrderStatusChange();
            System.out.println("Thread:" + Thread.currentThread().getName() + orderStatusChange.getDescribe() + "-----");
        }else {
            System.out.println("Thread:" + Thread.currentThread().getName() + "--OrderPayEventHandle 通用订单状态改变---");
        }
    }

    @Override
    public void handleException(Throwable exception) {
        IEventHandler.super.handleException(exception);
    }

    @Override
    public boolean support(OrderStatusChangeEvent event) {
        return IEventHandler.super.support(event);
    }
}
package com.jinyi.event.handle;

import com.jinyi.event.base.OrderStatusChangeDTO;
import com.jinyi.event.bizEvent.OrderPayEvent;
import com.jinyi.event.bizEvent.OrderStatusChangeEvent;
import com.jinyi.event.bizEvent.OrderUserCancelEvent;
import com.jinyi.event.enums.OrderTrackTypeEnum;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
public class OrderUserCancelEventHandle implements IEventHandler<OrderStatusChangeEvent> {


    @Override
    public void handle(OrderStatusChangeEvent event) {
        if (event instanceof OrderUserCancelEvent){
            OrderStatusChangeDTO changeDTO = event.getOrderStatusChangeDTO();
            OrderTrackTypeEnum orderStatusChange = changeDTO.getOrderStatusChange();
            System.out.println("Thread:" + Thread.currentThread().getName() + orderStatusChange.getDescribe() + "-----");
        }else {
            System.out.println("Thread:" + Thread.currentThread().getName() + "--OrderUserCancelEventHandle 通用订单状态改变---");
        }
    }

    @Override
    public boolean support(OrderStatusChangeEvent event) {
        return IEventHandler.super.support(event);
    }
}

package com.jinyi.event.handle;

import com.jinyi.event.base.OrderStatusChangeDTO;
import com.jinyi.event.bizEvent.OrderStatusChangeEvent;
import com.jinyi.event.bizEvent.OrderUserCancelEvent;
import com.jinyi.event.bizEvent.StockReduceEvent;
import com.jinyi.event.enums.OrderTrackTypeEnum;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
public class StockReduceEventHandle implements IEventHandler<OrderStatusChangeEvent> {


    @Override
    public void handle(OrderStatusChangeEvent event) {
        Boolean flag = event instanceof StockReduceEvent;
        if (flag ) {
            OrderStatusChangeDTO changeDTO = event.getOrderStatusChangeDTO();
            OrderTrackTypeEnum orderStatusChange = changeDTO.getOrderStatusChange();
            StockReduceEvent stockReduceEvent = (StockReduceEvent) event;
            Long goodsId = stockReduceEvent.getGoodsId();
            System.out.println("Thread:" + Thread.currentThread().getName() + orderStatusChange.getDescribe() + "-111----");
        }else {
            System.out.println("Thread:" + Thread.currentThread().getName() + "--StockReduceEventHandle 通用订单状态改变---");
        }
    }

    @Override
    public boolean support(OrderStatusChangeEvent event) {
        return IEventHandler.super.support(event);
    }
}

测试入口

package com.jinyi.event.send;

import com.jinyi.event.base.EventBusCenter;
import com.jinyi.event.base.OrderStatusChangeDTO;
import com.jinyi.event.bizEvent.OrderPayEvent;
import com.jinyi.event.bizEvent.OrderStatusChangeEvent;
import com.jinyi.event.enums.OrderTrackTypeEnum;
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;

/**
 * @author huangchong
 * @date 2024/4/19 16:33
 * @desc
 */
@RestController
@RequestMapping("/event")
public class BizPost {
    @Resource
    private EventBusCenter eventBusCenter;

    @GetMapping("/post")
    public void bizPost() {
        OrderStatusChangeDTO changeDTO =new OrderStatusChangeDTO();
        changeDTO.setUserId(1L);
        changeDTO.setOrderNo(100L);
        changeDTO.setOrderStatusChange(OrderTrackTypeEnum.ORDER_PAY);
        //仅触发订单支付 和 其他 通用handle
        OrderStatusChangeEvent event = new OrderPayEvent(this, changeDTO);
        eventBusCenter.post(event);
        //广播订单状态变更时间
//        OrderStatusChangeEvent event1 = new OrderStatusChangeEvent(this, changeDTO);
//        eventBusCenter.post(event1);
    }
}

项目启动类

@SpringBootApplication
public class EventApplication {

    public static void main(String[] args) {
        SpringApplication.run(EventApplication.class,args);
    }
}

test:

localhost:8080/event/post

resp:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1615396.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

什么是防抖和节流?有什么区别? 如何实现?

防抖&#xff08;Debounce&#xff09;和节流&#xff08;Throttle&#xff09;是两种常用的技术手段&#xff0c;主要用于控制某个函数在一定时间内触发的次数&#xff0c;以减少触发频率&#xff0c;提高性能并避免资源浪费。 防抖&#xff08;Debounce&#xff09;的工作原…

openEuler-23.03下载、安装

一、下载 下载地址&#xff1a;openEuler下载 | 欧拉系统ISO镜像 | openEuler社区官网 下载版本&#xff1a;openEuler-23.03-x86_64-dvd.iso 二、安装 cd /etc/sysconfig/network-scripts/ vi ifcfg-ens-33## 要修改部分 BOOTPROTOstatic## 新增部分 IPADDR192.168.1.128 …

AI觉醒派: 探索与AI协作路径,觉醒更强大的自己

AI觉醒派成立以来&#xff0c;微信社群已经壮大至几千人。许多新加入的小伙伴可能对我们还不够了解&#xff0c;今天&#xff0c;让我们通过这篇文章深入探讨我们的核心理念、梦想、以及如何借助人工智能觉醒更强大的自我。 &#x1f31f; AI觉醒派简介 AI觉醒派是一个探索人工…

深度学习入门(4)

神经网络的构建 import numpy as np import matplotlib.pyplot as plt def sigmoid(x):return 1/(1np.exp(-x)) def identity_function(x):#恒等函数return x def init_network():#进行权重和偏置的初始化&#xff0c;并保存到字典中network{}network[W1]np.array([[0.1,0.3,0…

清华大学:序列推荐模型稳定性飙升,STDP框架惊艳登场

获取本文论文原文PDF&#xff0c;请公众号留言&#xff1a;论文解读 引言&#xff1a;在线平台推荐系统的挑战与机遇 在线平台已成为我们日常生活中不可或缺的一部分&#xff0c;它们提供了丰富多样的商品和服务。然而&#xff0c;如何为用户推荐感兴趣的项目仍然是一个挑战。…

sql(ctfhub)

一.整数型注入 输入1 输入2 输入2-1&#xff0c;回显为1的结果&#xff0c;说明是数字型&#xff0c;只有数字型才可加减 判断字段数为2 查询数据库 查表 查列 显示flag内容 二.字符型注入 输入1 输入2 输入2-1&#xff0c;说明为字符型&#xff0c;不是数字型 判断闭合方式为…

新手小白,在数学建模的过程中应该怎么分工?

大家知道&#xff0c;数学建模竞赛是需要一个团队的三个人在三天或四天的时间内&#xff0c;完成模型建立&#xff0c;编程实现和论文写作的任务&#xff0c;对许多第一次参加建模或者建模经验比较欠缺的团队来说&#xff0c;是时间紧任务重的&#xff0c;那么怎么办呢&#xf…

Elasticsearch:简化 KNN 搜索

作者&#xff1a;来自 Elastic Panagiotis Bailis 在这篇博客文章中&#xff0c;我们将深入探讨我们为了使 KNN 搜索的入门体验变得更加简单而做出的努力&#xff01; 向量搜索 向量搜索通过在 Elasticsearch 中引入一种新的专有的 KNN 搜索类型&#xff0c;已经可以使用一段…

对接浦发银行支付(八)-- 对账接口

一、背景 本文不是要讲述支付服务的对账模块具体怎么做&#xff0c;仅是介绍如何对接浦发银行的对账接口。 也就是说&#xff0c;本文限读取到对账文件的内容&#xff0c;不会进一步去讲述如何与支付平台进行对账。 如果要获取商户的对账单&#xff0c;需要遵循以下步骤&…

数据分析_数据分析思维(1)

数据分析_数据分析思维(1) 这篇文章具体的给大家介绍数据分析中最为核心的技术之一: 数据分析思维的相关内容。 一、数据分析的三种核心思维 作为新手数据分析师或数据运营, 在面对数据异常的时候, 好多小伙伴都会出现: “好像是A引起的”, “好像也和B渠道有关”, “也可能…

江苏瑞达环保科技股份有限公司| 邀您参加2024全国水科技大会暨技术装备成果展览会

—— 展位号:A18 —— 江苏瑞达环保科技股份有限公司是一家致力于环境保护和可持续发展的高新技术企业&#xff0c;专注于环境治理技术研发和环保节能装备制造,为工业企业提供可靠的工程解决方案。2023年&#xff0c;瑞达科技被认定为江苏省省级专精特新企业。 瑞达科技成立于2…

rCore-Turorial-Book第三课(计算机启动流程和程序内存布局与编译流程探索)

本节任务&#xff1a;梳理程序在操作系统中被编译运行的全流程&#xff0c;大体了解我们在没有操作系统的情况下&#xff0c;我们会面对那些困难 重点 1. 计算机组成基础 面对的困难&#xff1a;没有操作系统&#xff0c;我们必须直面硬件资源&#xff0c;管理起他们并为应用程…

本地环境通过ssh通道连接服务器数据库,实现本地客户端和代码可以访问数据库

使用方法&#xff1a; ssh -p 搭建隧道的端口 -fNL 本地端口:远程ip:远程端口号 搭建隧道的账号搭建隧道的ip 可以增加参数-v,输出更多的信息 ssh -p 搭建隧道的端口 -fNL 本地端口:远程ip:远程端口号 -v 搭建隧道的账号搭建隧道的ip 有时候&#xff0c;测试环境的数据库不允许…

YOLOv8-PySide --- 基于 ultralytics 8.1.0 发行版优化 | 代码已开源

YOLOv8-PySide — 基于 ultralytics 8.1.0 发行版优化 Github 项目地址&#xff1a;https://github.com/WangQvQ/Ultralytics-PySide6 BiliBili视频地址&#xff1a;https://www.bilibili.com/video 页面效果 如何使用 pip install ultralytics8.1.0 or git clone --branch v…

如何判别三角形和求10 个整数中最大值?

分享每日小题&#xff0c;不断进步&#xff0c;今天的你也要加油哦&#xff01;接下来请看题------> 一、已知三条边a&#xff0c;b&#xff0c;c能否构成三角形&#xff0c;如果能构成三角形&#xff0c;判断三角形的类型&#xff08;等边三角形、等腰三角形或普通三角形 …

通过Docker新建并使用MySQL数据库

1. 安装Docker 确保您的系统上已经安装了Docker。可以通过以下命令检查Docker是否安装并运行&#xff1a; systemctl status docker如果没有安装或运行&#xff0c;请按照官方文档进行安装和启动。 2. 拉取MySQL镜像 从Docker Hub拉取MySQL官方镜像。这里以MySQL 5.7版本为…

(回溯)记忆化搜索和dp

动态规划的核心就是 状态的定义和状态的转移 灵神 的 回溯改递归思路 首先很多动态规划问题都可以采用 回溯 的思想 回溯主要思想就是把 一个大问题分解成小问题 比如 采用子集类回溯问题中的核心思想-> 选或不选 或者 选哪个 记忆化搜索之后 我们可以发现 每个新节点依…

【网络原理】UDP协议的报文结构 及 校验和字段的错误检测机制(CRC算法、MD5算法)

目录 UDP协议 UDP协议的报文结构及注意事项 UDP报文结构中的校验和字段 1. 校验和主要校验的内容 2. UDP校验和的实现方式 3. CRC&#xff08;循环冗余校验&#xff09;算法 4. MD5&#xff08;Message Digest Algorithm 5&#xff09; UDP协议 上一篇文章提过&#xf…

【C++】双指针算法:复写零

1.题目 别看这是一道简单题&#xff0c;它的通过率低于一些中等甚至困难的题目&#xff01; 大大增加这道题目难度的是最后一句话&#xff1a;1.不可越界写入。2.就地修改。 如果可以再创建一个数组的话&#xff0c;那么这道题目就会非常简单&#xff0c;但这道题目必须要求在…

汽车IVI中控开发入门及进阶(十六):carplay认证

现在有些中控采用高通的芯片如8155、8295等,实现多屏互动等,但是也有一些车型走低成本方案,比如能够实现HiCar、CarLife或者苹果Apple的Carplay等能进行手机投屏就好了。 能实现CarPlay功能通过Carplay认证,也就成了一些必须的过程,国产车规级中控芯片里,开阳有一款ARK1…