SpringBoot自动装配原理分析

论文阅读------Exposure Fusion: A Simple and Practical Alternative to High Dynamic Range Photography Mertens T, Kautz J, Van Reeth F. Exposure fusion: A simple and practical alternative to high dynamic range photography[C]//Computer graphics forum. Oxford, UK: Blackwell Publishing Ltd, 2009, 28(1): 161-171. 摘要 本文提出了一种将包围曝光的序列融合到高质量图像中的技术,而无需先转换为高动态范围(HD. 阅读详情

SpringBoot自动装配原理分析

一、SPI源码分析

为什么要讲SPI呢?因为在SpringBoot的自动装配中其实有使用到SPI机制,所以掌握了这部分对于SpringBoot的学习还是很有帮助的。

SPI ,全称为 Service Provider Interface,是一种服务发现机制。它通过在ClassPath路径下的 META-INF/services 文件夹查找文件,自动加载文件里所定义的类。这一机制为很多框架扩展提供了可能,比如在Dubbo、JDBC中都使用到了SPI机制。我们先通过一个很简单的例子来看下它是怎么用的。

案例介绍

先定义接口项目

image.png

然后创建一个扩展的实现,先导入上面接口项目的依赖

    <dependencies>
        <dependency>
            <groupId>com.bobo</groupId>
            <artifactId>JavaSPIBase</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

然后创建接口的实现

/**
 * SPI:MySQL对于 baseURL 的一种实现
 */
public class MySQLData implements BaseData {
    @Override
    public void baseURL() {
        System.out.println("mysql 的扩展实现....");
    }
}

然后在resources目录下创建 META-INF/services 目录,然后在目录中创建一个文件,名称必须是定义的接口的全类路径名称。然后在文件中写上接口的实现类的全类路径名称。

image.png

同样的再创建一个案例

image.png

然后在测试的项目中测试

    public static void main(String[] args) {
        ServiceLoader<BaseData> providers = ServiceLoader.load(BaseData.class);
        Iterator<BaseData> iterator = providers.iterator();
        while(iterator.hasNext()){
            BaseData next = iterator.next();
            next.baseURL();
        }
    }

根据不同的导入,执行的逻辑会有不同

image.png

image.png

源码查看

ServiceLoader

首先来看下ServiceLoader的类结构

   // 配置文件的路径
    private static final String PREFIX = "META-INF/services/";

    // 加载的服务  类或者接口
    private final Class<S> service;

    // 类加载器
    private final ClassLoader loader;

    // 访问权限的上下文对象
    private final AccessControlContext acc;

    // 保存已经加载的服务类
    private LinkedHashMap<String,S> providers = new LinkedHashMap<>();

    // 内部类,真正加载服务类
    private LazyIterator lookupIterator;

load

load方法创建了一些属性,重要的是实例化了内部类,LazyIterator。

public final class ServiceLoader<S> implements Iterable<S>
    private ServiceLoader(Class<S> svc, ClassLoader cl) {
        //要加载的接口
        service = Objects.requireNonNull(svc, "Service interface cannot be null");
        //类加载器
        loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
        //访问控制器
        acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
         reload();
        
    }
    public void reload() {
        //先清空
        providers.clear();
        //实例化内部类 
        LazyIterator lookupIterator = new LazyIterator(service, loader);
    }
}

查找实现类和创建实现类的过程,都在LazyIterator完成。当我们调用iterator.hasNext和iterator.next方法的时候,实际上调用的都是LazyIterator的相应方法。

private class LazyIterator implements Iterator<S>{
    Class<S> service;
    ClassLoader loader;
    Enumeration<URL> configs = null;
    Iterator<String> pending = null;
    String nextName = null; 
    private boolean hasNextService() {
        //第二次调用的时候,已经解析完成了,直接返回
        if (nextName != null) {
            return true;
        }
        if (configs == null) {
            //META-INF/services/ 加上接口的全限定类名,就是文件服务类的文件
            //META-INF/services/com.viewscenes.netsupervisor.spi.SPIService
            String fullName = PREFIX + service.getName();
            //将文件路径转成URL对象
            configs = loader.getResources(fullName);
        }
        while ((pending == null) || !pending.hasNext()) {
            //解析URL文件对象,读取内容,最后返回
            pending = parse(service, configs.nextElement());
        }
        //拿到第一个实现类的类名
        nextName = pending.next();
        return true;
    }
}

