Java 代码重试实现方式

Java 代码重试实现方式

  • 一.方法内直接自动重试
  • 二.静态代理方式
    • 1.启动类
    • 2.接口
    • 3.实现
    • 4.静态代理
    • 5.单元测试类
  • 三.JDK 动态代理
    • 1.代理类
    • 2.单元测试
  • 四.CGLIB 动态代理
    • 1.动态代理类
    • 2.单元测试
  • 五.手动 AOP
    • 1.自定义注解
    • 2.重试注解切面
    • 3.测试类
    • 4.单元测试方法
  • 六.Spring Retry
    • 1.测试类
    • 2.单元测试类
    • 3.单元测试方法
  • 七.Guava Retry
    • 1.测试类
    • 2.单元测试

依赖包

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>learn-demo</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>20</maven.compiler.source><maven.compiler.target>20</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><spring.version>3.1.2</spring.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.28</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>2.0.32</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.19</version></dependency><dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>6.0.11</version></dependency></dependencies></project>

一.方法内直接自动重试

    public static void main(String[] args) {autoRetry(3);}/*** 自动重试(执行总次数包含于重试次数内)* 优点:实现简单* 缺点:复用性差,代码侵入* @param retryTimes*/public static void autoRetry(int retryTimes){int times = 0;do {try {int i = 3/0;} catch (Exception e) {times++;System.out.println("第" + times + "次失败");}} while (times < retryTimes);}

二.静态代理方式

1.启动类

package org.example;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;/*** @author Administrator*/
@SpringBootApplication
public class LearnApp {public static void main(String[] args) {SpringApplication.run(LearnApp.class,args);}
}

2.接口

package org.example.service;/*** @description* @author zhuwd && moon* @version 1.0*/
public interface LearnService {/*** 自动重试*/void autoRetry();
}

3.实现

package org.example.service.impl;import org.example.service.LearnService;
import org.springframework.stereotype.Service;/*** @author zhuwd && moon* @Description* @create 2023-08-08 1:05*/
@Service
public class LearnServiceImpl implements LearnService {@Overridepublic void autoRetry() {throw new RuntimeException();}
}

4.静态代理

package org.example.service.impl;import org.example.service.LearnService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;/*** @author zhuwd && moon* @Description* @create 2023-08-08 1:06*/
@Service
public class LearnServiceProxyImpl implements LearnService {@Autowiredprivate LearnServiceImpl learnService;private static final int RETRY_TIMES = 3;@Overridepublic void autoRetry() {int times = 0;do {try {learnService.autoRetry();} catch (Exception e) {times++;System.out.println("第" + times + "次失败");}} while (times < RETRY_TIMES);}
}

5.单元测试类

import org.example.LearnApp;
import org.example.service.impl.LearnServiceProxyImpl;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;/*** @author zhuwd && moon* @Description* @create 2023-08-08 1:11*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = LearnApp.class)
public class LearnTest {@AutowiredLearnServiceProxyImpl learnServiceProxy;@Testpublic void test(){learnServiceProxy.autoRetry();}}

在这里插入图片描述

三.JDK 动态代理

1.代理类

package org.example.proxy;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;/*** @author zhuwd && moon* @Description 实现方式较优雅,但是被代理的类必须实现某个接口才能操作* @create 2023-08-08 21:14*/
public class RetryInvocationHandler implements InvocationHandler {private static final int RETRY_TIMES = 3;/*** 目标对象*/private final Object target;/*** 有参构造* @param target*/public RetryInvocationHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {int times = 0;do {try {return method.invoke(target,args);} catch (Exception e) {times++;System.out.println("第" + times + "次失败");}} while (times < RETRY_TIMES);return null;}
}

2.单元测试

