springboot自動裝配原理探究
結論:
- SpringBoot啟動會加載大量的自動配置類
- 我們看我們需要的功能有沒有在SpringBoot默認寫好的自動配置類當中;
- 我們再來看這個自動配置類中到底配置了哪些組件;(只要我們要用的組件存在在其中,我們就不需要再手動配置了)
- 給容器中自動配置類添加組件的時候,會從properties類中獲取某些屬性,我們只需要在組態檔中指定這些屬性的值即可;
對于配置類的讀取:
- 根據當前不同的條件判斷,決定這個配置類是否生效!
- 一但這個配置類生效;這個配置類就會給容器中添加各種組件;
- 這些組件的屬性是從對應的properties類中獲取的,這些類里面的每一個屬性又是和組態檔系結的;
- 所有在組態檔中能配置的屬性都是在xxxxProperties類中封裝著;
- 組態檔能配置什么就可以參照某個功能對應的這個屬性類
- 首先創建一個springboot專案,打開主啟動類

存在如下注解:
-
@SpringBootApplication放在專案的一個啟動類上,用來把啟動類注入到容器中,用來定義容器掃描的范圍,用來加載classpath環境中一些bean,
- 點進
@SpringBootApplication

可以看到包含如下注解:
-
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited四大元注解,
-
@SpringBootConfiguration標識一個springboot配置類
-
@EnableAutoConfiguration啟動自動裝配
-
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })開啟組件掃描
- 先點進
@ComponentScan中看看掃描了什么組件

在這個注解下我們找到了這樣一個屬性:
/**
* Controls the class files eligible for component detection.
* <p>Consider use of {@link #includeFilters} and {@link #excludeFilters}
* for a more flexible approach.
*/
String resourcePattern() default ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN;
找到這個屬性值:
public class ClassPathScanningCandidateComponentProvider implements EnvironmentCapable, ResourceLoaderAware {
static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";
}
可以看到幫我們匯入了所有當前啟動類所在路徑下的任意類檔案
- 接著點擊
@EnableAutoConfiguration,讓我們去看看自動裝配都做了什么

可以看到存在如下注解:
-
@AutoConfigurationPackage自動配置包
-
@Import(AutoConfigurationImportSelector.class)spring的底層注解,引入一個資源
- 點擊
@AutoConfigurationPackage

我們看到自動配置包引入了一個類資源,點進去看看

該類存盤來自匯入配置的包
- 點擊
@Import(AutoConfigurationImportSelector.class),我們去看看這個注解引入的資源內容

這是一個自動配置匯入選擇器
我們找到其中的個別方法
- 獲取自動配置物體

- 獲得候選配置

在候選配置中,我們注意到它呼叫了一個SpringFactoriesLoader.loadFactoryNames()方法:
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
getBeanClassLoader());
- 讓我們去看看
SpringFactoriesLoader這個類

這是一個用于框架內部使用的通用工廠加載機制,
這是剛剛看到的loadFactoryNames()方法:

這個類中還存在這樣一個方法:
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
Map<String, List<String>> result = cache.get(classLoader);
if (result != null) {
return result;
}
result = new HashMap<>();
try {
Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
String[] factoryImplementationNames =
StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
for (String factoryImplementationName : factoryImplementationNames) {
result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
.add(factoryImplementationName.trim());
}
}
}
// Replace all lists with unmodifiable lists containing unique elements
result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
cache.put(classLoader, result);
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
return result;
}
在這個方法中我們可以看到,它加載了一個FACTORIES_RESOURCE_LOCATION資源,并將從資源中拿到的東西封裝成一個個的Properties供接下來使用
/**
* The location to look for factories.
* <p>Can be present in multiple JAR files.
*/
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
- 找到這個資源
META-INF/spring.factories


可以看到這個檔案的內容就是我們用的一個又一個的配置

- 找個我們熟悉的,例如
HttpEncodingAutoConfiguration點進去看看

看到了如下的注解:
@Configuration(proxyBeanMethods = false)配置類標識
@EnableConfigurationProperties(ServerProperties.class)啟用配置屬性
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)Spring底層@Conditional注解
根據不同的條件判斷,如果滿足指定的條件,整個配置類里面的配置就會生效;
這里的意思就是判斷當前應用是否是web應用,如果是,當前配置類生效@ConditionalOnClass(CharacterEncodingFilter.class)判斷當前專案有沒有這個類CharacterEncodingFilter;SpringMVC中進行亂碼解決的過濾器;
@ConditionalOnProperty(prefix = "server.servlet.encoding", value = "https://www.cnblogs.com/radish40/archive/2022/06/04/enabled", matchIfMissing = true)判斷組態檔中是否存在某個配置:server.servlet.encoding.enabled;
如果不存在,判斷也是成立的
即使我們組態檔中不配置server.servlet.encoding.enabled=true,也是默認生效的;
可以看到它已經系結了一個組態檔
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {
//...
}
從此可以看到組態檔里寫的東西都在這個屬性類中封裝著,也就是說這個類里有的我們都可以在組態檔中配置

總結 :
-
根據當前不同的條件判斷,決定這個配置類是否生效!
-
一但這個配置類生效;這個配置類就會給容器中添加各種組件;
-
這些組件的屬性是從對應的properties類中獲取的,這些類里面的每一個屬性又是和組態檔系結的;
-
所有在組態檔中能配置的屬性都是在xxxxProperties類中封裝著;
-
組態檔能配置什么就可以參照某個功能對應的這個屬性類
這就是自動裝配的原理!
xxxxAutoConfigurartion:自動配置類;給容器中添加組件
xxxxProperties:封裝組態檔中相關屬性;
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/486723.html
標籤:其他
