当前位置: 首页 > article >正文

【Spring Boot】第二篇 自动装配原来就这么简单

导航

      • 一. 什么是自动装配?
      • 二. 如何实现自动装配?
        • 1. 配置清单在哪里?
        • 2. 自动装配实现
          • 核心点1: 从META‐INF/spring.factories路径读取配置类清单
          • 核心点2: 过滤
            • 第一次过滤: 根据EnableAutoConfiguration注解中exclude和excludeName属性
            • 第二次过滤: 通过AutoConfigurationImportFilter过滤器
        • 3. 总结自动装配的实现原理

还记得以前面试的时候,经常被问道,说一下Spring Boot的自动装配原理?
咋一听,原理? 觉得逼格应该挺高, 很高大上的东西, 等自己真正了解之后, 卧槽, 就那么回事。
Spring Boot版本是2.6.13

一. 什么是自动装配?

基于注解的Spring Boot的自动装配是Spring Boot框架中的一种特性,它允许开发者使用注解来简化和自动化应用程序的配置和装配过程。
通过使用@EnableAutoConfiguration特定的注解,Spring Boot可以根据应用程序的依赖关系和配置来自动装配和配置一系列的Bean对象和组件。开发者只需要在相应的类或方法上添加特定的注解,Spring Boot就会根据这些注解的配置信息自动完成相应的初始化和装配工作。
简单来说,就是解放开发者的双手, 一切的脏活累活直接交给Spring Boot来完成。

二. 如何实现自动装配?

在介绍自动装配原理之前, 先举一个生活中的简单例子,某天你发工资了, 要犒劳一下自己, 决定去吃一顿火锅, 来到火锅店扫描点餐, 点了一个鸳鸯锅底,并备注要微辣, 还有一些荤菜和素菜之类的。然后服务端打印了你下单的清单,给到后厨,厨师根据你的清单准备锅底和食材, 一切准备好后,服务员端到你的餐桌上, 直接开吃了。
在这里插入图片描述
这个例子重点在于菜单, 需要有人写,还需要有人读,; 例子中大厨就是Spring Boot的角色, 顾客就是写Spring Boot的开发人员, 菜单实际上就是Spring Boot自动装配的配置清单, 所以自动装配实际上就是一个实现这个读的步骤 。
接下来结合源码来具体分析:

1. 配置清单在哪里?

首先pom文件中依赖了spring-boot-starter-web

 <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
 </dependency>

其内部实际上又依赖了spring-boot-autoconfigure, 使用mvn dependency:tree -Dverbose生成依赖树, 来验证下
在这里插入图片描述
这个配置清单就在spring-boot-autoconfigureMETA-INF/spring.factories文件中
在这里插入图片描述
spring.factories文件中, 找到org.springframework.boot.autoconfigure.EnableAutoConfiguration, 下面都是自动装配的配置清单

# Auto Configure  核心配置: 待自动装配的配置清单
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRestClientAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.r2dbc.R2dbcDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.r2dbc.R2dbcRepositoriesAutoConfiguration,\
.......省略.......

配置清单已经有了,已经知道在什么位置了, 那么只需要让Spring Boot来读取就行了!

2. 自动装配实现

首先看Spring Boot 项目的启动类

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication  
public class SpringBootDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootDemoApplication.class, args);
    }
}

启动类被注解@SpringBootApplication定义,此注解用于标识该类是Spring Boot的配置类。配置类通常用于定义各种Bean(例如数据源、事务管理器等)以及其他配置(例如扫描路径、是否开启自动配置等)

细看注解@SpringBootApplication内部构造

