扩展 Cron4j 实现秒级定时任务

news/2025/1/7 20:02:27/文章来源:https://www.cnblogs.com/chqxyzhu/p/18655677

Cron4j 是一个轻量级的 Java 定时任务调度库,默认情况下不支持秒级别的定时任务。如果需要扩展秒级别的定时任务,可以通过修改 Cron4j 的源码来实现。本文将详细介绍如何修改 Cron4j 的源码以支持秒级别的定时任务。

环境准备

首先,从 Cron4j 的 GitHub 仓库 下载源码,并导入到你的 IDE 中。pom地址如下:

<dependency><groupId>it.sauronsoftware.cron4j</groupId><artifactId>cron4j</artifactId><version>2.2.5</version>
</dependency>

修改 SchedulingPattern 类

SchedulingPattern 类负责解析和匹配调度表达式。我们需要修改它以支持秒级别的调度。

添加秒字段:在 SchedulingPattern 类中添加对秒字段的支持。

/** cron4j - A pure Java cron-like scheduler* * Copyright (C) 2007-2010 Carlo Pelliccia (www.sauronsoftware.it)* * This program is free software: you can redistribute it and/or modify* it under the terms of the GNU Lesser General Public License version* 2.1, as published by the Free Software Foundation.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the* GNU Lesser General Public License 2.1 for more details.** You should have received a copy of the GNU Lesser General Public* License version 2.1 along with this program.* If not, see <http://www.gnu.org/licenses/>.*/
package it.sauronsoftware.cron4j;import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.StringTokenizer;
import java.util.TimeZone;/*** <p>* A UNIX crontab-like pattern is a string split in five space separated parts.* Each part is intented as:* </p>* <ol>* <li><strong>Minutes sub-pattern</strong>. During which minutes of the hour* should the task been launched? The values range is from 0 to 59.</li>* <li><strong>Hours sub-pattern</strong>. During which hours of the day should* the task been launched? The values range is from 0 to 23.</li>* <li><strong>Days of month sub-pattern</strong>. During which days of the* month should the task been launched? The values range is from 1 to 31. The* special value L can be used to recognize the last day of month.</li>* <li><strong>Months sub-pattern</strong>. During which months of the year* should the task been launched? The values range is from 1 (January) to 12* (December), otherwise this sub-pattern allows the aliases &quot;jan&quot;,* &quot;feb&quot;, &quot;mar&quot;, &quot;apr&quot;, &quot;may&quot;,* &quot;jun&quot;, &quot;jul&quot;, &quot;aug&quot;, &quot;sep&quot;,* &quot;oct&quot;, &quot;nov&quot; and &quot;dec&quot;.</li>* <li><strong>Days of week sub-pattern</strong>. During which days of the week* should the task been launched? The values range is from 0 (Sunday) to 6* (Saturday), otherwise this sub-pattern allows the aliases &quot;sun&quot;,* &quot;mon&quot;, &quot;tue&quot;, &quot;wed&quot;, &quot;thu&quot;,* &quot;fri&quot; and &quot;sat&quot;.</li>* </ol>* <p>* The star wildcard character is also admitted, indicating &quot;every minute* of the hour&quot;, &quot;every hour of the day&quot;, &quot;every day of the* month&quot;, &quot;every month of the year&quot; and &quot;every day of the* week&quot;, according to the sub-pattern in which it is used.* </p>* <p>* Once the scheduler is started, a task will be launched when the five parts in* its scheduling pattern will be true at the same time.* </p>* <p>* Some examples:* </p>* <p>* <strong>5 * * * *</strong><br />* This pattern causes a task to be launched once every hour, at the begin of* the fifth minute (00:05, 01:05, 02:05 etc.).* </p>* <p>* <strong>* * * * *</strong><br />* This pattern causes a task to be launched every minute.* </p>* <p>* <strong>* 12 * * Mon</strong><br />* This pattern causes a task to be launched every minute during the 12th hour* of Monday.* </p>* <p>* <strong>* 12 16 * Mon</strong><br />* This pattern causes a task to be launched every minute during the 12th hour* of Monday, 16th, but only if the day is the 16th of the month.* </p>* <p>* Every sub-pattern can contain two or more comma separated values.* </p>* <p>* <strong>59 11 * * 1,2,3,4,5</strong><br />* This pattern causes a task to be launched at 11:59AM on Monday, Tuesday,* Wednesday, Thursday and Friday.* </p>* <p>* Values intervals are admitted and defined using the minus character.* </p>* <p>* <strong>59 11 * * 1-5</strong><br />* This pattern is equivalent to the previous one.* </p>* <p>* The slash character can be used to identify step values within a range. It* can be used both in the form <em>*&#47;c</em> and <em>a-b/c</em>. The* subpattern is matched every <em>c</em> values of the range* <em>0,maxvalue</em> or <em>a-b</em>.* </p>* <p>* <strong>*&#47;5 * * * *</strong><br />* This pattern causes a task to be launched every 5 minutes (0:00, 0:05, 0:10,* 0:15 and so on).* </p>* <p>* <strong>3-18&#47;5 * * * *</strong><br />* This pattern causes a task to be launched every 5 minutes starting from the* third minute of the hour, up to the 18th (0:03, 0:08, 0:13, 0:18, 1:03, 1:08* and so on).* </p>* <p>* <strong>*&#47;15 9-17 * * *</strong><br />* This pattern causes a task to be launched every 15 minutes between the 9th* and 17th hour of the day (9:00, 9:15, 9:30, 9:45 and so on... note that the* last execution will be at 17:45).* </p>* <p>* All the fresh described syntax rules can be used together.* </p>* <p>* <strong>* 12 10-16&#47;2 * *</strong><br />* This pattern causes a task to be launched every minute during the 12th hour* of the day, but only if the day is the 10th, the 12th, the 14th or the 16th* of the month.* </p>* <p>* <strong>* 12 1-15,17,20-25 * *</strong><br />* This pattern causes a task to be launched every minute during the 12th hour* of the day, but the day of the month must be between the 1st and the 15th,* the 20th and the 25, or at least it must be the 17th.* </p>* <p>* Finally cron4j lets you combine more scheduling patterns into one, with the* pipe character:* </p>* <p>* <strong>0 5 * * *|8 10 * * *|22 17 * * *</strong><br />* This pattern causes a task to be launched every day at 05:00, 10:08 and* 17:22.* </p>* * @author Carlo Pelliccia* @since 2.0*/
public class SchedulingPattern {/*** The parser for the second values.*/private static final ValueParser SECONDS_VALUE_PARSER = new SecondsValueParser();/*** The parser for the minute values.*/private static final ValueParser MINUTE_VALUE_PARSER = new MinuteValueParser();/*** The parser for the hour values.*/private static final ValueParser HOUR_VALUE_PARSER = new HourValueParser();/*** The parser for the day of month values.*/private static final ValueParser DAY_OF_MONTH_VALUE_PARSER = new DayOfMonthValueParser();/*** The parser for the month values.*/private static final ValueParser MONTH_VALUE_PARSER = new MonthValueParser();/*** The parser for the day of week values.*/private static final ValueParser DAY_OF_WEEK_VALUE_PARSER = new DayOfWeekValueParser();/*** Validates a string as a scheduling pattern.* * @param schedulingPattern*            The pattern to validate.* @return true if the given string represents a valid scheduling pattern;*         false otherwise.*/public static boolean validate(String schedulingPattern) {try {new SchedulingPattern(schedulingPattern);} catch (InvalidPatternException e) {return false;}return true;}/*** The pattern as a string.*/private String asString;/*** The ValueMatcher list for the "minute" field.*/protected ArrayList secondsMatchers = new ArrayList();/*** The ValueMatcher list for the "minute" field.*/protected ArrayList minuteMatchers = new ArrayList();/*** The ValueMatcher list for the "hour" field.*/protected ArrayList hourMatchers = new ArrayList();/*** The ValueMatcher list for the "day of month" field.*/protected ArrayList dayOfMonthMatchers = new ArrayList();/*** The ValueMatcher list for the "month" field.*/protected ArrayList monthMatchers = new ArrayList();/*** The ValueMatcher list for the "day of week" field.*/protected ArrayList dayOfWeekMatchers = new ArrayList();/*** How many matcher groups in this pattern?*/protected int matcherSize = 0;/*** Builds a SchedulingPattern parsing it from a string.* * @param pattern*            The pattern as a crontab-like string.* @throws InvalidPatternException*             If the supplied string is not a valid pattern.*/public SchedulingPattern(String pattern) throws InvalidPatternException {this.asString = pattern;StringTokenizer st1 = new StringTokenizer(pattern, "|");if (st1.countTokens() < 1) {throw new InvalidPatternException("invalid pattern: \"" + pattern + "\"");}while (st1.hasMoreTokens()) {String localPattern = st1.nextToken();StringTokenizer st2 = new StringTokenizer(localPattern, " \t");if (st2.countTokens() != 6) {throw new InvalidPatternException("invalid pattern: \"" + localPattern + "\"");}try {secondsMatchers.add(buildValueMatcher(st2.nextToken(), SECONDS_VALUE_PARSER));} catch (Exception e) {throw new InvalidPatternException("invalid pattern \""+ localPattern + "\". Error parsing minutes field: "+ e.getMessage() + ".");}try {minuteMatchers.add(buildValueMatcher(st2.nextToken(), MINUTE_VALUE_PARSER));} catch (Exception e) {throw new InvalidPatternException("invalid pattern \""+ localPattern + "\". Error parsing minutes field: "+ e.getMessage() + ".");}try {hourMatchers.add(buildValueMatcher(st2.nextToken(), HOUR_VALUE_PARSER));} catch (Exception e) {throw new InvalidPatternException("invalid pattern \""+ localPattern + "\". Error parsing hours field: "+ e.getMessage() + ".");}try {dayOfMonthMatchers.add(buildValueMatcher(st2.nextToken(), DAY_OF_MONTH_VALUE_PARSER));} catch (Exception e) {throw new InvalidPatternException("invalid pattern \""+ localPattern+ "\". Error parsing days of month field: "+ e.getMessage() + ".");}try {monthMatchers.add(buildValueMatcher(st2.nextToken(), MONTH_VALUE_PARSER));} catch (Exception e) {throw new InvalidPatternException("invalid pattern \""+ localPattern + "\". Error parsing months field: "+ e.getMessage() + ".");}try {dayOfWeekMatchers.add(buildValueMatcher(st2.nextToken(), DAY_OF_WEEK_VALUE_PARSER));} catch (Exception e) {throw new InvalidPatternException("invalid pattern \""+ localPattern+ "\". Error parsing days of week field: "+ e.getMessage() + ".");}matcherSize++;}}/*** A ValueMatcher utility builder.* * @param str*            The pattern part for the ValueMatcher creation.* @param parser*            The parser used to parse the values.* @return The requested ValueMatcher.* @throws Exception*             If the supplied pattern part is not valid.*/private ValueMatcher buildValueMatcher(String str, ValueParser parser)throws Exception {if (str.length() == 1 && str.equals("*")) {return new AlwaysTrueValueMatcher();}ArrayList values = new ArrayList();StringTokenizer st = new StringTokenizer(str, ",");while (st.hasMoreTokens()) {String element = st.nextToken();ArrayList local;try {local = parseListElement(element, parser);} catch (Exception e) {throw new Exception("invalid field \"" + str+ "\", invalid element \"" + element + "\", "+ e.getMessage());}for (Iterator i = local.iterator(); i.hasNext();) {Object value = i.next();if (!values.contains(value)) {values.add(value);}}}if (values.size() == 0) {throw new Exception("invalid field \"" + str + "\"");}if (parser == DAY_OF_MONTH_VALUE_PARSER) {return new DayOfMonthValueMatcher(values);} else {return new IntArrayValueMatcher(values);}}/*** Parses an element of a list of values of the pattern.* * @param str*            The element string.* @param parser*            The parser used to parse the values.* @return A list of integers representing the allowed values.* @throws Exception*             If the supplied pattern part is not valid.*/private ArrayList parseListElement(String str, ValueParser parser)throws Exception {StringTokenizer st = new StringTokenizer(str, "/");int size = st.countTokens();if (size < 1 || size > 2) {throw new Exception("syntax error");}ArrayList values;try {values = parseRange(st.nextToken(), parser);} catch (Exception e) {throw new Exception("invalid range, " + e.getMessage());}if (size == 2) {String dStr = st.nextToken();int div;try {div = Integer.parseInt(dStr);} catch (NumberFormatException e) {throw new Exception("invalid divisor \"" + dStr + "\"");}if (div < 1) {throw new Exception("non positive divisor \"" + div + "\"");}ArrayList values2 = new ArrayList();for (int i = 0; i < values.size(); i += div) {values2.add(values.get(i));}return values2;} else {return values;}}/*** Parses a range of values.* * @param str*            The range string.* @param parser*            The parser used to parse the values.* @return A list of integers representing the allowed values.* @throws Exception*             If the supplied pattern part is not valid.*/private ArrayList parseRange(String str, ValueParser parser)throws Exception {if (str.equals("*")) {int min = parser.getMinValue();int max = parser.getMaxValue();ArrayList values = new ArrayList();for (int i = min; i <= max; i++) {values.add(new Integer(i));}return values;}StringTokenizer st = new StringTokenizer(str, "-");int size = st.countTokens();if (size < 1 || size > 2) {throw new Exception("syntax error");}String v1Str = st.nextToken();int v1;try {v1 = parser.parse(v1Str);} catch (Exception e) {throw new Exception("invalid value \"" + v1Str + "\", "+ e.getMessage());}if (size == 1) {ArrayList values = new ArrayList();values.add(new Integer(v1));return values;} else {String v2Str = st.nextToken();int v2;try {v2 = parser.parse(v2Str);} catch (Exception e) {throw new Exception("invalid value \"" + v2Str + "\", "+ e.getMessage());}ArrayList values = new ArrayList();if (v1 < v2) {for (int i = v1; i <= v2; i++) {values.add(new Integer(i));}} else if (v1 > v2) {int min = parser.getMinValue();int max = parser.getMaxValue();for (int i = v1; i <= max; i++) {values.add(new Integer(i));}for (int i = min; i <= v2; i++) {values.add(new Integer(i));}} else {// v1 == v2values.add(new Integer(v1));}return values;}}/*** This methods returns true if the given timestamp (expressed as a UNIX-era* millis value) matches the pattern, according to the given time zone.* * @param timezone*            A time zone.* @param millis*            The timestamp, as a UNIX-era millis value.* @return true if the given timestamp matches the pattern.*/public boolean match(TimeZone timezone, long millis) {GregorianCalendar gc = new GregorianCalendar();gc.setTimeInMillis(millis);gc.setTimeZone(timezone);int seconds = gc.get(Calendar.SECOND);int minute = gc.get(Calendar.MINUTE);int hour = gc.get(Calendar.HOUR_OF_DAY);int dayOfMonth = gc.get(Calendar.DAY_OF_MONTH);int month = gc.get(Calendar.MONTH) + 1;int dayOfWeek = gc.get(Calendar.DAY_OF_WEEK) - 1;int year = gc.get(Calendar.YEAR);for (int i = 0; i < matcherSize; i++) {ValueMatcher secondsMatcher = (ValueMatcher) secondsMatchers.get(i);ValueMatcher minuteMatcher = (ValueMatcher) minuteMatchers.get(i);ValueMatcher hourMatcher = (ValueMatcher) hourMatchers.get(i);ValueMatcher dayOfMonthMatcher = (ValueMatcher) dayOfMonthMatchers.get(i);ValueMatcher monthMatcher = (ValueMatcher) monthMatchers.get(i);ValueMatcher dayOfWeekMatcher = (ValueMatcher) dayOfWeekMatchers.get(i);boolean eval = secondsMatcher.match(seconds)&&minuteMatcher.match(minute)&& hourMatcher.match(hour)&& ((dayOfMonthMatcher instanceof DayOfMonthValueMatcher) ? ((DayOfMonthValueMatcher) dayOfMonthMatcher).match(dayOfMonth, month, gc.isLeapYear(year)): dayOfMonthMatcher.match(dayOfMonth))&& monthMatcher.match(month)&& dayOfWeekMatcher.match(dayOfWeek);if (eval) {return true;}}return false;}/*** This methods returns true if the given timestamp (expressed as a UNIX-era* millis value) matches the pattern, according to the system default time* zone.* * @param millis*            The timestamp, as a UNIX-era millis value.* @return true if the given timestamp matches the pattern.*/public boolean match(long millis) {return match(TimeZone.getDefault(), millis);}/*** Returns the pattern as a string.* * @return The pattern as a string.*/public String toString() {return asString;}/*** This utility method changes an alias to an int value.* * @param value*            The value.* @param aliases*            The aliases list.* @param offset*            The offset appplied to the aliases list indices.* @return The parsed value.* @throws Exception*             If the expressed values doesn't match any alias.*/private static int parseAlias(String value, String[] aliases, int offset)throws Exception {for (int i = 0; i < aliases.length; i++) {if (aliases[i].equalsIgnoreCase(value)) {return offset + i;}}throw new Exception("invalid alias \"" + value + "\"");}/*** Definition for a value parser.*/private static interface ValueParser {/*** Attempts to parse a value.* * @param value*            The value.* @return The parsed value.* @throws Exception*             If the value can't be parsed.*/public int parse(String value) throws Exception;/*** Returns the minimum value accepred by the parser.* * @return The minimum value accepred by the parser.*/public int getMinValue();/*** Returns the maximum value accepred by the parser.* * @return The maximum value accepred by the parser.*/public int getMaxValue();}/*** A simple value parser.*/private static class SimpleValueParser implements ValueParser {/*** The minimum allowed value.*/protected int minValue;/*** The maximum allowed value.*/protected int maxValue;/*** Builds the value parser.* * @param minValue*            The minimum allowed value.* @param maxValue*            The maximum allowed value.*/public SimpleValueParser(int minValue, int maxValue) {this.minValue = minValue;this.maxValue = maxValue;}public int parse(String value) throws Exception {int i;try {i = Integer.parseInt(value);} catch (NumberFormatException e) {throw new Exception("invalid integer value");}if (i < minValue || i > maxValue) {throw new Exception("value out of range");}return i;}public int getMinValue() {return minValue;}public int getMaxValue() {return maxValue;}}/*** The minutes value parser.*/private static class SecondsValueParser extends SimpleValueParser {/*** Builds the value parser.*/public SecondsValueParser() {super(0, 59);}}/*** The minutes value parser.*/private static class MinuteValueParser extends SimpleValueParser {/*** Builds the value parser.*/public MinuteValueParser() {super(0, 59);}}/*** The hours value parser.*/private static class HourValueParser extends SimpleValueParser {/*** Builds the value parser.*/public HourValueParser() {super(0, 23);}}/*** The days of month value parser.*/private static class DayOfMonthValueParser extends SimpleValueParser {/*** Builds the value parser.*/public DayOfMonthValueParser() {super(1, 31);}/*** Added to support last-day-of-month.* * @param value*            The value to be parsed* @return the integer day of the month or 32 for last day of the month* @throws Exception*             if the input value is invalid*/public int parse(String value) throws Exception {if (value.equalsIgnoreCase("L")) {return 32;} else {return super.parse(value);}}}/*** The value parser for the months field.*/private static class MonthValueParser extends SimpleValueParser {/*** Months aliases.*/private static String[] ALIASES = { "jan", "feb", "mar", "apr", "may","jun", "jul", "aug", "sep", "oct", "nov", "dec" };/*** Builds the months value parser.*/public MonthValueParser() {super(1, 12);}public int parse(String value) throws Exception {try {// try as a simple valuereturn super.parse(value);} catch (Exception e) {// try as an aliasreturn parseAlias(value, ALIASES, 1);}}}/*** The value parser for the months field.*/private static class DayOfWeekValueParser extends SimpleValueParser {/*** Days of week aliases.*/private static String[] ALIASES = { "sun", "mon", "tue", "wed", "thu", "fri", "sat" };/*** Builds the months value parser.*/public DayOfWeekValueParser() {super(0, 7);}public int parse(String value) throws Exception {try {// try as a simple valuereturn super.parse(value) % 7;} catch (Exception e) {// try as an aliasreturn parseAlias(value, ALIASES, 0);}}}}

使用方法:

首先,将上述修改后的类替换 cron4j 中的原类。
然后,传入的 cron 表达式要采用新的格式,包含秒级信息,例如 "0 0 0 * * *" 表示在每天的 0 点 0 分 0 秒执行任务,或者 "0-30 * * * * *" 表示每分钟的 0 到 30 秒都执行任务。
请注意,上述代码仅为示例,实际修改 cron4j 的源码可能会涉及更多复杂的细节,例如异常处理、并发问题、cron 表达式更复杂的匹配逻辑等,需要根据 cron4j 的实际源码进行更深入的修改和完善。此外,修改源码可能会影响其兼容性和稳定性,需要进行充分的测试。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C# typeof()实例详解

原文链接:https://www.cnblogs.com/ybqjymy/p/12902845.html 用于获取类型的 System.Type 对象。typeof 表达式采用以下形式:System.Type type = typeof(int); 备注若要获取表达式的运行时类型,可以使用 .NET Framework 方法 GetType,如下所示:1 int i = 0; 2 System.Type…

PhpStorm 2024.3.1.1 安装激活教程(激活至2026,实际上永久,亲测!)以及常见问题处理

申明:本教程 PhpStorm 补丁、激活码均收集于网络,请勿商用,仅供个人学习使用,如有侵权,请联系作者删除。若条件允许,希望大家购买正版 !卸载老版本 PhpStorm 首先,如果小伙伴的电脑上有安装老版本的 PhpStorm , 需要将其彻底卸载掉,如下所示(没有安装则不用管,直…

以太网物理层IOP测试设备TESTBASE-EIOP

OPEN联盟(OPEN Alliance)是一个由OEM、Tier1和Tier2共同组建的非盈利开放性的行业联盟,旨在将以太网技术在汽车环境中应用及推广,TESTBASE-EIOP是经纬恒润自主研发的车载以太网物理层IOP(交互性)自动化测试设备,可完整覆盖OPEN TC8 IOP测试标准。背景OPEN联盟(OPEN All…

Linux命令行连接蓝牙设备

Linux命令行连接蓝牙设备 查看Bluetooth设备: hciconfig启动一个Bluetooth设备,例如:hci0: hciconfig hci0 up相关指令查看特定的Bluetooth设备(例如,设备名为hci0): hciconfig hci0关闭一个Bluetooth设备(例如,设备名为hci0): hciconfig hci0 down修改一个Bluetoot…

华为云专家说:开源的商业化之路与开发者技术服务

开源在大量在云技术以及业务中应用,从开源与云的增长模式看,开源与云具有相当程度的相似性。本文来源:《华为云DTSE》第五期开源专刊,作者:华为云开发者支持首席布道师汪盛 开源、云的增长模式与 Product Led Growth具有较大相似性,两者增长立足于产品质量与使用的开发者…

JAVA-Day 06:if语句的三种形式

if语句的三种形式if(表达式){语句体}如果小括号里的表达式结果为真,则执行大括号中的语句体,如下图例子所示:2.if(表达式){语句体}else{语句体} 如果小括号里的表达式为真,则执行else前的大括号中的语句体,如果小括号里的表达式为假,则执行else后的大括号中的语句体。如下图…

Redis可视化工具 Another Redis Desktop Manager工具使用详细教程(附下载链接)

Redis 可视化工具推荐:Another Redis Desktop Manager Redis 是一种高性能的键值数据库,广泛应用于缓存和消息队列等场景。对于开发者来说,命令行工具固然强大,但操作繁琐。而一款高效易用的可视化工具可以极大地提升使用效率。本篇将为大家推荐一款开源、跨平台且功能强大…

跟狂神学习第一天,了解Markdown语法

Markdown学习 一个#+空格+标题名字=大标题/一级标题 二级标题 两个#+空格+标题 = 二级标题 三个#+空格+标题 = 三级标题 .......(以此类推) 一直到六级标题 字体 hello! 粗体:文字两边同时加两个* hello! 斜体:文字两边同时加一个* hello! 斜体加粗:文字两边同时加三个…

Ubuntu换源自用备用

Ubuntu换源(本地) 作者 原文链接:https://blog.csdn.net/MacWx/article/details/137689898 查询系统版本 lsb_release -a系统版本是 Ubuntu 20.04.6 LTS,注意这个开发代号Codename,Ubuntu每一个版本都有一个代号,这个一定要跟国内源对应,否则会出问题。 阿里云Ubuntu镜像…

大规模高性能云网络技术思路

控制面基础架构采用微服务架构模型,服务独立可扩展,可以根据每个服务的规模来部署满足需求的实例。具体网络控制面技术方案如图本文分享自天翼云开发者社区《大规模高性能云网络技术思路》,作者:程****超 控制面基础架构采用微服务架构模型,服务独立可扩展,可以根据每个服…

Python开发环境部署教程

本教程将详细介绍如何在 Windows 系统上配置 Python 开发环境,包括安装 Python、配置虚拟环境以及使用 VS Code 进行开发,适合新手和需要精细配置的开发者。本教程将详细介绍如何在 Windows 系统上配置 Python 开发环境,包括安装 Python、配置虚拟环境以及使用 VS Code 进行…

基于云效 Windows 构建环境和 Nuget 制品仓库进行 .Net 应用开发

本文将基于云效 Flow 流水线 Windows 构建环境和云效 Packages Nuget 制品仓库手把手教你如何开发并部署一个 .NET 应用,从环境搭建到实战应用发布的详细教程,帮助你掌握 .NET 开发的核心技能。作者:陆冬澄、周静 在现代软件研发体系中,.NET 平台由于其强大的功能、灵活性和…