【Spring Cloud】OpenFeign之扫描FeignClient类信息

Spring Cloud - Openfeign 实现原理分析 OpenFeign 是一个声明式 RESTful 网络请求客户端。OpenFeign 会根据带有注解的函数信息构建出网络请求的模板,在发送网络请求之前,OpenFeign 会将函数的参数值设置到这些请求模板中。虽然 OpenFeign 只能支持基于文本的网络请求,但是它可以极大简化网络请求的实现,方便编程人员快速构建自己的网络请求应用。 阅读详情

FeignClientRegistrar 做的第二件事是扫描指定包下的类文件,注册 @FeignClient 注解修饰的接口类信息:

//FeignClientsRegistrar#registerDefaultConfiguration
public void registerFeignClients(AnnotationMetadata metadata,
			BeanDefinitionRegistry registry) {
    //生成自定义的ClassPathScanningCandidateComponentProvider
    ClassPathScanningCandidateComponentProvider scanner = getScanner();
    scanner.setResourceLoader(this.resourceLoader);

    Set<String> basePackages;

    //获取@EnableFeignClients所有属性的键值对
    Map<String, Object> attrs = metadata
        .getAnnotationAttributes(EnableFeignClients.class.getName());
    //使用@FeignClient作为类型进行过滤,即只扫描出被@FeignClient修饰的类
    AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(
        FeignClient.class);
    //如果@EnableFeignClients没有设置clients属性,那么需要扫描basePackages,所以使用AnnotationTypeFilter从basePackages中扫描
    final Class<?>[] clients = attrs == null ? null
        : (Class<?>[]) attrs.get("clients");
    if (clients == null || clients.length == 0) {
        //设置TypeFilter
        scanner.addIncludeFilter(annotationTypeFilter);
        //获取basePackages
        basePackages = getBasePackages(metadata);
    }
    else {
        //如果配置了clients属性,则从clients指定的类的路径下查找
        final Set<String> clientClasses = new HashSet<>();
        basePackages = new HashSet<>();
        for (Class<?> clazz : clients) {
            basePackages.add(ClassUtils.getPackageName(clazz));
            clientClasses.add(clazz.getCanonicalName());
        }
        AbstractClassTestingTypeFilter filter = new AbstractClassTestingTypeFilter() {
            @Override
            protected boolean match(ClassMetadata metadata) {
                String cleaned = metadata.getClassName().replaceAll("\\$", ".");
                return clientClasses.contains(cleaned);
            }
        };
        scanner.addIncludeFilter(
            new AllTypeFilter(Arrays.asList(filter, annotationTypeFilter)));
    }

    //扫描包路径,获取使用@FeignClient注解修饰的接口类
    for (String basePackage : basePackages) {
        Set<BeanDefinition> candidateComponents = scanner
            .findCandidateComponents(basePackage);
        for (BeanDefinition candidateComponent : candidateComponents) {
            if (candidateComponent instanceof AnnotatedBeanDefinition) {
                // verify annotated class is an interface
                AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
                AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
                Assert.isTrue(annotationMetadata.isInterface(),
                              "@FeignClient can only be specified on an interface");

                //获取@FeignClient注解的属性键值对
                Map<String, Object> attributes = annotationMetadata
                    .getAnnotationAttributes(
                    FeignClient.class.getCanonicalName());

                //获取client的名称
                String name = getClientName(attributes);
                //单独注册每个@FeignClient中的configuration配置类
                registerClientConfiguration(registry, name,
                                            attributes.get("configuration"));

                //注册@FeignClient的接口类的BeanDefinition
                registerFeignClient(registry, annotationMetadata, attributes);
            }
        }
    }
}

如上述代码所示, FeignClientsRegistrar 的 registerFeignClients 方法依据 @EnableFeignClients 的属性,通过getBasePackages获取要扫描的包路径信息,然后获取这些包下所有被 @FeignClient 注解修饰的接口类的 BeanDefinition, 最后调用 registerFeignClient 动态注册 BeanDefinition。

可以看下getBasePackages方法:

