最新要闻
- 微动态丨各地计划生育宣传标语大全_最新计划生育宣传标语口号大全
- 男生中考忘涂机读卡妈妈崩溃大哭 让人心疼:网友疑惑这怎么会忘? 新要闻
- 零刻GTR7迷你主机618大促:R7 7840HS只要2680元
- 斐济群岛发生7.2级地震 预计不会发生海啸 新资讯
- Bungie程序员批暴雪太懒|焦点简讯
- 焦点速读:不寒而栗!英美团队称创造出全球首个合成人类胚胎模型 无需精子和卵子
- 联想小新Pro 2023酷睿版直降700元 32GB内存超大杯5599元
- 世界速读:有多少中国人 正假冒俄罗斯人直播带货?
- 小米14提前发:采用华星极窄边框直屏 颜值胜过iPhone 14 Pro 环球动态
- 【天天速看料】骁龙最强芯+2K直屏!宋紫薇预告iQOO 11S
- 世界看点:《小美人鱼》豆瓣评分人数38591人 口碑暴降至5.1分:国人都不爱看黑美人鱼?
- 北京理想汽车获得纯电/增程生产资质:规划有5款纯电新车
- DC宇宙重启之作!超英大片《闪电侠》上映:蝙蝠侠、超女联手登场
- 主页不刷新!网易LOFTER深夜崩溃:大量用户以为账号被封
- 【全球新要闻】PC玩家:没SSD 以后游戏都不让玩了?
- 这涂装属实有点帅!迷彩版特斯拉Cybertruck亮相街头|环球快讯
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
Spring Boot 实现定时任务动态管理,太爽了! 头条
一、功能说明
SpringBoot的定时任务的加强工具,实现对SpringBoot原生的定时任务进行动态管理,完全兼容原生@Scheduled注解,无需对原本的定时任务进行修改
(相关资料图)
二、快速使用
具体的功能已经封装成SpringBoot-starter即插即用:
com.github.guoyixing spring-boot-starter-super-scheduled 0.3.1
使用方法和源码:
- 码云:https://gitee.com/qiaodaimadewangcai/super-scheduled
- github:https://github.com/guoyixing/super-scheduled
推荐一个开源免费的 Spring Boot 实战项目:
https://github.com/javastacks/spring-boot-best-practice
三、实现原理
1、动态管理实现
(1) 配置管理介绍
@Component("superScheduledConfig")public class SuperScheduledConfig { /** * 执行定时任务的线程池 */ private ThreadPoolTaskScheduler taskScheduler; /** * 定时任务名称与定时任务回调钩子 的关联关系容器 */ private Map nameToScheduledFuture = new ConcurrentHashMap<>(); /** * 定时任务名称与定时任务需要执行的逻辑 的关联关系容器 */ private Map nameToRunnable = new ConcurrentHashMap<>(); /** * 定时任务名称与定时任务的源信息 的关联关系容器 */ private Map nameToScheduledSource = new ConcurrentHashMap<>(); /* 普通的get/sets省略 */}
(2) 使用后处理器拦截SpringBoot原本的定时任务
- 实现
ApplicationContextAware
接口拿到SpringBoot的上下文 - 实现
BeanPostProcessor
接口,将这个类标记为后处理器,后处理器会在每个bean实例化之后执行 - 使用
@DependsOn
注解强制依赖SuperScheduledConfig
类,让SpringBoot实例化SuperScheduledPostProcessor
类之前先实例化SuperScheduledConfig
类 - 主要实现逻辑在
postProcessAfterInitialization()
方法中
@DependsOn({"superScheduledConfig"})@Component@Orderpublic class SuperScheduledPostProcessor implements BeanPostProcessor, ApplicationContextAware { protected final Log logger = LogFactory.getLog(getClass()); private ApplicationContext applicationContext; /** * 实例化bean之前的操作 * @param bean bean实例 * @param beanName bean的Name */ @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } /** * 实例化bean之后的操作 * @param bean bean实例 * @param beanName bean的Name */ @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { //1.获取配置管理器 SuperScheduledConfig superScheduledConfig = applicationContext.getBean(SuperScheduledConfig.class); //2.获取当前实例化完成的bean的所有方法 Method[] methods = bean.getClass().getDeclaredMethods(); //循环处理对每个方法逐一处理 if (methods.length > 0) { for (Method method : methods) { //3.尝试在该方法上获取@Scheduled注解(SpringBoot的定时任务注解) Scheduled annotation = method.getAnnotation(Scheduled.class); //如果无法获取到@Scheduled注解,就跳过这个方法 if (annotation == null) { continue; } //4.创建定时任务的源属性 //创建定时任务的源属性(用来记录定时任务的配置,初始化的时候记录的是注解上原本的属性) ScheduledSource scheduledSource = new ScheduledSource(annotation, method, bean); //对注解上获取到源属性中的属性进行检测 if (!scheduledSource.check()) { throw new SuperScheduledException("在" + beanName + "Bean中" + method.getName() + "方法的注解参数错误"); } //生成定时任务的名称(id),使用beanName+“.”+方法名 String name = beanName + "." + method.getName(); //将以key-value的形式,将源数据存入配置管理器中,key:定时任务的名称 value:源数据 superScheduledConfig.addScheduledSource(name, scheduledSource); try { //5.将原本SpringBoot的定时任务取消掉 clearOriginalScheduled(annotation); } catch (Exception e) { throw new SuperScheduledException("在关闭原始方法" + beanName + method.getName() + "时出现错误"); } } } //最后bean保持原有返回 return bean; } /** * 修改注解原先的属性 * @param annotation 注解实例对象 * @throws Exception */ private void clearOriginalScheduled(Scheduled annotation) throws Exception { changeAnnotationValue(annotation, "cron", Scheduled.CRON_DISABLED); changeAnnotationValue(annotation, "fixedDelay", -1L); changeAnnotationValue(annotation, "fixedDelayString", ""); changeAnnotationValue(annotation, "fixedRate", -1L); changeAnnotationValue(annotation, "fixedRateString", ""); changeAnnotationValue(annotation, "initialDelay", -1L); changeAnnotationValue(annotation, "initialDelayString", ""); } /** * 获取SpringBoot的上下文 * @param applicationContext SpringBoot的上下文 */ @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; }}
(3) 使用ApplicationRunner
初始化自定义的定时任务运行器
- 实现
ApplicationContextAware
接口拿到SpringBoot的上下文 - 使用
@DependsOn
注解强制依赖threadPoolTaskScheduler
类 - 实现
ApplicationRunner
接口,在所有bean初始化结束之后,运行自定义逻辑 - 主要实现逻辑在
run()
方法中
@DependsOn("threadPoolTaskScheduler")@Componentpublic class SuperScheduledApplicationRunner implements ApplicationRunner, ApplicationContextAware { protected final Log logger = LogFactory.getLog(getClass()); private DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); private ApplicationContext applicationContext; /** * 定时任务配置管理器 */ @Autowired private SuperScheduledConfig superScheduledConfig; /** * 定时任务执行线程 */ @Autowired private ThreadPoolTaskScheduler threadPoolTaskScheduler; @Override public void run(ApplicationArguments args) { //1.定时任务配置管理器中缓存 定时任务执行线程 superScheduledConfig.setTaskScheduler(threadPoolTaskScheduler); //2.获取所有定时任务源数据 Map nameToScheduledSource = superScheduledConfig.getNameToScheduledSource(); //逐一处理定时任务 for (String name : nameToScheduledSource.keySet()) { //3.获取定时任务源数据 ScheduledSource scheduledSource = nameToScheduledSource.get(name); //4.获取所有增强类 String[] baseStrengthenBeanNames = applicationContext.getBeanNamesForType(BaseStrengthen.class); //5.创建执行控制器 SuperScheduledRunnable runnable = new SuperScheduledRunnable(); //配置执行控制器 runnable.setMethod(scheduledSource.getMethod()); runnable.setBean(scheduledSource.getBean()); //6.逐一处理增强类(增强器实现原理后面具体分析) List points = new ArrayList<>(baseStrengthenBeanNames.length); for (String baseStrengthenBeanName : baseStrengthenBeanNames) { //7.将增强器代理成point Object baseStrengthenBean = applicationContext.getBean(baseStrengthenBeanName); //创建代理 Point proxy = ProxyUtils.getInstance(Point.class, new RunnableBaseInterceptor(baseStrengthenBean, runnable)); proxy.setSuperScheduledName(name); //8.所有的points连成起来 points.add(proxy); } //将point形成调用链 runnable.setChain(new Chain(points)); //将执行逻辑封装并缓存到定时任务配置管理器中 superScheduledConfig.addRunnable(name, runnable::invoke); try { //8.启动定时任务 ScheduledFuture> schedule = ScheduledFutureFactory.create(threadPoolTaskScheduler , scheduledSource, runnable::invoke); //将线程回调钩子存到任务配置管理器中 superScheduledConfig.addScheduledFuture(name, schedule); logger.info(df.format(LocalDateTime.now()) + "任务" + name + "已经启动..."); } catch (Exception e) { throw new SuperScheduledException("任务" + name + "启动失败,错误信息:" + e.getLocalizedMessage()); } } } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; }}
(4) 进行动态管理
@Componentpublic class SuperScheduledManager { protected final Log logger = LogFactory.getLog(getClass()); private DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); @Autowired private SuperScheduledConfig superScheduledConfig; /** * 修改Scheduled的执行周期 * * @param name scheduled的名称 * @param cron cron表达式 */ public void setScheduledCron(String name, String cron) { //终止原先的任务 cancelScheduled(name); //创建新的任务 ScheduledSource scheduledSource = superScheduledConfig.getScheduledSource(name); scheduledSource.clear(); scheduledSource.setCron(cron); addScheduled(name, scheduledSource); } /** * 修改Scheduled的fixedDelay * * @param name scheduled的名称 * @param fixedDelay 上一次执行完毕时间点之后多长时间再执行 */ public void setScheduledFixedDelay(String name, Long fixedDelay) { //终止原先的任务 cancelScheduled(name); //创建新的任务 ScheduledSource scheduledSource = superScheduledConfig.getScheduledSource(name); scheduledSource.clear(); scheduledSource.setFixedDelay(fixedDelay); addScheduled(name, scheduledSource); } /** * 修改Scheduled的fixedRate * * @param name scheduled的名称 * @param fixedRate 上一次开始执行之后多长时间再执行 */ public void setScheduledFixedRate(String name, Long fixedRate) { //终止原先的任务 cancelScheduled(name); //创建新的任务 ScheduledSource scheduledSource = superScheduledConfig.getScheduledSource(name); scheduledSource.clear(); scheduledSource.setFixedRate(fixedRate); addScheduled(name, scheduledSource); } /** * 查询所有启动的Scheduled */ public List getRunScheduledName() { Set names = superScheduledConfig.getNameToScheduledFuture().keySet(); return new ArrayList<>(names); } /** * 查询所有的Scheduled */ public List getAllSuperScheduledName() { Set names = superScheduledConfig.getNameToRunnable().keySet(); return new ArrayList<>(names); } /** * 终止Scheduled * * @param name scheduled的名称 */ public void cancelScheduled(String name) { ScheduledFuture scheduledFuture = superScheduledConfig.getScheduledFuture(name); scheduledFuture.cancel(true); superScheduledConfig.removeScheduledFuture(name); logger.info(df.format(LocalDateTime.now()) + "任务" + name + "已经终止..."); } /** * 启动Scheduled * * @param name scheduled的名称 * @param scheduledSource 定时任务的源信息 */ public void addScheduled(String name, ScheduledSource scheduledSource) { if (getRunScheduledName().contains(name)) { throw new SuperScheduledException("定时任务" + name + "已经被启动过了"); } if (!scheduledSource.check()) { throw new SuperScheduledException("定时任务" + name + "源数据内容错误"); } scheduledSource.refreshType(); Runnable runnable = superScheduledConfig.getRunnable(name); ThreadPoolTaskScheduler taskScheduler = superScheduledConfig.getTaskScheduler(); ScheduledFuture> schedule = ScheduledFutureFactory.create(taskScheduler, scheduledSource, runnable); logger.info(df.format(LocalDateTime.now()) + "任务" + name + "已经启动..."); superScheduledConfig.addScheduledSource(name, scheduledSource); superScheduledConfig.addScheduledFuture(name, schedule); } /** * 以cron类型启动Scheduled * * @param name scheduled的名称 * @param cron cron表达式 */ public void addCronScheduled(String name, String cron) { ScheduledSource scheduledSource = new ScheduledSource(); scheduledSource.setCron(cron); addScheduled(name, scheduledSource); } /** * 以fixedDelay类型启动Scheduled * * @param name scheduled的名称 * @param fixedDelay 上一次执行完毕时间点之后多长时间再执行 * @param initialDelay 第一次执行的延迟时间 */ public void addFixedDelayScheduled(String name, Long fixedDelay, Long... initialDelay) { ScheduledSource scheduledSource = new ScheduledSource(); scheduledSource.setFixedDelay(fixedDelay); if (initialDelay != null && initialDelay.length == 1) { scheduledSource.setInitialDelay(initialDelay[0]); } else if (initialDelay != null && initialDelay.length > 1) { throw new SuperScheduledException("第一次执行的延迟时间只能传入一个参数"); } addScheduled(name, scheduledSource); } /** * 以fixedRate类型启动Scheduled * * @param name scheduled的名称 * @param fixedRate 上一次开始执行之后多长时间再执行 * @param initialDelay 第一次执行的延迟时间 */ public void addFixedRateScheduled(String name, Long fixedRate, Long... initialDelay) { ScheduledSource scheduledSource = new ScheduledSource(); scheduledSource.setFixedRate(fixedRate); if (initialDelay != null && initialDelay.length == 1) { scheduledSource.setInitialDelay(initialDelay[0]); } else if (initialDelay != null && initialDelay.length > 1) { throw new SuperScheduledException("第一次执行的延迟时间只能传入一个参数"); } addScheduled(name, scheduledSource); } /** * 手动执行一次任务 * * @param name scheduled的名称 */ public void runScheduled(String name) { Runnable runnable = superScheduledConfig.getRunnable(name); runnable.run(); }}
2、增强接口实现
增强器实现的整体思路与SpringAop的思路一致,实现没有Aop复杂
(1) 增强接口
@Order(Ordered.HIGHEST_PRECEDENCE)public interface BaseStrengthen { /** * 前置强化方法 * * @param bean bean实例(或者是被代理的bean) * @param method 执行的方法对象 * @param args 方法参数 */ void before(Object bean, Method method, Object[] args); /** * 后置强化方法 * 出现异常不会执行 * 如果未出现异常,在afterFinally方法之后执行 * * @param bean bean实例(或者是被代理的bean) * @param method 执行的方法对象 * @param args 方法参数 */ void after(Object bean, Method method, Object[] args); /** * 异常强化方法 * * @param bean bean实例(或者是被代理的bean) * @param method 执行的方法对象 * @param args 方法参数 */ void exception(Object bean, Method method, Object[] args); /** * Finally强化方法,出现异常也会执行 * * @param bean bean实例(或者是被代理的bean) * @param method 执行的方法对象 * @param args 方法参数 */ void afterFinally(Object bean, Method method, Object[] args);}
(2) 代理抽象类
public abstract class Point { /** * 定时任务名 */ private String superScheduledName; /** * 抽象的执行方法,使用代理实现 * @param runnable 定时任务执行器 */ public abstract Object invoke(SuperScheduledRunnable runnable); /* 普通的get/sets省略 */}
(3) 调用链类
public class Chain { private List list; private int index = -1; /** * 索引自增1 */ public int incIndex() { return ++index; } /** * 索引还原 */ public void resetIndex() { this.index = -1; }}
(4) cglib动态代理实现
使用cglib代理增强器,将增强器全部代理成调用链节点Point
public class RunnableBaseInterceptor implements MethodInterceptor { /** * 定时任务执行器 */ private SuperScheduledRunnable runnable; /** * 定时任务增强类 */ private BaseStrengthen strengthen; @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object result; //如果执行的是invoke()方法 if ("invoke".equals(method.getName())) { //前置强化方法 strengthen.before(obj, method, args); try { //调用执行器中的invoke()方法 result = runnable.invoke(); } catch (Exception e) { //异常强化方法 strengthen.exception(obj, method, args); throw new SuperScheduledException(strengthen.getClass() + "中强化执行时发生错误", e); } finally { //Finally强化方法,出现异常也会执行 strengthen.afterFinally(obj, method, args); } //后置强化方法 strengthen.after(obj, method, args); } else { //直接执行方法 result = methodProxy.invokeSuper(obj, args); } return result; } public RunnableBaseInterceptor(Object object, SuperScheduledRunnable runnable) { this.runnable = runnable; if (BaseStrengthen.class.isAssignableFrom(object.getClass())) { this.strengthen = (BaseStrengthen) object; } else { throw new SuperScheduledException(object.getClass() + "对象不是BaseStrengthen类型"); } } public RunnableBaseInterceptor() { }}
(5) 定时任务执行器实现
public class SuperScheduledRunnable { /** * 原始的方法 */ private Method method; /** * 方法所在的bean */ private Object bean; /** * 增强器的调用链 */ private Chain chain; public Object invoke() { Object result; //索引自增1 if (chain.incIndex() == chain.getList().size()) { //调用链中的增强方法已经全部执行结束 try { //调用链索引初始化 chain.resetIndex(); //增强器全部执行完毕,执行原本的方法 result = method.invoke(bean); } catch (IllegalAccessException | InvocationTargetException e) { throw new SuperScheduledException(e.getLocalizedMessage()); } } else { //获取被代理后的方法增强器 Point point = chain.getList().get(chain.getIndex()); //执行增强器代理 //增强器代理中,会回调方法执行器,形成调用链,逐一运行调用链中的增强器 result = point.invoke(this); } return result; } /* 普通的get/sets省略 */}
(6) 增强器代理逻辑
com.gyx.superscheduled.core.SuperScheduledApplicationRunner
类中的代码片段
//创建执行控制器SuperScheduledRunnable runnable = new SuperScheduledRunnable();runnable.setMethod(scheduledSource.getMethod());runnable.setBean(scheduledSource.getBean());//用来存放 增强器的代理对象List points = new ArrayList<>(baseStrengthenBeanNames.length);//循环所有的增强器的beanNamefor (String baseStrengthenBeanName : baseStrengthenBeanNames) { //获取增强器的bean对象 Object baseStrengthenBean = applicationContext.getBean(baseStrengthenBeanName); //将增强器代理成Point节点 Point proxy = ProxyUtils.getInstance(Point.class, new RunnableBaseInterceptor(baseStrengthenBean, runnable)); proxy.setSuperScheduledName(name); //增强器的代理对象缓存到list中 points.add(proxy);}//将增强器代理实例的集合生成调用链//执行控制器中设置调用链runnable.setChain(new Chain(points));
版权声明:本文为CSDN博主「敲代码的旺财」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/qq_34886352/article/details/106494637
近期热文推荐:
1.1,000+ 道 Java面试题及答案整理(2022最新版)
2.劲爆!Java 协程要来了。。。
3.Spring Boot 2.x 教程,太全了!
4.别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!
5.《Java开发手册(嵩山版)》最新发布,速速下载!
觉得不错,别忘了随手点赞+转发哦!
关键词:
Spring Boot 实现定时任务动态管理,太爽了! 头条
当前讯息:【一步步开发AI运动小程序】十二、自定义一个运动分析器,实现计时计数01
微动态丨各地计划生育宣传标语大全_最新计划生育宣传标语口号大全
男生中考忘涂机读卡妈妈崩溃大哭 让人心疼:网友疑惑这怎么会忘? 新要闻
零刻GTR7迷你主机618大促:R7 7840HS只要2680元
斐济群岛发生7.2级地震 预计不会发生海啸 新资讯
Bungie程序员批暴雪太懒|焦点简讯
焦点速读:不寒而栗!英美团队称创造出全球首个合成人类胚胎模型 无需精子和卵子
联想小新Pro 2023酷睿版直降700元 32GB内存超大杯5599元
世界速读:有多少中国人 正假冒俄罗斯人直播带货?
小米14提前发:采用华星极窄边框直屏 颜值胜过iPhone 14 Pro 环球动态
今日看点:100个物联网项目(基于ESP32)1ESP32的基础
读数据压缩入门笔记05_字典转换|全球焦点
全球热消息:快速上手kettle(四)壶中可以倒出些啥?
【天天速看料】骁龙最强芯+2K直屏!宋紫薇预告iQOO 11S
世界看点:《小美人鱼》豆瓣评分人数38591人 口碑暴降至5.1分:国人都不爱看黑美人鱼?
北京理想汽车获得纯电/增程生产资质:规划有5款纯电新车
DC宇宙重启之作!超英大片《闪电侠》上映:蝙蝠侠、超女联手登场
主页不刷新!网易LOFTER深夜崩溃:大量用户以为账号被封
【全球新要闻】PC玩家:没SSD 以后游戏都不让玩了?
这涂装属实有点帅!迷彩版特斯拉Cybertruck亮相街头|环球快讯
顾客吐槽海底捞8块钱生菜仅2片 门店回应:精准按克称重 没问题-天天热头条
成龙晒合影悼念黄永玉 二人结缘于电影《十二生肖》
PC玩家:没SSD就没法玩游戏了
这次41位“乘客”上天!中国新纪录
网络传输中的重要参数-简单的网络画像 天天聚看点
文心一言 VS 讯飞星火 VS chatgpt (42)-- 算法导论5.4 6题_聚看点
新华书店真不差钱:顾客“只看不买” 营收仍有上千亿-焦点消息
每日焦点!杭州第19届亚运会奖牌“湖山”正式发布:印有断桥、三潭印月
Intel处理器品牌正式升级!有请全新的酷睿Ultra|环球消息
国产之光!比亚迪登2023年BrandZ最具价值榜前十:唯一中国汽车品牌
第三次博客:PTA题目集6-8总结-当前信息
索尼LYTIA公布新品:一口气推出5款5000万像素传感器_天天热点评
观热点:2岁女童误吞23颗磁力珠 医生:随时可能发生肠穿孔
亏电3.9升、纯电跑200km!比亚迪驱逐舰07申报:合资中型轿车发抖
《神鬼寓言》女性设计引热议:东西方怎么差这么多?
B社《星空》引力惊人:法国XSX销量暴涨1335%
Java并发(十)----线程之守护线程 今日讯
商务部:两个原因致全国实际使用外资以美元计下降_天天时快讯
打破国外垄断 国产GPU架构天狼星亮相:自研架构自主可控|即时焦点
全球短讯!贾跃亭透露创业心酸:被美国市场教育 战胜华尔街顶级破产黑帮
梅西今晚8点首发出场!直击北京工体蹲守现场:人满为患-环球时讯
理想L9 Pro来了!将取消激光雷达!预估售价42-43万元
天天日报丨体型太大!美国大码女子乘飞机被要求买2座位:吐槽称难受又费钱
微服务配置中心选型比较——Nacos、Apollo
记录--前端如何优雅导出多表头xlsx
昂利康:七氟烷原料药上市申请获批
新西兰经济陷入技术性衰退
天天热头条丨商品日报(6月15日):焦煤领涨商品市场 贵金属承压下行
新华指数|钢“财”说:库存降幅收窄,宏观情绪回暖|全球最资讯
新出行贺磊聊“李想疯狂输出的背后” 点名多位车企高管
北京工体梅西含量超标:今晚8点举行足球友谊赛-全球快看点
一加第四款《原神》联名机在路上了:这次主角是派蒙
双髻鲨头上的“锤子”有什么用? 世界热资讯
618先别买洗地机!分享几条你不知道的要点|即时焦点
万方查重多久出报告(万方查重)-全球速递
扩展中国剩余定理(EXCRT)
天天即时看!三类重要Linux文件的用途与区别
沉浸式的使用 Windows/office激活工具|环球聚焦
delphi7使用rave5.0展现数据库数据报表
一文读懂物联网平台如何搞定80%以上的物联网项目
最新快讯!经常出汗是怎么回事呢_经常出汗是怎么回事
亚运会倒计时100天!vivo成手机独家供应商:交付vivo X90s、iQOO 11S 天天要闻
世界即时:越南人的国民神车! 越南版“宝骏悦也”发布:车长仅3114mm
天天快看点丨河北热成了炣北!多地气温突破40℃:石家庄成今年首个40℃省会级城市
环球要闻:谷歌推出“硬核”智能家居编辑器:支持用户手搓脚本
环球最资讯丨周鸿祎:做大模型这3个月 最惭愧的是自己不擅长吹牛
美晨生态:诸城经开投累计质押股数约为7843万股
世界视讯!如何优雅地使用Low Code提高开发效率
环球热点!ctfpwn-堆入门之uaf(新手向)
会说话!爱德华兹谈生涯至今最爱的时刻:唐斯的60分之夜
游戏网站开除40%员工 “AI编辑”每周撰写数百篇问题文章引众怒|每日焦点
让手机更智能!小米小爱建议宣布已覆盖40余款机型 看看有你的吗?|全球报道
3A大作游戏《星空》尚未发售 却已收到玩家差评:直接0分 焦点速看
夜景拍摄表现出彩:尼康尼克尔Z DX 24mm f/1.7镜头开售_全球观热点
天天最新:芭比娃娃真人电影《芭比》确认引进中国内地:画风对比《小美人鱼》如何?
vivox9什么时候上市的多少钱(vivox9什么时候上市的) 最新资讯
资讯:上传自己java项目到maven中央仓库pom
当前关注:《深入探索C++对象模型》- 第一章 - 关于对象 - 笔记
.NET 文件上传服务设计 天天快播报
变形积木:以装配式装修助力美团酒店布局“百品、千城、万店”-当前观点
国资委召开中央企业提高上市公司质量暨并购重组工作专题会-环球热资讯
科创板收盘播报:科创50指数跌0.14% 电气设备股表现强势|环球热议
马斯克邀请丰田加入特斯拉快充阵营:你们充电太慢了
要闻:新一轮油价调整将于6月28日开启 这次又有降价的可能
Steam客户端大规模更新!新增实用笔记功能 世界热议
AMD Yes!RX 6650 XT显卡杀到1799元:比N卡更香 天天播资讯
贾跃亭团队出身就是不一样!高合HiPhi Y内饰官图发布:平替FF 91
世界热文:手机微信出现状态是什么意思(微信出现状态是怎么回事)
云小课|RDS for MySQL参数模板一键导入导出,参数配置轻松搞定|焦点简讯
【环球时快讯】数据分析提效5倍,国有集团企业数字化历程 | 数字化标杆
ESMapV数字孪生三维可视化云平台-零代码可视化设计师助力者
flask自定义参数校验、序列化和反序列化_视讯
出庭当晚特朗普与“金主”举行晚宴,筹得200多万美元-世界微头条
微资讯!新华社权威快报|“一箭41星” 发射成功
欠2.4亿罚款又如何?贾跃亭国内“现身”:我不要烧太多钱也能快速成功 环球快讯
端午节放假3天自驾方便了!滴滴租车正式上线:跑车、房车全都有
全球即时:一机搞定全屋清洁!石头新品洗地机A10 Ultra今晚首销:到手价3399元
1799元咬死RTX 3060显卡 英特尔新驱动继续鸡血:性能猛增33%|当前快看
用上丰田氢燃料电池 海马7X-H来了:不到5分钟加注续航达800km-天天微速讯