import org.example.LearnApp;
import org.example.proxy.RetryInvocationHandler;
import org.example.service.LearnService;
import org.example.service.impl.LearnServiceImpl;
import org.example.service.impl.LearnServiceProxyImpl;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;/*** @author zhuwd && moon* @Description* @create 2023-08-08 1:11*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = LearnApp.class)
public class LearnTest {@AutowiredLearnServiceImpl learnService;@Testpublic void testJdk(){InvocationHandler handler = new RetryInvocationHandler(learnService);LearnService service = (LearnService) Proxy.newProxyInstance(handler.getClass().getClassLoader(), learnService.getClass().getInterfaces(),handler);service.autoRetry();}
}

在这里插入图片描述

四.CGLIB 动态代理

注意依赖选择 cglib 包下的,不要用 spring 下的

1.动态代理类

package org.example.proxy;import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;/*** @author zhuwd && moon* @Description* @create 2023-08-08 21:25*/
public class CGLibRetryProxyHandler implements MethodInterceptor {private static final int RETRY_TIMES = 3;private Object target;@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {int times = 0;do {try {return method.invoke(target,objects);} catch (Exception e) {times++;System.out.println("第" + times + "次失败");}} while (times < RETRY_TIMES);return null;}/*** 生产代理类* @param target* @return*/public Object getProxy(Object target){this.target = target;Enhancer enhancer = new Enhancer();enhancer.setSuperclass(this.target.getClass());enhancer.setCallback(this);enhancer.setClassLoader(this.target.getClass().getClassLoader());Object proxy = enhancer.create();return proxy;}}

2.单元测试

import org.example.LearnApp;
import org.example.proxy.CGLibRetryProxyHandler;
import org.example.service.LearnService;
import org.example.service.impl.LearnServiceImpl;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;/*** @author zhuwd && moon* @Description* @create 2023-08-08 1:11*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = LearnApp.class)
public class LearnTest {@AutowiredLearnServiceImpl learnService;@Testpublic void testCglib(){CGLibRetryProxyHandler handler = new CGLibRetryProxyHandler();LearnService service = (LearnService) handler.getProxy(learnService);service.autoRetry();}
}
如果是JDK17及以上版本,用IDEA调试需要增加VM配置:--add-opens java.base/java.lang=ALL-UNNAMED

在这里插入图片描述

在这里插入图片描述

五.手动 AOP

利用自定义注解实现重试AOP逻辑

1.自定义注解

package org.example.anno;import java.lang.annotation.*;/*** @author zhuwd && moon* @Description* @create 2023-08-08 22:50*/
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RetryAnno {/*** 重试次数* @return*/int retryTimes() default 3;/*** 重试间隔(s)* @return*/int retryInterval() default 3;}

2.重试注解切面

package org.example.config;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.example.anno.RetryAnno;
import org.springframework.stereotype.Component;import java.util.concurrent.TimeUnit;/*** @author zhuwd && moon* @Description* @create 2023-08-08 22:52*/
@Aspect
@Component
public class RetryAspect {@Pointcut("@annotation(org.example.anno.RetryAnno)")private void retryCall(){};@Around("retryCall()")public Object retry(ProceedingJoinPoint joinPoint) throws Throwable{MethodSignature signature = (MethodSignature) joinPoint.getSignature();RetryAnno retryAnno = signature.getMethod().getAnnotation(RetryAnno.class);int retryTimes = retryAnno.retryTimes();int retryInterval = retryAnno.retryInterval();int times = 0;do {try {return joinPoint.proceed();} catch (Exception e) {times++;System.out.println(System.currentTimeMillis() + "  第" + times + "次失败");TimeUnit.SECONDS.sleep(retryInterval);}} while (times < retryTimes);return null;}}

3.测试类

package org.example.config;import org.example.anno.RetryAnno;
import org.springframework.stereotype.Component;/*** @author zhuwd && moon* @Description* @create 2023-08-08 23:02*/
@Component
public class LearnRetry {@RetryAnno(retryTimes = 3,retryInterval = 3)public void retry(){throw new RuntimeException();}}