@Target(ElementType.TYPE)   //表明@SpringBootApplication注解只能定义在类上
@Retention(RetentionPolicy.RUNTIME) //表明当注解标注的类编译以被JVM加载方式保留
@Documented   //Java Doc会生成注解信息 
@Inherited  //是否会被继承 
@SpringBootConfiguration //标注在某个类上,表示这是一个Spring Boot的配置类
@EnableAutoConfiguration  //★核心, 开启自动配置功能
//@ComponentScan 扫描包, 相当于在spring.xml 配置中<context:comonent-scan> 
//但是并没有指定basepackage,如果没有指定spring底层会自动扫描当前配置类所有在的包
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

    /**
	 * 排除特定的自动配置类,使它们永远不会被应用。返回:要排除的类
	 */
	@AliasFor(annotation = EnableAutoConfiguration.class)
	Class<?>[] exclude() default {};

    /**
	 * 排除特定的自动配置类名,使它们永远不会被应用。返回:要排除的类名
	 */
	@AliasFor(annotation = EnableAutoConfiguration.class)
	String[] excludeName() default {};

    /**
	 * 属性可以指定一个或多个包名,用逗号分隔。告诉Spring Boot在启动时需要扫描的包,以查找带有注解的类
	 * @SpringBootApplication(scanBasePackages = {"com.example.package1", "com.example.package2"})
	 */
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
	String[] scanBasePackages() default {};
	
    /**
	 * 属性指定一个或多个类,Spring Boot 在启动时会扫描这些类所在的包
	 * @SpringBootApplication(scanBasePackageClasses = {MyClass1.class, MyClass2.class})
	 */
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
	Class<?>[] scanBasePackageClasses() default {};

    /**
	 * 该属性指定一个自定义的Bean名称生成器。
	 * Spring Boot应用程序中的每个Bean都需要一个唯一的名称来标识它们,通常使用默认的命名策略。
     * 但是,如果需要对Bean的名称进行自定义,可以通过实现BeanNameGenerator接口并在nameGenerator属性中指定自定义的Bean名称生成器。
     * 使用自定义的名称生成器可以根据项目需求为Bean生成特定的名称。
	 */
	@AliasFor(annotation = ComponentScan.class, attribute = "nameGenerator")
	Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

    /**
	 * 该属性指定一个自定义的Bean名称生成器。
	 * 用于控制是否为@Configuration配置类中的@Bean方法生成代理对象
     * 默认情况下,Spring Boot应用程序会为配置类(也就是带有@Configuration注解的类)中的@Bean方法生成代理对象。
     * 这样做的目的是为了确保@Bean方法每次调用都返回同一个Bean实例,以充分利用Spring的缓存机制。
     * 但是,如果希望禁用这种代理行为,可以将proxyBeanMethods属性设置为false。
     * 禁用代理行为可能会导致@Bean方法每次都创建一个新的Bean实例,可能会降低应用程序的性能。
	 */
	@AliasFor(annotation = Configuration.class)
	boolean proxyBeanMethods() default true;

}

可以看到,注解类SpringBootApplication又被@EnableAutoConfiguration注解定义, 这么直白的名字,一看就知道它要开启自动装配,SpringBoot要开始骚了,于是默默进去看源码

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage   //用于指定自动配置类所在的包。它的作用是告诉Spring Boot应该扫描哪个包来寻找自动配置类
@Import(AutoConfigurationImportSelector.class)   //核心
public @interface EnableAutoConfiguration {

	/**
	 * 一个常量,用于指定一个环境变量或系统属性,用于在启用自动配置时覆盖默认值。
	 * 默认情况下,自动配置是启用的,但可以通过设置这个属性来覆盖默值。如果设置了该属性的值为false,则自动配置将被禁用。
	 */
	String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

	/**
	 * 用于排除某些自动配置类。可以指定一个或多个类,使其不被自动配置
	 * 例如:@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
	 */
	Class<?>[] exclude() default {};

	/**
	 * 与 exclude 属性类似,但是通过指定类的全限定名来排除自动配置类
	 * 例如:@EnableAutoConfiguration(excludeName"org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration")
	 */
	String[] excludeName() default {};
}

利用注解@Import导入了AutoConfigurationImportSelector类, 而AutoConfigurationImportSelector类实现了DeferredImportSelector,并重写了getImportGroup()方法

@Override
public Class<? extends Group> getImportGroup() {
	return AutoConfigurationGroup.class;
}