//FeignClientsRegistrar#getBasePackages
protected Set<String> getBasePackages(AnnotationMetadata importingClassMetadata) {
    Map<String, Object> attributes = importingClassMetadata
        .getAnnotationAttributes(EnableFeignClients.class.getCanonicalName());

    //获取values属性值
    Set<String> basePackages = new HashSet<>();
    for (String pkg : (String[]) attributes.get("value")) {
        if (StringUtils.hasText(pkg)) {
            basePackages.add(pkg);
        }
    }
    //获取basePackages属性值
    for (String pkg : (String[]) attributes.get("basePackages")) {
        if (StringUtils.hasText(pkg)) {
            basePackages.add(pkg);
        }
    }
    //获取basePackageClasses属性值
    for (Class<?> clazz : (Class[]) attributes.get("basePackageClasses")) {
        basePackages.add(ClassUtils.getPackageName(clazz));
    }

    //获取@EnableFeignClients注解修饰的类的全路径
    if (basePackages.isEmpty()) {
        basePackages.add(
            ClassUtils.getPackageName(importingClassMetadata.getClassName()));
    }
    return basePackages;
}

它根据 @EnableFeignClients 注解的value、basePackages、basePackageClasses属性来判断要扫描的路径,如果有则加入到backPackages属性中,如果没有则获取使用 @EnableFeignClients 注解修饰的类的全路径加入basePackages。

OpenFeign 使用 ClassPathScanningCandidateComponentProvider 和各类 TypeFilter 来过滤出被 @FeignClient 修饰的类,getScanner方法如下:

//FeignClientsRegistrar#getScanner
protected ClassPathScanningCandidateComponentProvider getScanner() {
    return new ClassPathScanningCandidateComponentProvider(false, this.environment) {
        @Override
        protected boolean isCandidateComponent(
            AnnotatedBeanDefinition beanDefinition) {
            boolean isCandidate = false;
            //判断beanDefinition是否为内部类
            if (beanDefinition.getMetadata().isIndependent()) {
                //判断是否为接口类,并且该接口不为Annotation类型,则返回true,否则返回false
                if (!beanDefinition.getMetadata().isAnnotation()) {
                    isCandidate = true;
                }
            }
            return isCandidate;
        }
    };
}

ClassPathScanningCandidateComponentProvider 的作用是遍历指定路径的包下的所有类。比如指定包路径为 aaa/bbb/ccc ,它会找出 aaa.bbb.ccc 包下所有的类,将所有的类封装成 Resource 接口集合。Resource 接口是 Spring 对资源的封装,有 FileSystemResource、 ClassPathResource、 UrlResource 等多种实现。 接着 ClassPathScanningCandidateComponentProvider 类会遍历 Resource 集合,通includeFilters 和 excludeFilters两种过滤器进行过滤操作。 includeFilters 和 excludeFilters是 TypeFilter 接口类型实例的集合,TypeFilter 是一个用于判断类型是否满足要求的类型过滤器。 excludeFilters 中只要有一个 TypeFilter 满足条件,那么这个 Resource 就会被过滤掉;而 includeFilters 中只要有一个 TypeFilter 满足条件,这个 Resource 就不会被过滤。 如果一个 Resource 没有被过滤,它会被转换成 ScannedGenericBeanDefinition 添加到 BeanDefinition 集合中。

//ClassPathScanningCandidateComponentProvider#scanCandidateComponents
static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";
private String resourcePattern = DEFAULT_RESOURCE_PATTERN;

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
    Set<BeanDefinition> candidates = new LinkedHashSet<>();
    try {
        //根据basePackages生成需要搜索的路径
        String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
            resolveBasePackage(basePackage) + '/' + this.resourcePattern;
        //将basePackages下所有的类封装成Resource类集合
        Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
        boolean traceEnabled = logger.isTraceEnabled();
        boolean debugEnabled = logger.isDebugEnabled();
        
        //遍历Resource
        for (Resource resource : resources) {
            if (traceEnabled) {
                logger.trace("Scanning " + resource);
            }
            if (resource.isReadable()) {
                try {
                    MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
                    //使用excludeFilters和includeFilters进行过滤
                    if (isCandidateComponent(metadataReader)) {
                        ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                        sbd.setSource(resource);
                        if (isCandidateComponent(sbd)) {
                            if (debugEnabled) {
                                logger.debug("Identified candidate component class: " + resource);
                            }
                            candidates.add(sbd);
                        }
                        else {
                            if (debugEnabled) {
                                logger.debug("Ignored because not a concrete top-level class: " + resource);
                            }
                        }
                    }
                    else {
                        if (traceEnabled) {
                            logger.trace("Ignored because not matching any filter: " + resource);
                        }
                    }
                }
                catch (Throwable ex) {
                    throw new BeanDefinitionStoreException(
                        "Failed to read candidate component class: " + resource, ex);
                }
            }
            else {
                if (traceEnabled) {
                    logger.trace("Ignored because not readable: " + resource);
                }
            }
        }
    }
    catch (IOException ex) {
        throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
    }
    return candidates;
}