4.单元测试方法

import org.example.LearnApp;
import org.example.config.LearnRetry;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;/*** @author zhuwd && moon* @Description* @create 2023-08-08 1:11*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = LearnApp.class)
public class LearnTest {@AutowiredLearnRetry learnRetry;@Testpublic void testAopRetry(){learnRetry.retry();}
}

在这里插入图片描述

六.Spring Retry

<dependency><groupId>org.springframework.retry</groupId><artifactId>spring-retry</artifactId><version>2.0.2</version>
</dependency>

1.测试类

package org.example.config;import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.EnableRetry;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Component;/*** @author zhuwd && moon* @Description* @create 2023-08-08 23:10*/
@Component
@EnableRetry
public class SpringRetry {/*** maxAttempts 最大重试次数* backoff.delay 重试延迟* backoff.multiplier 延迟倍数,即第一次间隔 2S 第二次将间隔 4秒*/@Retryable(maxAttempts = 3,backoff = @Backoff(delay = 2000,multiplier = 2))public void retry(){System.out.println(System.currentTimeMillis() + "  重试 ...");throw new RuntimeException();}/*** @Recover 注解必须和 @Retryable 在同一个类;且返回值一致不能抛出额外异常** @param e*/@Recoverpublic void recover(RuntimeException e){System.out.println("已达最大重试次数");}}

2.单元测试类

import org.example.LearnApp;
import org.example.config.SpringRetry;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;/*** @author zhuwd && moon* @Description* @create 2023-08-08 1:11*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = LearnApp.class)
public class LearnTest {@AutowiredSpringRetry springRetry;@Testpublic void testSpringRetry(){springRetry.retry();}
}

在这里插入图片描述

3.单元测试方法

import org.example.LearnApp;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.retry.backoff.FixedBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import java.util.HashMap;
import java.util.Map;/*** @author zhuwd && moon* @Description* @create 2023-08-08 1:11*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = LearnApp.class)
public class LearnTest {public void retry(){System.out.println(System.currentTimeMillis() + "  重试 ...");throw new RuntimeException();}@Testpublic void testSpringRetryMethod(){RetryTemplate template = new RetryTemplate();/*** 重试策略*/Map<Class<? extends Throwable>,Boolean> map = new HashMap<>();map.put(RuntimeException.class,true);SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(3,map);/*** 重试回退策略*/FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();backOffPolicy.setBackOffPeriod(2000);template.setRetryPolicy(retryPolicy);template.setBackOffPolicy(backOffPolicy);Boolean execute = template.execute(retryContext -> {retry();return true;},retryContext -> {System.out.println("已达最大重试次数");return false;});System.out.println("调用结果 " + execute);}
}

在这里插入图片描述

七.Guava Retry

<dependency><groupId>com.github.rholder</groupId><artifactId>guava-retrying</artifactId><version>2.0.0</version>
</dependency>

1.测试类

package org.example.config;import org.springframework.stereotype.Component;/*** @author zhuwd && moon* @Description 10S 后返回正确值* @create 2023-08-08 23:49*/
@Component
public class GuavaRetry {private static long init_time = System.currentTimeMillis() + 1000 * 10;public int retry(){if (System.currentTimeMillis() > init_time){return 0;}return -1;}}

2.单元测试

