2025/4/6
向全棧工程師邁進!
一、自動配置
所謂的自動配置原理就是遵循約定大約配置的原則,在boot工程程序啟動后,起步依賴中的一些bean對象會自動的注入到IOC容器中。
在講解Spring Boot 中bean對象的管理的時候,我們注入bean對象的過程如下,但這種方式不是自動注入的。?
并沒有達到自動配置。 而自動配置是當程序在引入spring-boot-starter-web 起步依賴,boot工程在啟動后,會自動往ioc容器中注入DispatcherServlet等bean對象,這就是自動配置。那自動配置的原理是什么呢?
二、自動配置原理
在這里只先引入springboot起步核心依賴,而并沒有引入spring-boot-starter-web起步依賴。
<!--引入springboot起步核心依賴-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId>
</dependency>
在沒有引入spring-boot-starter-web依賴之前,我們嘗試輸出spring-boot-starter-web起步依賴會自動注入的bean對象,沒有在pom.xml文件中添加改起步依賴時,輸出發現根本沒有。
package com.example.demo;import org.springframework.context.ApplicationContext;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class Demo1Application {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(Demo1Application.class, args);System.out.println(context.getBean("dispatcherServlet"));}}
導入依賴spring-boot-starter-web后,再次嘗試輸出其bean對象,發現成功,當引入依賴后,其bean對象被自動的注入了。
2.1 查看@SpringBootApplication注解源碼
是組合了以下三個注解
- @SpringBootConfiguration 其本身也是一個組合注解
- @EnableAutoConfiguration 其本身也是一個組合注解
- @ComponentScan 是Bean掃描的注解
@SpringBootConfiguration的內部代碼:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.springframework.boot;import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Indexed;@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {@AliasFor(annotation = Configuration.class)boolean proxyBeanMethods() default true;
}
可以發現在@SpringBootConfiguration內部也是有@Configuration注解的,所以當在啟動類上添加注解@SpringBootApplication其實就是也在啟動類上添加了@Configuration注解,所以啟動類也是一個配置類。
@EnableAutoConfiguration的內部代碼:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.springframework.boot.autoconfigure;import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";Class<?>[] exclude() default {};String[] excludeName() default {};
}
@EnableAutoConfiguration是自動配置的核心注解,該@EnableAutoConfiguration注解其實組合了@AutoConfigurationPackage和@Import兩個注解,在@Import注解中導入實現類AutoConfigurationImportSelector。其AutoConfigurationImportSelector的實現類如下(代碼不全):
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.springframework.boot.autoconfigure;import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
........
import org.springframework.util.StringUtils;public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {private static final AutoConfigurationEntry EMPTY_ENTRY = new AutoConfigurationEntry();private static final String[] NO_IMPORTS = new String[0];private static final Log logger = LogFactory.getLog(AutoConfigurationImportSelector.class);private static final String PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE = "spring.autoconfigure.exclude";private ConfigurableListableBeanFactory beanFactory;private Environment environment;private ClassLoader beanClassLoader;private ResourceLoader resourceLoader;private ConfigurationClassFilter configurationClassFilter;public AutoConfigurationImportSelector() {}............private MetadataReaderFactory getMetadataReaderFactory() {try {return (MetadataReaderFactory)this.beanFactory.getBean("org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory", MetadataReaderFactory.class);} catch (NoSuchBeanDefinitionException var2) {return new CachingMetadataReaderFactory(this.resourceLoader);}}}
}
?可以發現在這個實現類(AutoConfigurationImportSelector
)中,會從 META-INF/spring.factories
文件中讀取所有自動配置類,它讀取的 key 是:
org.springframework.boot.autoconfigure.EnableAutoConfiguration
加載所有配置類,條件匹配后注冊為 Bean。
2.2 自動配置原理——舉個栗子🧩
核心:
AutoConfigurationImportSelector 會從 META-INF/spring.factories 文件中讀取所有自動配置類,它讀取的 key 是:
org.springframework.boot.autoconfigure.EnableAutoConfiguration
。
? 你寫了一個 Spring Boot 項目,啟動類是這樣的:
@SpringBootApplication
public class MyApp {public static void main(String[] args) {SpringApplication.run(MyApp.class, args);}
}
?這個注解其實包含了 @EnableAutoConfiguration
,表示:
“嘿 SpringBoot,我想用你自動幫我配置一些常見功能,比如數據庫、Web、Redis 等!”
?🧠 那 SpringBoot 是怎么知道你要配置啥的?
這時候就輪到 AutoConfigurationImportSelector 出場了!
它是一個“選擇器”,全名叫:
org.springframework.boot.autoconfigure.AutoConfigurationImportSelector
它的作用是:
🧭“我去找一個叫
spring.factories
的文件,里面寫了:SpringBoot 應該自動配置哪些類。我一個個加載它們,看看哪個需要用,哪個可以跳過。”
📂 spring.factories 是什么?
它是一個純文本配置文件,路徑在:
classpath:/META-INF/spring.factories
這個文件來自哪個 jar 包?👉 就是 Spring Boot 的依賴包之一:
spring-boot-autoconfigure-xxx.jar
打開看一下這個文件長什么樣:
# 配置項的 key
org.springframework.boot.autoconfigure.EnableAutoConfiguration=# 配置的值(每一行都是一個自動配置類,全限定類名)
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.redis.RedisAutoConfiguration
🌟 所以:Spring Boot 會遍歷所有這些類,一個個判斷:
-
項目中有沒有用到數據庫?
-
類路徑中有沒有 MySQL 驅動?
-
你有沒有配置
spring.datasource.url
? -
有沒有你自己寫的 DataSource Bean?
滿足這些條件它就幫你創建這個 Bean;不滿足,它就跳過。
?如下是我真實項目中其spring.factories文件中的內容。
三、實現自動配置?
自動配置全過程如下:
?
山高路遠,我們慢些走,路邊有花,遠處有彩虹,西邊有落日......?