一文帶你了解SpringBoot中常用注解的原理和使用
@AutoConfiguration
讀取所有jar包下的 /META-INF/spring.factories 并追加到一個 LinkedMultiValueMap 中。每一個url中記錄的文件路徑如下:
file:/C:/Users/wangchao/apache-maven-3.5.0/repo/com/baomidou/mybatis-plus-boot-starter/3.5.1/mybatis-plus-boot-starter-3.5.1.jar!/META-INF/spring.factories
按照如下路徑查看
// 1. @EnableAutoConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
}
// 2. AutoConfigurationImportSelector.class#selectImports()
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
// 3. AutoConfigurationImportSelector.class#getAutoConfigurationEntry()
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
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);
}
// 4. AutoConfigurationImportSelector.class#getCandidateConfigurations()
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
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;
}
// 5. org.springframework.core.io.support.SpringFactoriesLoader#loadFactoryNames()
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}最終使用 loadSpringFactories(@Nullable ClassLoader classLoader) 方法讀取所有配置文件。
// 6. org.springframework.core.io.support.SpringFactoriesLoader#loadSpringFactories()
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
while (urls.hasMoreElements()) {
// 讀取所有jar包下的 /META-INF/spring.factories
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();
for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}tomcat的自動配置內(nèi)置于springboot的autoconfiguration中。參考tomcat的自動配置:SpringBoot如何實現(xiàn)Tomcat自動配置
mybatis-plus的配置沒有被springboot包括。因此mybatis-stater中包含一個包mybatis-spring-boot-autoconfigure,這其中配置了需要自動配置的類。
因此我們也可以在自己的項目下新建 /META-INF/spring.factories ,并配置自動配置類。
@Import
@Import 用于導(dǎo)入配置類或需要前置加載的類。被導(dǎo)入的類會注冊為Bean,可直接作為Bean被引用。它的 value 屬性可以支持三種類型:
- 被 @Configuration 修飾的配置類、或普通類(4.2版本之后可以)。
- ImportSelector 接口的實現(xiàn)。
- ImportBeanDefinitionRegistrar 接口的實現(xiàn)。
@Import 的配置
@Configuration
@Import(value = {TestA.class, TestB.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
public class ConfigurationTest {
}導(dǎo)入一個普通類
package com.example.ssmpdemo.entity;
public class TestA {
public void fun(){
System.out.println("testA");
}
}導(dǎo)入一個配置類
package com.example.ssmpdemo.entity;
import org.springframework.context.annotation.Configuration;
@Configuration
public class TestB {
public void fun(){
System.out.println("testB");
}
}通過實現(xiàn) ImportSelector 接口
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.example.ssmpdemo.entity.TestC"};
}
}通過重寫 ImportBeanDefinitionRegistrar 的 registerBeanDefinitions 方法。
import com.example.ssmpdemo.entity.TestD;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
RootBeanDefinition root = new RootBeanDefinition(TestD.class);
registry.registerBeanDefinition("testD", root);
}
}@ConfigurationProperties
- 支持常見的下劃線、中劃線和駝峰的轉(zhuǎn)換。支持對象引導(dǎo)。比如:user.friend.name 代表的是user對象中的friend對象中的name
- 需要有set()方法
- 只添加 @ConfigurationProperties(prefix = "xxx") 并不會生效,需要配合 @Configuration 讓容器識別到。
- @EnableConfigurationProperties(value = ConfigData.class ) 會將value中指定的類注冊為Bean,可直接用 @AutoWired 引用。
1.定義一個類用來記錄所有字段,并使用@ConfigurationProperties(prefix = "xxx")將數(shù)據(jù)注入到ConfigData中。
package com.example.ssmpdemo.entity;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* 用來記錄Configuration的數(shù)據(jù)
* @author wangc
*/
@Data
@ConfigurationProperties(value = "spring.datasource.druid")
public class ConfigData {
private String driverClassName;
private String url;
private String username;
private String password;
}
# 對應(yīng)的yml文件
spring:
datasource:
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:5506/ssmpdemo?serverTimezone=UTC
username: root
password: xxxx2.使用@EnableConfigurationProperties(JDBCProperties.class) 將 ConfigData 注冊為Bean,并提供給ConfigurationTest使用 。可將ConfigData作為參數(shù)注入到構(gòu)造函數(shù)和普通函數(shù)中。
3.可以用以下方式引用被@ConfigurationProperties(value = "spring.datasource.druid")修飾的ConfigData
可以直接把 ConfigData 當成Bean使用
/**
* 可直接被注入
*/
@Autowired
private ConfigData configData;
可以用構(gòu)造函數(shù)傳入進來
@Data
@Configuration
@EnableConfigurationProperties(value = ConfigData.class )
public class ConfigurationTest {
private ConfigData configData2;
/**
* 作為構(gòu)造函數(shù)的參數(shù)注入
* @param data
*/
ConfigurationTest(ConfigData data){
this.configData2 = data;
}
也可以作為@Bean的方法函數(shù)的參數(shù)。只有當前類(ConfigurationTest)才可
/**
* 直接作為函數(shù)的參數(shù)
* @param data
* @return
*/
@Bean(name = "configData2")
HashMap<String, String> getBean(ConfigData data){
return new HashMap<>(0);
}
可以省略ConfigData直接將字段注入到返回結(jié)果中。
@Bean
@ConfigurationProperties(value = "spring.datasource.druid")
HashMap<String, String> getBean2(ConfigData data){
// 會自動為hashMap賦值,或使用set方法為對象賦值
return new HashMap<>();
}
EnableConfigurationProperties注解的內(nèi)部如下,它導(dǎo)入了一個實現(xiàn)了 ImportBeanDefinitionRegistrar 接口的類。
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(EnableConfigurationPropertiesRegistrar.class)
class EnableConfigurationPropertiesRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
registerInfrastructureBeans(registry);
ConfigurationPropertiesBeanRegistrar beanRegistrar = new ConfigurationPropertiesBeanRegistrar(registry);
// 獲得@EnableConfigurationProperties的value指向的對象,并注冊。
getTypes(metadata).forEach(beanRegistrar::register);
}到此這篇關(guān)于一文帶你了解SpringBoot中常用注解的原理和使用的文章就介紹到這了,更多相關(guān)SpringBoot注解內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
IntelliJ?IDEA教程之clean或者install?Maven項目的操作方法
這篇文章主要介紹了IntelliJ?IDEA教程之clean或者install?Maven項目的操作方法,本文分步驟給大家介紹兩種方式講解如何調(diào)試出窗口,需要的朋友可以參考下2023-04-04
SpringBoot+Vue+Flowable模擬實現(xiàn)請假審批流程
這篇文章主要為大家詳細介紹了如何利用SpringBoot+Vue+Flowable模擬實現(xiàn)一個請假審批流程,文中的示例代碼講解詳細,需要的可以參考一下2022-08-08
SpringBoot解析指定Yaml配置文件的實現(xiàn)過程
這篇文章主要介紹了SpringBoot解析指定Yaml配置文件,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-03-03
SpringBoot之RestTemplate在URL中轉(zhuǎn)義字符的問題
這篇文章主要介紹了SpringBoot之RestTemplate在URL中轉(zhuǎn)義字符的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-06-06
springsecurity中http.permitall與web.ignoring的區(qū)別說明
這篇文章主要介紹了springsecurity中http.permitall與web.ignoring的區(qū)別說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08