创建实例对象,当然,调用next方法的时候,实际调用到的是,lookupIterator.nextService。它通过反射的方式,创建实现类的实例并返回。

private class LazyIterator implements Iterator<S>{
    private S nextService() {
        //全限定类名
        String cn = nextName;
        nextName = null;
        //创建类的Class对象
        Class<?> c = Class.forName(cn, false, loader);
        //通过newInstance实例化
        S p = service.cast(c.newInstance());
        //放入集合,返回实例
        providers.put(cn, p);
        return p; 
    }
}

看到这儿,我想已经很清楚了。获取到类的实例,我们自然就可以对它为所欲为了!

二、自动装配源码分析

在前面的分析中,Spring Framework一直在致力于解决一个问题,就是如何让bean的管理变得更简单,如何让开发者尽可能的少关注一些基础化的bean的配置,从而实现自动装配。所以,所谓的自动装配,实际上就是如何自动将bean装载到Ioc容器中来。

实际上在spring 3.x版本中,Enable模块驱动注解的出现,已经有了一定的自动装配的雏形,而真正能够实现这一机制,还是在spirng 4.x版本中,conditional条件注解的出现。ok,我们来看一下spring boot的自动装配是怎么一回事。

自动装配的演示

 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency> 
spring:
    redis:
      host: 127.0.0.1 
      port: 6379
 @Autowired
    private RedisTemplate<String,String>redisTemplate;

按照下面的顺序添加starter,然后添加配置,使用RedisTemplate就可以使用了? 那大家想没想过一个问题,为什么RedisTemplate可以被直接注入?它是什么时候加入到Ioc容器的呢? 这就是自动装配。自动装配可以使得classpath下依赖的包相关的bean,被自动装载到Spring Ioc容器中,怎么做到的呢?

深入分析EnableAutoConfiguration

EnableAutoConfiguration的主要作用其实就是帮助springboot应用把所有符合条件的@Configuration配置都加载到当前SpringBoot创建并使用的IoC容器中。

再回到EnableAutoConfiguration这个注解中,我们发现它的import是这样

@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

但是从EnableAutoCOnfiguration上面的import注解来看,这里面并不是引入另外一个Configuration。而是一个ImportSelector。这个是什么东西呢?

AutoConfigurationImportSelector是什么?

Enable注解不仅仅可以像前面演示的案例一样很简单的实现多个Configuration的整合,还可以实现一些复杂的场景,比如可以根据上下文来激活不同类型的bean,@Import注解可以配置三种不同的class

  1. 第一种就是前面演示过的,基于普通bean或者带有@Configuration的bean进行诸如
  2. 实现ImportSelector接口进行动态注入

实现ImportBeanDefinitionRegistrar接口进行动态注入

CacheService

public class CacheService {
}

LoggerService

public class LoggerService {
}

EnableDefineService

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented 
@Inherited  --允许被继承
@Import({MyDefineImportSelector.class})
public @interface EnableDefineService {

    String[] packages() default "";
}

MyDefineImportSelector

public class MyDefineImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        //获得指定注解的详细信息。我们可以根据注解中配置的属性来返回不同的class,
        //从而可以达到动态开启不同功能的目的
    
annotationMetadata.getAllAnnotationAttributes(EnableDefineService.class.getName(),true)
            .forEach((k,v) -> {
                log.info(annotationMetadata.getClassName());
                log.info("k:{},v:{}",k,String.valueOf(v));
            });
        return new String[]{CacheService.class.getName()};
    }
}

EnableDemoTest

@SpringBootApplication
@EnableDefineService(name = "mashibing",value = "mashibing")
public class EnableDemoTest {
    public static void main(String[] args) {
        ConfigurableApplicationContext ca=SpringApplication.run(EnableDemoTest.class,args);
        System.out.println(ca.getBean(CacheService.class));
        System.out.println(ca.getBean(LoggerService.class));
    }
}

了解了selector的基本原理之后,后续再去分析AutoConfigurationImportSelector的原理就很简单了,它本质上也是对于bean的动态加载。

@EnableAutoConfiguration注解的实现原理

了解了ImportSelector和ImportBeanDefinitionRegistrar后,对于EnableAutoConfiguration的理解就容易一些了

它会通过import导入第三方提供的bean的配置类:AutoConfigurationImportSelector