返回了一个自定义实现DeferredImportSelector.Group类的AutoConfigurationGroup静态内部类, 并重写process()方法

private static class AutoConfigurationGroup
			implements DeferredImportSelector.Group, BeanClassLoaderAware, BeanFactoryAware, ResourceLoaderAware {

		private final Map<String, AnnotationMetadata> entries = new LinkedHashMap<>();

		private final List<AutoConfigurationEntry> autoConfigurationEntries = new ArrayList<>();

		private ClassLoader beanClassLoader;

		private BeanFactory beanFactory;

		private ResourceLoader resourceLoader;

		private AutoConfigurationMetadata autoConfigurationMetadata;

		@Override
		public void setBeanClassLoader(ClassLoader classLoader) {
			this.beanClassLoader = classLoader;
		}

		@Override
		public void setBeanFactory(BeanFactory beanFactory) {
			this.beanFactory = beanFactory;
		}

		@Override
		public void setResourceLoader(ResourceLoader resourceLoader) {
			this.resourceLoader = resourceLoader;
		}

		@Override
		public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
			Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
					() -> String.format("Only %s implementations are supported, got %s",
							AutoConfigurationImportSelector.class.getSimpleName(),
							deferredImportSelector.getClass().getName()));
			//核心方法getAutoConfigurationEntry(),加载配置类清单				
			AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
					.getAutoConfigurationEntry(annotationMetadata);
			this.autoConfigurationEntries.add(autoConfigurationEntry);
			for (String importClassName : autoConfigurationEntry.getConfigurations()) {
				this.entries.putIfAbsent(importClassName, annotationMetadata);
			}
		}
		........省略......
   }

Spring Boot内部在解析@Import注解时会调用AutoConfigurationImportSelector.getAutoConfigurationEntry()方法,
下面是Spring Boot 2.6.13版本的源码: 重点关注三个核心点

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
	if (!isEnabled(annotationMetadata)) {
		return EMPTY_ENTRY;
	}
	AnnotationAttributes attributes = getAttributes(annotationMetadata);
	//核心点1: 从META‐INF/spring.factories中获得候选的自动配置类
	List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
	//去重
	configurations = removeDuplicates(configurations);
	//核心点2:过滤
	//第一次过滤:根据EnableAutoConfiguration注解中exclude和excludeName属性,获取不需要自动装配的类名单
	Set<String> exclusions = getExclusions(annotationMetadata, attributes);
    //进行排除
	checkExcludedClasses(configurations, exclusions);
    //exclusions 也排除
	configurations.removeAll(exclusions);
    //第二次过滤: 通过读取spring.factories 中的OnBeanCondition\OnClassCondition\OnWebApplicationCondition进行过滤
	configurations = getConfigurationClassFilter().filter(configurations);
	//这个方法是调用实现了AutoConfigurationImportListener的bean..  分别把候选的配置名单,和排除的配置名单传进去做扩展
	fireAutoConfigurationImportEvents(configurations, exclusions);
	return new AutoConfigurationEntry(configurations, exclusions);
}
核心点1: 从META‐INF/spring.factories路径读取配置类清单

SpringFactoriesLoader中的loadSpringFactories()方法中有明确定义

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
   MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
    if (result != null) {
        return result;
    } else {
        try {
            //指定了路径
            Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
            MultiValueMap<String, String> result = new LinkedMultiValueMap();

            while(urls.hasMoreElements()) {
                URL url = (URL)urls.nextElement();
                UrlResource resource = new UrlResource(url);
                Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                Iterator var6 = properties.entrySet().iterator();

                while(var6.hasNext()) {
                    Map.Entry<?, ?> entry = (Map.Entry)var6.next();
                    String factoryTypeName = ((String)entry.getKey()).trim();
                    String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                    int var10 = var9.length;

                    for(int var11 = 0; var11 < var10; ++var11) {
                        String factoryImplementationName = var9[var11];
                        result.add(factoryTypeName, factoryImplementationName.trim());
                    }
                }
            }

            cache.put(classLoader, result);
            return result;
        } catch (IOException var13) {
            throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
        }
    }
}

