Java 代码重试实现方式

news2024/12/29 14:44:43

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 {
    @Override
    public 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 {

    @Autowired
    private LearnServiceImpl learnService;

    private static final int RETRY_TIMES = 3;

    @Override
    public 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 {

    @Autowired
    LearnServiceProxyImpl learnServiceProxy;

    @Test
    public 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;
    }

    @Override
    public 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 {

    @Autowired
    LearnServiceImpl learnService;

    @Test
    public 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;

    @Override
    public 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 {

    @Autowired
    LearnServiceImpl learnService;

    @Test
    public 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 {

    @Autowired
    LearnRetry learnRetry;

    @Test
    public 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
     */
    @Recover
    public 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 {


    @Autowired
    SpringRetry springRetry;

    @Test
    public 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();
    }

    @Test
    public 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 {

    @Autowired
    GuavaRetry guavaRetry;

    @Test
    public 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() {
                    @Override
                    public <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.coloradmin.cn/o/851698.html

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

相关文章

固态硬盘接口对比

固态硬盘接口对比 M.2接口固态硬盘固态硬盘接口固态硬盘尺寸接口兼容性 M.2接口 M.2接口&#xff0c;也称为NGFF&#xff08;Next Generation Form Factor&#xff09;&#xff0c;是一种计算机拓展接口规范。常见的M.2接口有A key、B key、E key和M key&#xff0c;不同的key…

书单背景怎么制作?分享一个实用的工具

在今天的信息时代&#xff0c;越来越多的人通过阅读来丰富自己的知识和技能。为了方便大家查找阅读材料&#xff0c;书单背景的制作变得越来越重要。本文将介绍书单背景的制作方法以及需要注意的问题。 书单背景的制作方法 1. 使用在线制作工具 在线制作工具如Canva提供了许多…

比较研发项目管理系统:哪个更适合您的需求?

项目管理系统对于保持项目进度、提高效率和确保质量至关重要。然而&#xff0c;市场上众多的研发项目管理系统让许多团队陷入选择困难。本文将对几个主流的研发项目管理系统进行深入分析&#xff0c;以帮助您找到最适合您团队的解决方案。 “哪个研发项目管理系统好用好&#x…

【MySQL】检索数据使用数据处理函数

函数 与其他大多数计算机语言一样&#xff0c;SQL支持利用函数来处理数据。函数一般是在数据上执行的&#xff0c;它给数据的转换和处理提供了方便。 函数没有SQL的可移植性强&#xff1a;能运行在多个系统上的代码称为可移植的。多数SQL语句是可移植的&#xff0c;而函数的可…

【Archaius技术专题】「Netflix原生态」动态化配置服务之微服务配置组件变色龙

前提介绍 如果要设计开发一套微服务基础架构&#xff0c;参数化配置是一个非常重要的点&#xff0c;而Netflix也开源了一个叫变色龙Archaius的配置中心客户端&#xff0c;而且Archaius可以说是比其他客户端具备更多生产级特性&#xff0c;也更灵活。*在NetflixOSS微服务技术栈…

CSS 的选择器有哪些种类?分别如何使用?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 元素选择器&#xff08;Element Selector&#xff09;⭐ 类选择器&#xff08;Class Selector&#xff09;⭐ ID 选择器&#xff08;ID Selector&#xff09;⭐ 后代选择器&#xff08;Descendant Selector&#xff09;⭐ 子元素选择器&a…

本地开发 npm 好用的http server、好用的web server、静态服务器

好用的web server总结 有时需要快速启动一个web 服务器&#xff08;http服务器&#xff09;来伺服静态网页&#xff0c;安装nginx又太繁琐&#xff0c;那么可以考虑使用npm serve、http-server、webpack-dev-server。 npm serve npm 的serve可以提供给http server功能&#…

外贸行业三大客户管理软件的特点?

外贸企业在开拓国际市场的过程中&#xff0c;经常会遇到客户信息混乱、销售流程复杂、市场竞争激烈等痛点。因此&#xff0c;外贸企业急需一款CRM系统来帮助他们管理客户信息、跟进销售机会等。这里有一份外贸客户管理软件排名&#xff0c;希望对您有所帮助。 Zoho CRM Zoho …

Nacos基本应用

Nacos 基本应用 Nacos 提供了 SDK 和 OpenAPI 方式来完成服务注册与发现等操作&#xff0c;SDK 实际上是对于 http 请求的封装。 微服务架构的电子商务平台&#xff0c;其中包含订单服务、商品服务和用户服务。可以使用 Nacos 作为服务注册和发现的中心&#xff0c;以便各个微…

aijs 盒子出血

效果演示 盒子出血演示 1.左下点 2.左上点 3.上左点 var doc activeDocument; var pt 72 / 25.4; var cx 3 * pt;var marks []; for (var i 0; i < doc.selection.length; i) {var shape doc.selection[i];if (shape.typename GroupItem && shape.pageItems.…

2023年深度学习最新研究成果

LLMs领域 AGI领域 无剑芯片设计平台 三级标题 四级标题 五级标题 六级标题

使用fopen等标准C库来操作文件

fopen 需要的头文件&#xff1a; #include <stdio.h> 函数原型&#xff1a; FILE *fopen(const char *pathname, const char *mode); 参数&#xff1a; pathname: 文件路径mode: “r” &#xff1a;以只读方式打开文件&#xff0c;该文件必须存在。“w” &#xff…

省电模式稳定电压显示IC32×4 LCD显示驱动芯片

简述 VK1C21A是一个点阵式存储映射的LCD驱动器&#xff0c;可支持最大128点&#xff08;32SEGx4COM&#xff09; 的LCD屏&#xff0c;也支持2COM和3COM的LCD屏。单片机可通过3/4个通信脚配置显示参数和发 送显示数据&#xff0c;也可通过指令进入省电模式。具备高抗干扰&a…

攻防演练的开局之战,泛资产暴露面检测

原文地址 全国信息安全攻防演练&#xff0c;已经蓄势待发。在网络安全的棋盘上&#xff0c;新型攻击手段不断涌现&#xff0c;不仅影子资产成为攻击的目标&#xff0c;邮件钓鱼、代码和配置文件泄露&#xff0c;甚至关联的供应链公司的安全缺陷都可能成为攻击者钻营的突破口。因…

AirServer2023最新Mac苹果电脑系统投屏软件

AirServer是一个Mac专用投屏工具&#xff0c;功能强大&#xff0c;并且可以通过网络和其他平台同步视频内容。可以使用多个设备进行投屏&#xff0c;快速查看同一局域网内的视频。支持的设备&#xff1a;苹果系统。支持 Windows、 Mac、 Android、 iOS、 windows平台。通过这款…

Simulink仿真模块 - Compare To Zero

Compare To Zero:确定信号与零的比较方式 库:Simulink / Logic and Bit Operations HDL Coder / Logic and Bit Operations 模型为: 双击模型打开参数设置界面为: 说明 Compare To Zero 模块将输入信号与零进行比较。使用 Operator 参数指定输入与零的比较方式。 …

python免费下载安装教程,python编程软件 免安装

本篇文章给大家谈谈python免费下载安装教程&#xff0c;以及python编程软件 免安装&#xff0c;希望对各位有所帮助&#xff0c;不要忘了收藏本站喔。 百度网盘 请输入提取码 提取码: wifx 下载好记得把python文件解压&#xff0c;里面有32位和64位的&#xff0c;根据自己配置…

界面控件DevExpress WPF Chart组件——拥有超快的数据可视化库!

DevExpress WPF Chart组件拥有超大的可视化数据集&#xff0c;并提供交互式仪表板与高性能WPF图表库。DevExpress Charts提供了全面的2D / 3D图形集合&#xff0c;包括数十个UI定制和数据分析/数据挖掘选项。 PS&#xff1a;DevExpress WPF拥有120个控件和库&#xff0c;将帮助…

基于PHP的轻量级博客typecho

本文完成于 5 月中旬&#xff0c;发布时未在最新版本上验证&#xff1b; 什么是 typecho &#xff1f; Typecho 是一款基于 PHP 的博客软件&#xff0c;旨在成为世界上最强大的博客引擎。Typecho 在 GNU 通用公共许可证 2.0 下发布。支持多种数据库&#xff0c;原生支持 Markdo…

何时构建你的护城河?不确定性、成功和防御性

原文&#xff1a;www.notboring.co/p/when-to-dig-a-moat shadow 本文相当有启发性&#xff0c;我做了关键内容的整理&#xff0c;分享给大家&#xff1a; 不确定性、成功和防御性 Uncertainty Success Defensibility 有一种观点&#xff1a;如果你拥有最有才华的团队、最好的产…