@Import(AutoConfigurationImportSelector.class)

从名字来看,可以猜到它是基于ImportSelector来实现基于动态bean的加载功能。之前我们讲过Springboot @Enable*注解的工作原理ImportSelector接口selectImports返回的数组(类的全类名)都会被纳入到spring容器中。

那么可以猜想到这里的实现原理也一定是一样的,定位到AutoConfigurationImportSelector这个类中的selectImports方法

selectImports

public String[] selectImports(AnnotationMetadata annotationMetadata) {
   if (!isEnabled(annotationMetadata)) {
      return NO_IMPORTS;
   }
// 从配置文件(spring-autoconfigure-metadata.properties)中加载 AutoConfigurationMetadata
   AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
         .loadMetadata(this.beanClassLoader);
// 获取所有候选配置类EnableAutoConfiguration
   AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(
         autoConfigurationMetadata, annotationMetadata);
   return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}

getAutoConfigurationEntry

protected AutoConfigurationEntry getAutoConfigurationEntry(
      AutoConfigurationMetadata autoConfigurationMetadata,
      AnnotationMetadata annotationMetadata) {
   if (!isEnabled(annotationMetadata)) {
      return EMPTY_ENTRY;
   }
//获取元注解中的属性
   AnnotationAttributes attributes = getAttributes(annotationMetadata);
//使用SpringFactoriesLoader 加载classpath路径下META-INF\spring.factories中,
//key= org.springframework.boot.autoconfigure.EnableAutoConfiguration对应的value
   List<String> configurations = getCandidateConfigurations(annotationMetadata,
         attributes);
//去重
   configurations = removeDuplicates(configurations);
//应用exclusion属性
   Set<String> exclusions = getExclusions(annotationMetadata, attributes);
   checkExcludedClasses(configurations, exclusions);
   configurations.removeAll(exclusions);
//过滤,检查候选配置类上的注解@ConditionalOnClass,如果要求的类不存在,则这个候选类会被过滤不被加载
   configurations = filter(configurations, autoConfigurationMetadata);
   //广播事件
fireAutoConfigurationImportEvents(configurations, exclusions);
   return new AutoConfigurationEntry(configurations, exclusions);
}

本质上来说,其实EnableAutoConfiguration会帮助springboot应用把所有符合@Configuration配置都加载到当前SpringBoot创建的IoC容器,而这里面借助了Spring框架提供的一个工具类SpringFactoriesLoader的支持。以及用到了Spring提供的条件注解@Conditional,选择性的针对需要加载的bean进行条件过滤

SpringFactoriesLoader

为了给大家补一下基础,我在这里简单分析一下SpringFactoriesLoader这个工具类的使用。它其实和java中的SPI机制的原理是一样的,不过它比SPI更好的点在于不会一次性加载所有的类,而是根据key进行加载。

首先,SpringFactoriesLoader的作用是从classpath/META-INF/spring.factories文件中,根据key来加载对应的类到spring IoC容器中。接下来带大家实践一下

创建外部项目jar

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>4.3.13.RELEASE</version>
</dependency>

创建bean以及config

public class mashibingCore {
    public String study(){
        System.out.println("good good study, day day up");
        return "mashibingEdu.com";
    }
}
@Configuration
public class mashibingConfig {
    @Bean
    public mashibingCore mashibingCore(){
        return new mashibingCore();
    }
}

创建另外一个工程(spring-boot)

把前面的工程打包成jar,当前项目依赖该jar包

<dependency>
    <groupId>com.mashibingedu.practice</groupId>
    <artifactId>mashibing-Core</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

通过下面代码获取依赖包中的属性

运行结果会报错,原因是mashibingCore并没有被Spring的IoC容器所加载,也就是没有被EnableAutoConfiguration导入

@SpringBootApplication
public class SpringBootStudyApplication {
    public static void main(String[] args) throws IOException {
        ConfigurableApplicationContext ac=SpringApplication.run(SpringBootStudyApplication.class, args);
        mashibingCore Myc=ac.getBean(mashibingCore.class);
        System.out.println(Myc.study());
    }
}

解决方案

在mashibing-Core项目resources下新建文件夹META-INF,在文件夹下面新建spring.factories文件,文件中配置,key为自定配置类EnableAutoConfiguration的全路径,value是配置类的全路径

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.mashibingedu.practice.mashibingConfig