spring.factories配置清单中的内容是不是全部读?
不是的, 根据标识符org.springframework.boot.autoconfigure.EnableAutoConfiguration, 从指定位置读取内容。

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
   //从META‐INF/spring.factories中获得候选的自动配置类
   //读取的配置类有133个
   List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
		getBeanClassLoader());
   Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
		+ "are using a custom packaging, make sure that file is correct.");
   return configurations;
}

protected Class<?> getSpringFactoriesLoaderFactoryClass() {
    return EnableAutoConfiguration.class;
}

在源码SpringFactoriesLoader.loadFactoryNames()方法中有定义

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    //从META‐INF/spring.factories中获得候选的自动配置类
    //读取的配置类有133个
	List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
			getBeanClassLoader());
	Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
			+ "are using a custom packaging, make sure that file is correct.");
    return configurations;
}

/**
 * 依据getSpringFactoriesLoaderFactoryClass()可知, 参数factoryType其实就是EnableAutoConfiguration.class
 */
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
       //factoryTypeName的值就是org.springframework.boot.autoconfigure.EnableAutoConfiguration
       //刚好对应上spring.factories配置清单上指定位置
       String factoryTypeName = factoryType.getName(); 
       return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
核心点2: 过滤

为什么需要过滤? 从spring.factories文件中读取到所有配置类,是否都需要进行自动装配,然后让如IOC容器中?
答案是否定的, 并不是都需要进行自动装配, 需要按需装配, 这就需要Spring Boot自己进行选择性的判断。
根据源码AutoConfigurationImportSelector.getAutoConfigurationEntry()方法可知,会进行两次过滤

第一次过滤: 根据EnableAutoConfiguration注解中exclude和excludeName属性

根据EnableAutoConfiguration注解中excludeexcludeName属性,获取不需要自动装配的类名单, 但是从注解SpringBootApplication类中可知, 定义的@EnableAutoConfiguration注解并没有设置exclude和excludeName属性值,所以可忽略

第二次过滤: 通过AutoConfigurationImportFilter过滤器

首先会在spring.factories文件根据org.springframework.boot.autoconfigure.AutoConfigurationImportFilter标识, 在指定位置读取需要进行过滤的内容

# Auto Configuration Import Filters 核心过滤: 根据条件进行许选择性的自动装配
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition

使用过滤器AutoConfigurationImportFilter, 争对三个spring.factories文件定义的内容分别对注解@OnBeanCondition, @OnClassCondition@OnWebApplicationCondition进行条件按判断, 不符合条件的不会进行自动装配。
见源码SpringFactoriesLoader中的loadFactories()方法

public static <T> List<T> loadFactories(Class<T> factoryType, @Nullable ClassLoader classLoader) {
      Assert.notNull(factoryType, "'factoryType' must not be null");
      ClassLoader classLoaderToUse = classLoader;
      if (classLoader == null) {
          classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
      }
      //factoryType 是org.springframework.boot.autoconfigure.AutoConfigurationImportFilter
      //从spring.factories文件的org.springframework.boot.autoconfigure.AutoConfigurationImportFilter指定位置读取内容
      //集合中有三个
      //org.springframework.boot.autoconfigure.condition.OnBeanCondition
      //org.springframework.boot.autoconfigure.condition.OnClassCondition
      //org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition
      List<String> factoryImplementationNames = loadFactoryNames(factoryType, classLoaderToUse);
      if (logger.isTraceEnabled()) {
          logger.trace("Loaded [" + factoryType.getName() + "] names: " + factoryImplementationNames);
      }

      List<T> result = new ArrayList(factoryImplementationNames.size());
      Iterator var5 = factoryImplementationNames.iterator();

      while(var5.hasNext()) {
          String factoryImplementationName = (String)var5.next();
          result.add(instantiateFactory(factoryImplementationName, factoryType, classLoaderToUse));
      }

      AnnotationAwareOrderComparator.sort(result);
      return result;
  }