通过调试可以看到扫描的路径是basePackages,如下图:
扫描路径

而通过路径扫描到的类有如下:

扫描类

根据图上看到,scanCandidateComponents方法会扫描路径下的所有类文件(*.class),不管是 Bean 实例,还是普通的 Java 类,都会被扫描到。

接着方法会遍历 Resource 集合, 并通过includeFilter 和 excludeFilter属性进行过滤,方法为isCandidateComponent:

//ClassPathScanningCandidateComponentProvider#isCandidateComponent
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
    //排除
    for (TypeFilter tf : this.excludeFilters) {
        if (tf.match(metadataReader, getMetadataReaderFactory())) {
            return false;
        }
    }
    //包括
    for (TypeFilter tf : this.includeFilters) {
        if (tf.match(metadataReader, getMetadataReaderFactory())) {
            return isConditionMatch(metadataReader);
        }
    }
    return false;
}

通过isCandidateComponent方法,会过滤出满足条件的配置类,由此会筛选出带有 @FeignClient 注解修饰的FeignClient 接口类。

for (String basePackage : basePackages) {
    //内部调用ClassPathScanningCandidateComponentProvider#scanCandidateComponents
    Set<BeanDefinition> candidateComponents = scanner
        .findCandidateComponents(basePackage);
    for (BeanDefinition candidateComponent : candidateComponents) {
        if (candidateComponent instanceof AnnotatedBeanDefinition) {
            // verify annotated class is an interface
            AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
            AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
            Assert.isTrue(annotationMetadata.isInterface(),
                          "@FeignClient can only be specified on an interface");

            //获取@FeignClient注解的属性键值对
            Map<String, Object> attributes = annotationMetadata
                .getAnnotationAttributes(
                FeignClient.class.getCanonicalName());

            //获取服务名
            String name = getClientName(attributes);
            //将@FeignClient上的configuration注册到服务名name上
            registerClientConfiguration(registry, name,
                                        attributes.get("configuration"));

            //注册FeignClient接口类
            registerFeignClient(registry, annotationMetadata, attributes);
        }
    }
}

循环遍历 BeanDefinition ,获取每个 FeignClient 接口类上的configuration属性,并进行注册。该注册方法同 @EnableFeignClients 注册默认配置类一样,都是调用同一个方法registerClientConfiguration,只不过此处会注册 @FeignClient 上的configuration对应的配置类,同样注册了一个类为 FeignClientSpecification 的 Bean 实例,Bean的name为xxx.FeignClientSpecification,而xxx为使用 @FeignClient 注解的接口类名称,可以根据 @FeignClient 注解的contextId、value、name、serviceId属性的其中一个获取。

接着调用registerFeignClient方法进行 FeignClient接口类对象的注册:

private void registerFeignClient(BeanDefinitionRegistry registry,
		AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
    String className = annotationMetadata.getClassName();
    //构建FeignClientFactoryBean类型的bean
    BeanDefinitionBuilder definition = BeanDefinitionBuilder
        .genericBeanDefinition(FeignClientFactoryBean.class);
    validate(attributes);
    definition.addPropertyValue("url", getUrl(attributes));
    definition.addPropertyValue("path", getPath(attributes));
    //依次顺序判断serviceId、name、value的值作为name
    String name = getName(attributes);
    definition.addPropertyValue("name", name);
    //如果配置了contextId属性,则使用contextId,否则使用name
    String contextId = getContextId(attributes);
    definition.addPropertyValue("contextId", contextId);
    definition.addPropertyValue("type", className);
    definition.addPropertyValue("decode404", attributes.get("decode404"));
    
    //熔断/断路器
    definition.addPropertyValue("fallback", attributes.get("fallback"));
    definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
    definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);

    //别名
    String alias = contextId + "FeignClient";
    AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();

    //默认为true
    boolean primary = (Boolean) attributes.get("primary"); // has a default, won't be
    // null

    beanDefinition.setPrimary(primary);

    String qualifier = getQualifier(attributes);
    if (StringUtils.hasText(qualifier)) {
        alias = qualifier;
    }

    BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,
                                                           new String[] { alias });
    //注册bean
    BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
}