重新打包,重新运行SpringBootStudyApplication这个类。

可以发现,我们编写的那个类,就被加载进来了。

Spring Boot中的条件过滤

在分析AutoConfigurationImportSelector的源码时,会先扫描spring-autoconfiguration-metadata.properties文件,最后在扫描spring.factories对应的类时,会结合前面的元数据进行过滤,为什么要过滤呢? 原因是很多的@Configuration其实是依托于其他的框架来加载的,如果当前的classpath环境下没有相关联的依赖,则意味着这些类没必要进行加载,所以,通过这种条件过滤可以有效的减少@configuration类的数量从而降低SpringBoot的启动时间。

修改mashibing-Core

在META-INF/增加配置文件,spring-autoconfigure-metadata.properties。

com.mashibingedu.practice.mashibingConfig.ConditionalOnClass=com.mashibingedu.TestClass

格式:自动配置的类全名.条件=值

上面这段代码的意思就是,如果当前的classpath下存在TestClass,则会对mashibingConfig这个Configuration进行加载

演示过程(spring-boot)

  1. 沿用前面spring-boot工程的测试案例,直接运行main方法,发现原本能够被加载的mashibingCore,发现在ioc容器中找不到了。

    public static void main(String[] args) throws IOException {
        ConfigurableApplicationContext ac=SpringApplication.run(SpringBootStudyApplication.class, args);
        mashibingCore Myc=ac.getBean(mashibingCore.class);
        System.out.println(Myc.study());
    }
    
  2. 在当前工程中指定的包com.mashibingedu下创建一个TestClass以后,再运行上面这段代码,程序能够正常执行

三、手写Starter

我们通过手写Starter来加深对于自动装配的理解

1.创建一个Maven项目,quick-starter

定义相关的依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
    <version>2.1.6.RELEASE</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.56</version>
    <!-- 可选 -->
    <optional>true</optional>
</dependency>

2.定义Formate接口

定义的格式转换的接口,并且定义两个实现类

public interface FormatProcessor {
    /**
     * 定义一个格式化的方法
     * @param obj
     * @param <T>
     * @return
     */
    <T> String formate(T obj);
}

public class JsonFormatProcessor implements FormatProcessor {
    @Override
    public <T> String formate(T obj) {
        return "JsonFormatProcessor:" + JSON.toJSONString(obj);
    }
}
public class StringFormatProcessor implements FormatProcessor {
    @Override
    public <T> String formate(T obj) {
        return "StringFormatProcessor:" + obj.toString();
    }
}

3.定义相关的配置类

首先定义格式化加载的Java配置类

@Configuration
public class FormatAutoConfiguration {

    @ConditionalOnMissingClass("com.alibaba.fastjson.JSON")
    @Bean
    @Primary // 优先加载
    public FormatProcessor stringFormatProcessor(){
        return new StringFormatProcessor();
    }

    @ConditionalOnClass(name="com.alibaba.fastjson.JSON")
    @Bean
    public FormatProcessor jsonFormatProcessor(){
        return new JsonFormatProcessor();
    }
}

定义一个模板工具类

public class HelloFormatTemplate {

    private FormatProcessor formatProcessor;


    public HelloFormatTemplate(FormatProcessor processor){
        this.formatProcessor = processor;
    }

    public <T> String doFormat(T obj){
        StringBuilder builder = new StringBuilder();
        builder.append("Execute format : ").append("<br>");
        builder.append("Object format result:" ).append(formatProcessor.formate(obj));
        return builder.toString();
    }
}

再就是整合到SpringBoot中去的Java配置类

@Configuration
@Import(FormatAutoConfiguration.class)
public class HelloAutoConfiguration {

    @Bean
    public HelloFormatTemplate helloFormatTemplate(FormatProcessor formatProcessor){
        return new HelloFormatTemplate(formatProcessor);
    }
}

4.创建spring.factories文件

在resources下创建META-INF目录,再在其下创建spring.factories文件

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  org.mashibingedu.autoconfiguration.HelloAutoConfiguration

install 打包,然后就可以在SpringBoot项目中依赖改项目来操作了。

5.测试

在SpringBoot中引入依赖

<dependency>
    <groupId>org.example</groupId>
    <artifactId>format-spring-boot-starter</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

在controller中使用

@RestController
public class UserController {