最后过滤完成后, 剩下的就是需要进行自动装配的配置类了

HttpEncodingAutoConfiguration配置类,来举例

//标记了@Configuration Spring底层会给配置创建cglib动态代理。 作用:就是防止每次调用本类的Bean方法而重新创建对象,Bean是默认单例的
@Configuration(proxyBeanMethods = false) 
@EnableConfigurationProperties(ServerProperties.class)  //启用可以在配置类设置的属性 对应的类
//条件注解, 当前是web环境,条件成立,才进行自动装配
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) 
//条件注解,容器中必须有CharacterEncodingFilter类,条件成立,才进行自动装配
@ConditionalOnClass(CharacterEncodingFilter.class) 
//条件注解, 表示配置文件application.properties有server.servlet.encoding配置,且定义的值是enabled时,条件成立,允许进行自动装配
@ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true) 
public class HttpEncodingAutoConfiguration {
	private final Encoding properties;

	public HttpEncodingAutoConfiguration(ServerProperties properties) {
		this.properties = properties.getServlet().getEncoding();
	}

	@Bean
	@ConditionalOnMissingBean  // 当IOC容器中没有CharacterEncodingFilter时,才会创建
	public CharacterEncodingFilter characterEncodingFilter() {
		CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
		filter.setEncoding(this.properties.getCharset().name());
		filter.setForceRequestEncoding(this.properties.shouldForce(Encoding.Type.REQUEST));
		filter.setForceResponseEncoding(this.properties.shouldForce(Encoding.Type.RESPONSE));
		return filter;
	}

	@Bean
	public LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() {
		return new LocaleCharsetMappingsCustomizer(this.properties);
	}

......省略......
}

当注解@ConditionalOnWebApplication, @ConditionalOnClass@ConditionalOnProperty定义的条件都成立时, 那么Spring Boot就会对该配置类里被注解@Bean定义的方法,进行自动装配, 创建对应的Bean对象,然后放入IOC容器中。这样当Spring Boot正常运行后,就可以直接从IOC容器中拿Bean对象直接使用了。

3. 总结自动装配的实现原理

在这里插入图片描述
从从spring-boot-autoconfigure JAR包的META-INF/spring.factories文件中获取的配置列表起初有133个
在这里插入图片描述
经过层层过滤之后, 最后还剩下24个
在这里插入图片描述
最后结合例子和源码详解,Spring Boot基于注解的自动装配的原理,是不是很简单。


http://www.kler.cn/a/231698.html

相关文章:

  • 豆包 MarsCode + 开源 = ?AI 助力开源社区新人成长
  • ComfyUI实现老照片修复——AI修复老照片(ComfyUI-ReActor / ReSwapper)解决天坑问题及加速pip下载
  • Oracle Agile PLM Web Service Java示例测试开发(一)环境环境、准备说明
  • 链式存储结构
  • ThreeJS示例教程200+【目录】
  • Python “字典” 实战案例:5个项目开发实例
  • 2024.2.7日总结(小程序开发4)
  • 通过nginx学习linux进程名的修改
  • 每日一题!如约而至!(图片整理,寻找数组的中心下标)
  • 寒假作业2月5号
  • 配置dns服务的正反向解析
  • JUnit5单元测试框架提供的注解
  • Django学习记录01
  • 如何使用websocket
  • LLVM实战之opt工具的使用
  • 每日一练 | 华为认证真题练习Day182
  • 大厂聚合支付系统架构演进(下)
  • 【开源】基于JAVA+Vue+SpringBoot的新能源电池回收系统
  • 【C#】Xasset加载资源模块
  • 中科大计网学习记录笔记(四):Internet 和 ISP | 分组延时、丢失和吞吐量
  • nodeJS 的 npm 设置国内高速镜像之淘宝镜像的方法
  • 小白水平理解面试经典题目LeetCode 71. Simplify Path【Stack类】
  • Java-加解密-roadmap
  • 16:定时器和计数器
  • 【Ubuntu】安装filebeat
  • SpringCache缓存快速实现注解