registerFeignClient的功能就是解析 **@FeignClient **注解的属性,并对该 FeignClient 接口类进行注册,注册的 Bean 类型为 FeignClientFactoryBean,并依次将 **@FeignClient ** 属性设置到 FeignClientFactoryBean 实例中,用于后期实例的获取。

//BeanDefinitionReaderUtils#registerBeanDefinition
public static void registerBeanDefinition(
    BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
    throws BeanDefinitionStoreException {

    // Register bean definition under primary name.
    String beanName = definitionHolder.getBeanName();
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

    // Register aliases for bean name, if any.
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {
        for (String alias : aliases) {
            registry.registerAlias(beanName, alias);
        }
    }
}

微信公众号:Java知识集训

@EnableFeignClients注解报红的另类解决方案 @EnableFeignClients注解报红的解决方案 文章目录前言一、pom文件二、启动类问题解决 前言 两天,是的,没错,我被这个注解EnableFeignClients卡了两天,度娘都快翻烂了,最后的原因,你绝对想不到,特此记录一下。 首先来看下我这人畜无害的配置,是不是看起来一切正常?但是,就是启动类里面的那个EnableFeignClients一直报红,尝试了各种办法,未果。 一、pom文件 <?xml version="1.0" encoding="UTF-8"?> <p 阅读详情

相关推荐

Spring Cloud OpenFeign 工作原理解析

背景 OpenFeign 是 Spring Cloud 家族的一个成员, 它最核心的作用是为 HTTP 形式的 Rest API 提供了非常简洁高效的 RPC 调用方式。 如果说 Spring Cloud 其他成员解决的是系统级别的可用性,扩展性问题, 那么 OpenFeign 解决的则是与开发人员利益最为紧密的开发效率问题。 使用方式 在介绍 ...

萧萧的专栏 2万+

Spring Cloud OpenFeign源码解析

Spring Cloud OpenFeign源码解析 那么,功能如此强大的Spring Cloud OpenFeign,到底是如何实现上述的功能?本文通过源码解析,对上述功能逐一解释。

weixin_42524843的博客 816

Spring Cloud OpenFeign详解

作为Spring Cloud的子项目之一,Spring Cloud OpenFeign以将OpenFeign集成到Spring Boot应用中的方式,为微服务架构下服务之间的调用提供了解决方案。首先,利用了OpenFeign的声明式方式定义Web服务客户端;其次还更进一步,通过集成Ribbon或Eureka实现负载均衡的HTTP客户端。 Spring Cloud OpenFeign的最新版本是2...

成长的足迹 11万+

@EnableFeignClients详解

*** 扫描feignClient修饰的接口,配置在配置类上即可生效* 支持接口、类以及美剧/*** 扫描路径/*** 指定某个类的包为扫描路径*/ Class <?/*** 指定配置*/ Class <?/*** 指定某些类,优先*/ Class <?@EnableFeignClients导入了FeignClientsRegistrar类,FeignClientsRegistrar实现了ImportBeanDefinitionRegistrar,负责进行Feign的注入。

weixin_45845507的博客 1万+

手撸一个spring cloud openFeign

最近在看spring-cloud-openFeign的源码,为了帮助理解流程,手撸了一个基于github.feign的简化版的spring-cloud-openFeign,如果对feign工作原理不明白的,建议先看上一篇文章spring-cloud-openFeign源码深度解析 https://blog.youkuaiyun.com/sinat_29899265/article/details/865779...

Jagger的博客 453

Spring Cloud 源码分析之OpenFeign

OpenFeign是一个远程客户端请求代理,它的基本作用是让开发者能够以面向接口的方式来实现远程调用,从而屏蔽底层通信的复杂性,它的具体原理如下图所示。 在今天的内容中,我们需要详细分析OpenFeign它的工作原理及源码,我们继续回到这段代码。 @Slf4j @RestController @RequestMapping("/order") public class OrderController { @Autowired IGoodsServiceFeignClient go

wdjnb的博客 1228

【微服务笔记06】微服务组件之OpenFeign配置信息及RequestInterceptor请求拦截器

@EnableFeignClients 注解:启用OpenFeign组件,可以设置一个扫描路径,这样在启动工程的时候,OpenFeign就会扫描工程中指定的包路径下,所有包含【@FeignClient】的类,将其作为OpenFeign客户端。这个注解中含有下面几个属性:

✅ Java 开发工程师 4574

Spring cloud 中使用 OpenFeign:让 http 调用更优雅

Feign 是一个声明式的 Web service 客户端。它使编写 Web service 客户端更加容易。只需使用 Feign 创建一个Java 接口并对其进行注释就能发起远程 Http 调用。它支持可插拔的注解,包括 Feign 注解和 JAX-RS 注解。Feign 还支持可插拔式编码器和解码器来对请求体和响应体进行编解码。 本文详细介绍了如何在项目中使用 Spring Cloud OpenFeign。

Cloud-Future的博客 4240

Feign源码之@EnableFeignClients

注解属性 先看一下@EnableFeignClients有5个属性 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Import(FeignClientsRegistrar.class) public @interface EnableFeignClients { /** * Alias for the {@link #basePackages()} attribute. Allows for mo

Ethan_199402的博客 2397

Openfeign的实现原理

OpenFeign 是 Spring Cloud 家族的一个成员, 它最核心的作用是为 HTTP 形式的 Rest API 提供了非常简洁高效的 RPC 调用方式。 如果说 Spring Cloud 其他成员解决的是系统级别的可用性,扩展性问题, 那么 OpenFeign 解决的则是与开发人员利益最为紧密的开发效率问题。 完成 Feign 调用前所进行的操作: 添加依赖 <spring-cloud.version>Hoxton.SR9</spring-cloud.ve

gr5201314的博客 5281

云原生微服务 第六章 Spring Cloud中使用OpenFeign

OpenFeign 全称 Spring Cloud OpenFeign,它是 Spring 官方推出的一种声明式服务调用与负载均衡组件。我们可以像调用本地方法一样来调用远程服务,而完全感觉不到这是在进行远程调用。

Java 技术专栏,从入门到精通,熟悉企业级开发 6780

总结一下openfeign的用法:

总结一下openfeign的用法: 分为三步: 1:引包导入 2:在启动类上加注解,启用feign. 可以扫包带有@FeignClient的,及可以设置它的配置类; 3:写feign接口,可以配置下feign接口的调用规则。 第一步引包,我这里用的是okhttp. <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-clou.

hqw921054的博客 627

Maven的下载安装配置教程(详细图文)

目录 一、简单了解一下什么是Maven 二、maven的下载 三、maven的安装 四、maven的环境变量配置 五、setting文件配置 六、开发工具配置Maven 一、简单了解一下什么是Maven Maven就是一款帮助程序员构建项目的工具,我们只需要告诉Maven需要哪些Jar 包,它会帮助我们下载所有的Jar,极大提升开发效率。 1.Maven翻译为“专家“, ”内行”的意思,是著名Apache公司下基于Java开发的开源项目。 2.Maven项目对象模型(POM)是一..

bakelFF的博客 12万+

SpringCloud——OpenFeign 微服务远程调用组件使用教程

Spring Boot已经自动装配了Feign的配置,但是我们自己是可以修改或者自定义Feign的配置的,可以修改的配置如下:上面是我们最常用到的,当然也还有其他的,这里就不说了简单来说一下日志,日志一共分为四个级别NONE:没有任何日志,也是默认配置;BASIC:可以记录http请求什么时候发送,什么时候结束,耗时多久等基本信息;HEADERS:除了BASIC中含有的以外,还包含请求头和响应头;FULL:是最全面的,除了HEADERS中包含的以外,还包含请求体信息和响应体信息。

m0_70325779的博客 1万+

FPGA实战:SRIO接口数据流控制与回环测试详解

本文详细解析了FPGA中SRIO接口的数据流控制机制与回环测试实战。通过剖析SRIO IP核的AXI4-Stream接口握手时序(tvalid/tready/tlast),重点阐述了HELLO数据包格式与状态机设计,并提供了完整的Verilog代码示例。文章以回环测试为核心验证手段,指导开发者排查常见问题,为FPGA高速互连通信设计提供实用指南。

weixin_29173777的博客 427

PyTorch复现EEG-TCNet踩坑记:从BCI IV2a数据到TCN块缺失的完整解决方案

本文详细解析了使用PyTorch复现EEG-TCNet模型的全过程,重点解决了BCI IV2a数据集预处理和TCN模块缺失的技术难题。通过标准化数据流程、跨受试者验证策略以及三种因果卷积实现方案,为运动想象分类任务提供完整解决方案,帮助研究者高效实现模型复现与优化。

weixin_30699955的博客 319

Spring Cloud Alibaba——OpenFeign

OpenFeign是一个显示声明式的WebService客户端。使用OpenFeign能让编写Web Service客户端更加简单。使用时只需定义服务接口,然后在上面添加注解。OpenFeign也支持可拔插式的编码和解码器。对feign进行了封装,使其支持MVC注解和。和Eureka(服务注册中心)和Ribbon组合可以实现负载均衡。在中使用OpenFeign。

国家专精特新小巨人、资深消防行业企业、国家高新技术企业、智慧消防技术实验室、准独角兽企业、浙江省电流AI技术研发中心 1355

AD24层次原理图设计避坑指南:如何解决端口连接与自动交叉引用问题

本文深入解析AD24层次原理图设计的核心机制,聚焦端口连接错误、自动交叉引用干扰等常见问题。通过对比自上而下与自下而上设计流程,提供端口类型匹配、命名规范等实用解决方案,并指导如何关闭烦人的红色框线视觉干扰,帮助工程师高效避坑,实现复杂系统的模块化设计。

wdx01234567的博客 620

Spring Cloud OpenFeign 核心原理

Spring Cloud OpenFeign 核心原理

weixin_46619605的博客 1212

论文理解【LLM-Clarification】—— 【QDrawer】Asking the Right Question at the Right Time: Human and Model Unce

本文基于 CoDraw 任务对 LLM 澄清提问的触发方式进行探索,发现模型内部不确定性与人类澄清决策相关性弱,使用不确定性阈值触发澄清提问相比模仿人类提问时机,性能和计算效率都更好

佚失的诗篇 770

直击高频编程考点:字符串知识及经典算法题总结

字符串相关基本练习题总结(最长公共子串、最长回文子串、最长无重复字符子串、最小覆盖子串、字符串相乘、中文数字表达转实际数字格式等)

曾经“等你生日那天”都遥远得像未来,如今却可欢愉的挥手说“下个十年见” 172万+

【源码】spring cloud openfeign负载均衡分析之FeignBlockingLoadBalancerClient

spring cloud openfeign负载均衡分析之FeignBlockingLoadBalancerClient

万物皆字节 896

基于 YOLOv26 的遥感图像目标检测系统:从原理到模型

本文介绍了基于YOLOv26的遥感图像目标检测系统。YOLOv26凭借端到端设计、轻量化架构和小目标优化能力,有效解决了遥感图像中多尺度目标、复杂背景、小目标检测等挑战。系统采用CSPDarknet骨干网络和FPN+PAN特征融合模块,通过MuSGD优化器和改进损失函数提升训练效果。文章详细阐述了数据预处理、模型训练流程和优化技巧,包括Tile推理和混合精度训练。系统支持多种部署方式,在CPU上推理速度提升43%,能实现高精度、实时性的遥感目标检测,适用于城市规划、农业监测等场景。

一键难忘的博客 569

Spring Cloud OpenFeign 原理

Spring Cloud OpenFeign

杨宇昌的博客 1402

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

上一篇: 【Spring Cloud】OpenFeign之@EnableFeignClients(1)注册默认配置
下一篇: 【Spring Cloud】OpenFeign之自动配置类FeignAutoConfiguration
caychen
博客等级 码龄9年 110粉丝 113原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值