    @Autowired
    private HelloFormatTemplate helloFormatTemplate;

    @GetMapping("/format")
    public String format(){
        User user = new User();
        user.setName("BoBo");
        user.setAge(18);
        return helloFormatTemplate.doFormat(user);
    }
}

6.自定义Starter关联配置信息

有些情况下我们可以需要用户在使用的时候动态的传递相关的配置信息,比如Redis的Ip,端口等等,这些信息显然是不能直接写到代码中的,这时我们就可以通过SpringBoot的配置类来实现。

首先引入依赖支持

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <version>2.2.6.RELEASE</version>
    <optional>true</optional>
</dependency>

然后创建对应的属性类

@ConfigurationProperties(prefix = HelloProperties.HELLO_FORMAT_PREFIX)
public class HelloProperties {

    public static final String HELLO_FORMAT_PREFIX="mashibing.hello.format";

    private String name;

    private Integer age;

    private Map<String,Object> info;

    public Map<String, Object> getInfo() {
        return info;
    }

    public void setInfo(Map<String, Object> info) {
        this.info = info;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

然后再Java配置类中关联

@Configuration
@Import(FormatAutoConfiguration.class)
@EnableConfigurationProperties(HelloProperties.class)
public class HelloAutoConfiguration {

    @Bean
    public HelloFormatTemplate helloFormatTemplate(HelloProperties helloProperties,FormatProcessor formatProcessor){
        return new HelloFormatTemplate(helloProperties,formatProcessor);
    }
}

调整模板方法

public class HelloFormatTemplate {

    private FormatProcessor formatProcessor;

    private HelloProperties helloProperties;

    public HelloFormatTemplate(HelloProperties helloProperties,FormatProcessor processor){
        this.helloProperties = helloProperties;
        this.formatProcessor = processor;
    }

    public <T> String doFormat(T obj){
        StringBuilder builder = new StringBuilder();
        builder.append("Execute format : ").append("<br>");
        builder.append("HelloProperties:").append(formatProcessor.formate(helloProperties.getInfo())).append("<br>");
        builder.append("Object format result:" ).append(formatProcessor.formate(obj));
        return builder.toString();
    }
}

增加提示

在这个工程的META-INF/下创建一个additional-spring-configuration-metadata.json,这个是设置属性的提示类型

{
  "properties": [
    {
      "name": "mashibing.hello.format.name",
      "type": "java.lang.String",
      "description": "账号信息",
      "defaultValue": "root"
    },{
      "name": "mashibing.hello.format.age",
      "type": "java.lang.Integer",
      "description": "年龄",
      "defaultValue": 18
    }
  ]
}
	protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
        // 加载当前系统下 META-INF/spring.factories 文件中声明的配置类
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
        // 移除掉重复的
		configurations = removeDuplicates(configurations);
        // 移除掉显示排除的
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
        // 过滤掉不需要载入的配置类
		configurations = getConfigurationClassFilter().filter(configurations);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}
利用ArcGIS的模型构建器实现批量投影栅格和批量克里金插值 博主要批量投影几百个栅格,但是ArcGIS中的投影栅格的批处理工具需要手动一条条设置参数,还是麻烦,因此学习了使用模型构建器(ModelBuilder)来批量投影栅格,可以导入需投影栅格的文件夹,然后迭代投影,并按栅格原名逐个输出到指定目录。 1.在工具箱里构建模型 在arctool box里右键点击空白处,选择【添加工具箱】,点击ArcGIS默认工作目录的工具箱进行添加,然后Toolbox就会被添加到ArcToolbox页面,右键点击Toolbox,选择“新建”-“模型” 2.编写模型 (1). 阅读详情

相关推荐

SAP移动类型

SAP移动类型移动类型定义 移动类型定义

qq_20593197的博客 6201

深入探究Spring Boot自动配置原理及SPI机制:实现灵活的插件化开发

在传统的Spring应用程序中,我们需要手动配置各种组件、依赖和属性,以满足应用程序的需求。这通常涉及编写大量的XML配置文件或Java配置类,并进行复杂的依赖注入和组件装配。这种手动配置过程可能非常繁琐且容易出错。而Spring Boot的自动配置机制通过约定大于配置的原则,基于应用程序的依赖和配置信息,自动推断和配置应用程序所需的各种组件。它通过提供默认的配置和装配规则,减少了我们的工作量,使得我们可以更专注于业务逻辑的开发。接下来就讲解一下自动配置的原理实现。

Apple_Boy的博客 1228

HFSS仿真中如何提取最大E/H场强与频率关系曲线

本文详细讲解了在HFSS仿真中提取最大E/H场强与频率关系曲线的完整流程。通过使用场计算器(Field Calculator)和创建场报告,工程师可以准确获得器件在整个频带内的电场或磁场强度峰值,并进一步推导出关键的功率容量曲线,为高功率射频器件(如滤波器、耦合器)的设计提供至关重要的安全评估依据。

ss78901的博客 1098

Springboot中SPI机制及自动装配

SpringBoot 自动装配原理

ChengXuYuanH__的博客 2327

PADS Layout中快速导入自定义元器件封装的实用技巧

本文详细介绍了在PADS Layout中高效导入自定义元器件封装的实用技巧。针对封装“找不到”、“对不上”、“导不进”三大痛点,系统梳理了从封装文件来源识别、库规划管理,到三种核心导入场景(从库文件添加、从其他设计借用、处理第三方格式)的完整操作流程,并提供了导入后的关键验证清单与常见问题排查方法,旨在帮助硬件工程师快速掌握这一提升设计效率的关键技能。

weixin_29302047的博客 375

《遥感大模型生产级实战:从数据到决策的端到端AI工程》系列第三部分:城市洪涝灾害应急响应与评估平台实战-文章 14:项目二启动与多源异构数据对齐

我们将系统性地梳理城市洪涝场景下的所有关键数据源,从天上的卫星(光学与SAR)、空中的无人机,到地面的物联网传感器和社交媒体信息流,深入剖析每种数据在洪涝响应中的独特价值、获取方式与内在局限性。本章的核心将是一个详尽的、生产级的数据对齐技术全景,我们将分步解决三大核心对齐难题:空间对齐(将所有数据投影到统一的地理坐标系)、时间对齐(处理不同采样频率的时间序列)以及最困难的语义对齐(将文本描述与物理观测相关联)。

panshengwu的博客 2003

Spring Boot自动装配原理超详细解析

本文以最详细的方式去介绍Spring Boot自动装配的原理,从SPI到自动装配的源码解析

qq_26751319的博客 1158

64、5G 侧链通信技术详解

本文详细解析了5G侧链通信的关键技术,包括资源感知与选择、UE间协调、混合ARQ、功率控制、信道探测与CSI报告以及侧链同步。资源感知与选择通过周期性或随机方式实现资源分配,UE间协调通过主动或被动方式避免资源冲突。混合ARQ机制确保数据传输可靠性,功率控制和信道探测优化传输质量并减少干扰。侧链同步则通过多种方式确保设备间时间一致性。这些技术相互配合,构建了高效稳定的5G侧链通信体系,适用于智能交通、物联网、应急通信等多个领域,为未来无线通信发展提供强大支撑。

oil88的博客 100

死磕Spring,什么是SPI机制,对SpringBoot自动装配有什么帮助

1. SPI是一个机制,流程由三个组件构成ServiceLoader,就是ClassLoader;Service,是接口,作为文件(在META-INF/services目录下)的名称ServiceProvider,是接口的实现类,作为文件(在META-INF/services目录下)的内容2. SPI执行流程ServiceLoader通过classpath路径,加载指定的Service文件,然后使用里面合适的内容ServiceProvider。

m0_46638350的博客 2397

【AUTOSAR-DCM】-3.1-将CDD导入CFG并查看$22服务配置变化(UDS诊断DID带一个Data)

案例背景:(共8页精讲) 在《【UDS诊断描述文件CDD】-3.2-编辑CDD给$22服务创建一个带一个Data的DID(dataIdentifier)数据标识符》中,适应使用CANdela Studio在CDD中创建一个带一个Data的DID(dataIdentifier)数据标识符,见图0-1。现在我们将该CDD文件导入到CFG(DaVinci Configurator),看看配置会发生哪些变化。 图0-1 目录 1 将诊断描述文件CDD导入CFG(DaVinci Configurator.

「汽车电子助手」的博客 1630

QGIS004:【05矢量属性表】-保留字段、删除字段、添加唯一值索引字段、添加字段到属性表、添加自增量字段、添加XY字段到图层、文本型转浮点型、重构字段、重命名字段

摘要:QGIS矢量属性表工具箱包括保留字段、删除字段、添加唯一值索引字段、添加字段到属性表、添加自增量字段、添加XY字段到图层、文本型转浮点型、重构字段、重命名字段等选项,本文介绍各选项的基本操作。

qq_31762031的博客 2311

SPI机制是如何应用于springboot自动装配中

Spring Boot 自动装配机制是基于 SPI 机制的,通过。

u012534547的博客 746

华为OD机试双机位C卷 - 高矮个子排队 (C++/Py/Java/Js/Go/C)

华为OD机试双机位C卷 高矮个子排队,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解。华为OD机试 - 高矮个子排队。

qq_45776114的博客 2160

springboot 自动装配_Spring Boot自动装配原理分析

阅读本文约需要10分钟大家好,我是你们的导师,经常看我朋友圈的同学应该知道,我每天会在微信上给大家免费提供以下服务!1、长期为你提供最优质的学习资源!2、给你解决技术问题!3、每天在朋友圈里分享优质的技术文章!4、每周1、3、5送纸质书籍免费送给大家,每年至少送书800本书!5、为大家推荐靠谱的就业单位!请注意!我上面说的5点全部都是免费的!全网你应该找不到第二家吧!当然,大家...

weixin_39984442的博客 166

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

SpringBoot 自动装配原理源码分析

自动装配实际上就是把第三方组件的Bean装载到IOC容器里,不需要开发人员再去写Bean相关的一个配置

jlihan的博客 1381

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

SpringBoot自动装配原理及分析

SpringBoot自动装配

qq_36397267的博客 1079

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

【原理分析】细说SpringBoot的自动装配原理

1.什么是SpringBoot?   对于spring框架,我们接触得比较多的应该是spring mvc、和spring。而spring的核心在于IOC(控制反转对于spring框架来说,就是由spring来负责控制对象的生命周期和对象间的关系)和DI(依赖注入IoC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的。比如对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个Connection对象,有了

波波烤鸭的博客 14万+

从源码角度分析SpringBoot自动装配流程原理:

从源码角度分析SpringBoot的自动装配

m0_62074940的博客 1501

SpringBoot自动装配原理及启动分析

SpringBoot自动装配原理及启动分析 1.pom依赖分析 我们创建的springboot项目都需要继承自springboot父项目。 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.5.3</version> </p

Main_1125的博客 294

SpringBoot自动装配原理分析(二)

在前面的分析中,Spring Framework一直在致力于解决一个问题,就是如何让bean的管理变得更简单,如何让开发者尽可能的少关注一些基础化的bean的配置,从而实现自动装配。所以,所谓的自动装配,实际上就是如何自动将bean装载到Ioc容器中来。实际上在spring 3.x版本中,Enable模块驱动注解的出现,已经有了一定的自动装配的雏形,而真正能够实现这一机制,还是在spirng 4.x版本中,conditional条件注解的出现。

weixin_43881799的博客 1024

SpringBoot自动装配原理分析和实现自定义启动器

文章目录1.概述2.自动装配原理分析2.1@SpringBootConfiguration2.2@EnableAutoConfiguration3.自定义启动器 1.概述 SpringBoot的自动装配,减少了原先需要编写xml配置文件或java配置类。本文将分析SpringBoot自动装配的原理(版本是2.3.5)。从注解的作用到源码分析,再到自定义SpringBoot启动器。 2.自动装配原理分析 自动装配的实现和这个注解有密切的关联。该注解是个复合注解,里面包含了三个关键的注解 @SpringBoo

gongsenlin341的博客 2500

自动装配 自动注入_Spring Boot自动装配原理和源码分析

该篇的主要内容Spring Boot的自动装配原理【有案例模拟】Spring Boot自动装配源码分析SpringBoot中的自动装载原理SpringBoot具备开箱即用的特点,它默默的帮我们做了很多事情【自动创建和装配很多对象】自动装配的实现主要是通过ImportSelector接口完成的自动装配ImportSelectorImportSelector接口是Spring导入外部配置的核心接口,在...

weixin_39944375的博客 240

SpringBoot源码分析-自动装配-实现原理

SpringBoot,源码分析,自动装配,selectImports方法没有进入的原因

namelessmyth的专栏 328
上一篇: JDK 19 新特性
优秀小白熊
博客等级 码龄3年 1155粉丝 195原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值