import com.github.rholder.retry.*;
import org.example.LearnApp;
import org.example.config.GuavaRetry;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;/*** @author zhuwd && moon* @Description* @create 2023-08-08 1:11*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = LearnApp.class)
public class LearnTest {@AutowiredGuavaRetry guavaRetry;@Testpublic void testGuavaRetry(){Retryer<Integer> retryer = RetryerBuilder.<Integer>newBuilder()//根据异常重试.retryIfException()//根据结果重试.retryIfResult(result-> !Objects.equals(result,0))//重试策略.withWaitStrategy(WaitStrategies.fixedWait(2, TimeUnit.SECONDS))//停止策略.withStopStrategy(StopStrategies.stopAfterAttempt(300))//监听重试进度.withRetryListener(new RetryListener() {@Overridepublic <V> void onRetry(Attempt<V> attempt) {System.out.println(System.currentTimeMillis() + "  第" + attempt.getAttemptNumber() + "次失败");}}).build();try {int result = retryer.call(()->guavaRetry.retry());System.out.println("调用结果:" + result);} catch (ExecutionException e) {throw new RuntimeException(e);} catch (RetryException e) {throw new RuntimeException(e);}}}

在这里插入图片描述

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

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

相关文章

【Linux】深入理解进程概念

个人主页&#xff1a;&#x1f35d;在肯德基吃麻辣烫 我的gitee&#xff1a;Linux仓库 个人专栏&#xff1a;Linux专栏 分享一句喜欢的话&#xff1a;热烈的火焰&#xff0c;冰封在最沉默的火山深处 文章目录 前言浅谈进程概念1. 进程和操作系统的联系2.描述进程的对象——PCB …

如何调教让chatgpt读取自己的数据文件(保姆级图文教程)

提示&#xff1a;如何调教让chatgpt读取自己的数据文件(保姆级图文教程) 文章目录 前言一、如何投喂自己的数据&#xff1f;二、调教步骤总结 前言 chatgpt提示不能读取我们提供的数据文件&#xff0c;我们应该对它进行调教。 一、如何投喂自己的数据&#xff1f; 让chatgpt读…

通向架构师的道路之weblogic的集群与配置

一、Weblogic的集群 还记得我们在第五天教程中讲到的关于Tomcat的集群吗? 两个tomcat做node即tomcat1, tomcat2&#xff0c;使用Apache HttpServer做请求派发。 现在看看WebLogic的集群吧&#xff0c;其实也差不多。 区别在于&#xff1a; Tomcat的集群的实现为两个物理上…

网络安全渗透测试之靶场训练

NWES: 7月26号武汉地震检测中心遭受境外具有政府背景的黑客组织和不法分子的网络攻击。 目前网络攻击主要来自以下几种方式: DDOS&#xff1a;分布式拒绝服务攻击。通过制造大量无用的请求向目标服务器发起访问&#xff0c;使其因短时间内无法处理大量请求而陷入瘫痪。主要针对…

oracle容灾备份怎么样Oracle容灾备份

随着科学技术的发展和业务的增长&#xff0c;数据安全问题越来越突出。为了保证数据的完整性、易用性和保密性&#xff0c;公司需要采取一系列措施来防止内容丢失的风险。  Oracle是一个关系数据库管理系统(RDBMS),OracleCorporation是由美国软件公司开发和维护的。该系统功能…

【C语言题解】将一句话的单词进行倒置,标点不倒置。

题目描述&#xff1a;将一句话的单词进行倒置&#xff0c;标点不倒置。比如 “I like beijing.”&#xff0c;经过处理后变为&#xff1a;“beijing. like I”。 文章目录 原题目题目描述&#xff1a;输入描述&#xff1a;输出描述&#xff1a;题目链接&#xff1a; 整体思路分…

【数模】主成分分析PCA

主成分分析(Principal Component Analysis,PCA)&#xff0c;是一种降维算法&#xff0c;它能将多个指标转换为少数几个主成分&#xff0c;这些主成分是原始变量的线性组合&#xff0c;且彼此之间互不相关&#xff0c;其能反映出原始数据的大部分信息。使用场景&#xff1a;一般…

jupyter文档转换成markdown

背景 上一篇文章**《如何优雅地用python生成模拟数据》**我就使用jupyter写的&#xff0c;这个真的是万能的&#xff0c;可以插入markdown格式的内容&#xff0c;也可写代码&#xff0c;关键是像ipython一样&#xff0c;可以分步执行。 我可以这样自由的写我的博客内容&#x…

linux 安装go 1.18版本

首先去官网找到对应的版本 直接下载下来&#xff08;如果服务器可以直接访问到go 官网也可以wget直接下载到服务器&#xff09; 然后把该包上传到linux 的/usr/local 目录下 然后直接解压安装该包&#xff1a; sudo tar -C /usr/local -zxvf go1.18.10.linux-amd64.tar.gz 然…

设计模式行为型——观察者模式

目录 什么是观察者模式 观察者模式的实现 观察者模式角色 观察者模式类图 观察者模式举例 观察者模式代码实现 观察者模式的特点 优点 缺点 使用场景 注意事项 实际应用 什么是观察者模式 观察者模式&#xff08;Observer Pattern&#xff09;是一种行为型设计模式…

【工程优化问题】基于多种智能优化算法的压力容器设计问题研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

VMware16.2.5版本虚拟机克隆服务步骤(图解版)

目录 一、VMware16.2.5版本虚拟机克隆服务具体步骤二、VMware16.2.5版本虚拟机克隆服务后如何配置静态ip 一、VMware16.2.5版本虚拟机克隆服务具体步骤 1.1、先停止需要克隆的服务&#xff0c;选中需要克隆的服务——>鼠标右键选择【电源】——>【关闭客户机】&#xff…

【Linux升级之路】5_基础IO

&#x1f31f;hello&#xff0c;各位读者大大们你们好呀&#x1f31f; &#x1f36d;&#x1f36d;系列专栏&#xff1a;【Linux升级之路】 ✒️✒️本篇内容&#xff1a;文件操作&#xff0c;文件管理&#xff0c;重定向&#xff0c;简易shell添加重定向功能&#xff0c;文件属…

骑士牛(BFS)

题面 john用他的一头母牛和Don先生交换了一头“骑士牛”。这头牛有一个独特的能力——在牧场中能像中国象棋中的马一样跑跳&#xff08;会中国象棋吗&#xff1f;不会&#xff1f;注意&#xff1a;本题不考虑马被“蹩脚”的情况&#xff09;。 当然&#xff0c;这头牛不能跳到岩…

python接口自动化之正则用例参数化

前言 ​ 我们在做接口自动化的时候&#xff0c;处理接口依赖的相关数据时&#xff0c;通常会使用正则表达式来进行提取相关的数据。 ​ 正则表达式&#xff0c;又称正规表示式、正规表示法、正规表达式、规则表达式、常规表示法(Regular Expression&#xff0c;在代码中常简写…

【搜索框的匹配功能】

功能需求&#xff1a; 1. 输入关键字的同时&#xff0c;以下拉列表的形式显示匹配的内容&#xff1b; 2. 点击下拉列表的选项&#xff0c;跳转到对应的新的页面 注意&#xff1a;这里读取data.txt&#xff08;检索的文件对象&#xff09;&#xff0c;会存在跨域的问题&#x…

瞅一眼nginx

目录 &#x1f9ac;什么是nginx? &#x1f9ac;nginx配置官方yum源&#xff1a; &#x1f9ac;nginx优点 &#x1f9ac;nginx 缺点 &#x1f9ac;查看nginx默认模块 &#x1f40c;nginx新版本的配置文件&#xff1a; &#x1f40c;nginx目录索引 &#x1f40c;nginx状态…

【C++】开源:ceres和g2o非线性优化库配置使用

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍ceres和g2o非线性优化库配置使用。 无专精则不能成&#xff0c;无涉猎则不能通。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&…

IT 基础架构自动化

什么是 IT 基础架构自动化 IT 基础架构自动化是通过使用技术来控制和管理构成 IT 基础架构的软件、硬件、存储和其他网络组件来减少人为干预的过程&#xff0c;目标是构建高效、可靠的 IT 环境。 为什么要自动化 IT 基础架构 为客户和员工提供无缝的数字体验已成为企业的当务…