事業(yè)單位網(wǎng)站建設(shè)工作方案sem百度競價推廣
文章目錄
- SpringBoot依賴管理特性
- 依賴管理
- 開發(fā)導(dǎo)入starter場景啟動器
- SpringBoot自動配置特性
- 自動配好Tomcat
- 自動配好SpringMVC
- 默認(rèn)的包結(jié)構(gòu)
- 各種配置擁有默認(rèn)值
- 按需加載所有自動配置項
- SpringBoot注解底層注解
- @Configuration
- @Import導(dǎo)入組件
- @Conditional條件裝配
- @ImportResource導(dǎo)入Spring配置文件
- @ConfigurationProperties配置綁定
- 自動配置
- @SpringBootApplication的源碼
- @SpringBootConfiguration
- @ComponentScan
- @EnableAutoConfiguration
- 自動包規(guī)則原理
- @AutoConfigurationPackage
- 初始加載自動配置類
- @Import(AutoConfigurationImportSelector.class)
- @Import(AutoConfigurationImportSelector.class)
- 按需配置的例子
- 自動配置流程
SpringBoot依賴管理特性
依賴管理
我們在HelloWorld中導(dǎo)入的父項目依賴
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.4.RELEASE</version>
</parent>
spring-boot-starter-parent的父項目中的一個依賴如下:
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>2.3.4.RELEASE</version>
</parent>
spring-boot-dependencies幾乎聲明了所有開發(fā)中常用的依賴的版本號,自動版本仲裁機(jī)制
- 導(dǎo)入spring-boot-starter-parent父項目是用來做依賴管理的,這樣我們導(dǎo)入依賴無需關(guān)注版本號,自動版本仲裁
- 引入依賴默認(rèn)都可以不寫版本
- 引入非版本仲裁的jar,要寫版本號。
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId>
</dependency>
-
可以修改默認(rèn)版本號
-
查看spring-boot-dependencies里面規(guī)定當(dāng)前依賴的版本 用的 key。
-
在當(dāng)前項目里面重寫配置,如下面的代碼。
-
<properties><mysql.version>5.1.43</mysql.version>
</properties>
開發(fā)導(dǎo)入starter場景啟動器
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
- 見到很多 spring-boot-starter-* : *就某種場景
- web就是我們開發(fā)web應(yīng)用的場景
- 只要引入starter,這個場景的所有常規(guī)需要的依賴我們都自動引入
- 更多SpringBoot所有支持的場景
- 當(dāng)我們覺得不夠用,還可以自己創(chuàng)建starter啟動器
- 見到的 *-spring-boot-starter: 第三方為我們提供的簡化開發(fā)的場景啟動器。
所有場景啟動器最底層的依賴
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><version>2.3.4.RELEASE</version><scope>compile</scope>
</dependency>
SpringBoot自動配置特性
這里我們以我們導(dǎo)入的web場景下的starter為例子
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
自動配好Tomcat
- 引入Tomcat依賴。
- 配置Tomcat
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId><version>2.3.4.RELEASE</version><scope>compile</scope>
</dependency>
自動配好SpringMVC
- 引入SpringMVC全套組件
- 自動配好SpringMVC常用組件(功能)
<dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.2.9.RELEASE</version><scope>compile</scope>
</dependency>
- 自動配好Web常見功能,如:字符編碼問題
- SpringBoot幫我們配置好了所有web開發(fā)的常見場景
public static void main(String[] args) {//1、返回我們IOC容器ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);//2、查看容器里面的組件String[] names = run.getBeanDefinitionNames();for (String name : names) {System.out.println(name);}
}
//部分輸出結(jié)果
tomcatWebServerFactoryCustomizer
org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration
characterEncodingFilter--------設(shè)置字符編碼的過濾器
localeCharsetMappingsCustomizer
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration
multipartConfigElement
multipartResolver
spring.servlet.multipart-org.springframework.boot.autoconfigure.web.servlet.MultipartProperties
org.springframework.aop.config.internalAutoProxyCreator
我們之前想解決中文亂碼問題,需要我們自己配置字符編碼過濾器,有了SpringBoot,我們都不需要設(shè)置
默認(rèn)的包結(jié)構(gòu)
- 主程序(也就是被我們@SpringBootApplication修飾的類)所在包及其下面的所有子包里面的組件都會被默認(rèn)掃描進(jìn)來
- 自動代替我們之前Ioc容器xml文件中配置的自動掃描組件
- 無需以前的包掃描配置
- 想要改變掃描路徑
- @SpringBootApplication(scanBasePackages=“com.lun”)
- 為什么不能直接通過@ComponentScan 指定掃描路徑 因為我們的@SpringBootApplication()是一個合成注解
@SpringBootApplication(scanBasePackages="com.lsc")
等同于
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.lun")
各種配置擁有默認(rèn)值
- 默認(rèn)配置最終都是映射到某個類上,如:
MultipartProperties
#設(shè)置服務(wù)器的端口號
server.port=8080
#設(shè)置文件上傳的最大大小
spring.servlet.multipart.max-file-size=10MB
配置文件的值最終會綁定每個類上,因為這個類會在容器中創(chuàng)建對象
按需加載所有自動配置項
- 我們的SpringBoot非常多的starter
- 引入了哪些場景這個場景的自動配置才會開啟
- SpringBoot所有的自動配置功能都在 spring-boot-autoconfigure 包里面
- 但是不是所有的配置都會生效,至于原理需要了解相關(guān)注解的原理
我們的spring-boot-starter-web中存在spring-boot-starter依賴
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><version>2.3.4.RELEASE</version><scope>compile</scope>
</dependency>
我們的spring-boot-starter中存在spring-boot-autoconfigure
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId><version>2.3.4.RELEASE</version><scope>compile</scope>
</dependency>
SpringBoot注解底層注解
@Configuration
表示當(dāng)前這個類是配置類,類似我們xml配置文件的作用
/*** @author lsc* #Description MyConfig* #Date: 2023/2/11 11:11*/
@Configuration(proxyBeanMethods = true)
public class MyConfig {@Bean//給容器中添加組件。以方法名作為組件的id。返回類型就是組件類型。返回的值,就是組件在容器中的實例public User user01(){User user = new User(1, "劉頌成");user.setCat(tomcat());return user ;}@Bean("tomcat")//如果不想以方法名為名稱,可以自己自定義public Cat tomcat(){return new Cat("tomcat");}
}
- 配置類里面使用@Bean標(biāo)注在方法上給容器注冊組件,默認(rèn)也是單實例的
- 配置類本身也是組件
- proxyBeanMethods:代理bean的方法
-
Full(proxyBeanMethods = true)(保證每個@Bean方法被調(diào)用多少次返回的組件都是單實例的)(默認(rèn))
-
Lite(proxyBeanMethods = false)(每個@Bean方法被調(diào)用多少次返回的組件都是新創(chuàng)建的)
-
測試
@SpringBootApplication(scanBasePackages = "com.lsc")
public class MainApplication {public static void main(String[] args) {//1、返回我們IOC容器ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);//2、查看容器里面的組件String[] names = run.getBeanDefinitionNames();for (String name : names) {System.out.println(name);}//3、從容器中獲取組件Pet tom01 = run.getBean("tom", Pet.class);Pet tom02 = run.getBean("tom", Pet.class);System.out.println("組件:"+(tom01 == tom02));//4、com.atguigu.boot.config.MyConfig$$EnhancerBySpringCGLIB$$51f1e1ca@1654a892MyConfig bean = run.getBean(MyConfig.class);System.out.println(bean);//如果@Configuration(proxyBeanMethods = true) 代理對象調(diào)用方法。SpringBoot總會檢查這個組件是否在容器中有。//保持組件單實例User user = bean.user01();User user1 = bean.user01();System.out.println(user == user1);//trueUser user01 = run.getBean("user01", User.class);Cat tom = run.getBean("tomcat", Cat.class);System.out.println("用戶的寵物:"+(user01.getPet() == tom));//true}
}
- 最佳實戰(zhàn)
- 配置 類組件之間無依賴關(guān)系用Lite模式加速容器啟動過程,減少判斷
- 配置 類組件之間有依賴關(guān)系,方法會被調(diào)用得到之前單實例組件,用Full模式(默認(rèn))
@Import導(dǎo)入組件
-
@Bean、@Component、@Controller、@Service、@Repository,它們是Spring的基本標(biāo)簽,在Spring Boot中并未改變它們原來的功能。
-
@ComponentScan表示掃描組件,來指定要掃描的包
@Import({User.class, DBHelper.class})
@Configuration(proxyBeanMethods = false)
public class MyConfig {@Bean//給容器中添加組件。以方法名作為組件的id。返回類型就是組件類型。返回的值,就是組件在容器中的實例public User user01(){User user = new User(1, "劉頌成");user.setCat(tomcat());return user ;}@Bean("tomcat")//如果不想以方法名為名稱,可以自己自定義public Cat tomcat(){return new Cat("tomcat");}
}
- @Import自動導(dǎo)入對應(yīng)的類,利用其無參構(gòu)造方法創(chuàng)建一個Bean給容器進(jìn)行管理
- @Import({User.class, DBHelper.class})給容器中自動創(chuàng)建出這兩個類型的組件、默認(rèn)組件的名字就是全類名
測試類:
@SpringBootApplication(scanBasePackages = "com.lsc")
public class MainApplication {public static void main(String[] args) {//返回的是IOC容器ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class,args);String[] beanNamesForType = run.getBeanNamesForType(User.class);for (String s : beanNamesForType) {System.out.println(s);}DBHelper bean1 = run.getBean(DBHelper.class);System.out.println(bean1);}
}
//
com.lsc.springboot.pojo.User
user01
ch.qos.logback.core.db.DBHelper@73d6d0c
@Conditional條件裝配
條件裝配:滿足Conditional指定的條件,則進(jìn)行組件注入
- ConditionalOnBean,當(dāng)容器存在某個Bean,才會進(jìn)行注入以下的對象
- ConditionalOnMissingBean,當(dāng)容器不存在某個Bean,才會進(jìn)行注入以下的對象
用@ConditionalOnBean舉例說明
/*** @author lsc* #Description MyConfig* #Date: 2023/2/11 11:11*/
@Configuration(proxyBeanMethods = true)
@ConditionalOnBean(name = "tomcat")//只有當(dāng)有tom名字的Bean時,MyConfig類的Bean才能生效。
public class MyConfig {@Bean//給容器中添加組件。以方法名作為組件的id。返回類型就是組件類型。返回的值,就是組件在容器中的實例public User user01(){User user = new User(1, "劉頌成");user.setCat(tomcat());return user ;}
// @Bean("tomcat")//如果不想以方法名為名稱,可以自己自定義public Cat tomcat(){return new Cat("tomcat");}
}
- 現(xiàn)在我們的容器中是不存在user01這個bean
- 對應(yīng)的條件裝配注解可以放在方法上也可以放在類上
@SpringBootApplication(scanBasePackages = "com.lsc")
public class MainApplication {public static void main(String[] args) {//返回的是IOC容器ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class,args);//查看我們IOC容器中Bean的組件名稱boolean tomcat = run.containsBean("tomcat");System.out.println("名稱為tomcat的存在"+tomcat);boolean user01 = run.containsBean("user01");System.out.println("名稱為user01的bean存在"+user01);}
}
//輸出結(jié)果
名稱為tomcat的存在false
名稱為user01的bean存在false
- 我們看到我們的tomcat這個bean不存在,所以連user01這個bean也沒有注入容器
@ImportResource導(dǎo)入Spring配置文件
比如,公司使用bean.xml文件生成配置bean,然而你為了省事,想繼續(xù)復(fù)用bean.xml,@ImportResource登場。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean class="com.lsc.springboot.pojo.User" id="haha"><property name="id" value="2"></property><property name="name" value="sss"></property></bean><bean class="com.lsc.springboot.pojo.Cat" id="hehe"><property name="name" value="小貓"></property></bean>
</beans>
測試
public static void main(String[] args) {//1、返回我們IOC容器ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);boolean haha = run.containsBean("haha");boolean hehe = run.containsBean("hehe");System.out.println("haha:"+haha);//trueSystem.out.println("hehe:"+hehe);//true
}
@ConfigurationProperties配置綁定
如何使用Java讀取到properties文件中的內(nèi)容,并且把它封裝到JavaBean中,以供隨時使用
傳統(tǒng)方式
public class getProperties {public static void main(String[] args) throws FileNotFoundException, IOException {Properties pps = new Properties();pps.load(new FileInputStream("a.properties"));Enumeration enum1 = pps.propertyNames();//得到配置文件的名字while(enum1.hasMoreElements()) {String strKey = (String) enum1.nextElement();String strValue = pps.getProperty(strKey);System.out.println(strKey + "=" + strValue);//封裝到JavaBean。}}}
- 我們需要自己讀取文件的內(nèi)容,然后進(jìn)行判斷存入
Spring Boot一種配置配置綁定:
@ConfigurationProperties + @Component
假設(shè)有配置文件application.properties
mycar.brand=BYD
mycar.price=10000
@Component
@ConfigurationProperties(prefix = "mycar")
public class Car {private String brand;private Integer price;.......
}
- 因為只有被spring管理,才能擁有SpringBoot強(qiáng)大的功能
@RestController
public class HelloWorldController {@AutowiredCar car;@RequestMapping("/car")public Car car(){return car;}
SpringBoot另一種配置配置綁定
@EnableConfigurationProperties + @ConfigurationProperties
- 開啟Car配置綁定功能
- 把這個Car這個組件自動注冊到容器中
@ConfigurationProperties(prefix = "mycar")
public class Car {
...
}
@EnableConfigurationProperties(Car.class)
public class MyConfig {
...
}
自動配置
被@SpringBootApplication表示為主類
@SpringBootApplication(scanBasePackages = "com.lsc")
public class MainApplication {public static void main(String[] args) {SpringApplication.run(MainApplication.class,args);}
@SpringBootApplication的源碼
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {@Filter(type = FilterType.CUSTOM,classes = {TypeExcludeFilter.class}
), @Filter(type = FilterType.CUSTOM,classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {...
}
重點(diǎn)分析@SpringBootConfiguration
,@EnableAutoConfiguration
,@ComponentScan
@SpringBootConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {@AliasFor(annotation = Configuration.class)boolean proxyBeanMethods() default true;
}
@Configuration
代表當(dāng)前是一個配置類。
@ComponentScan
指定掃描哪些Spring注解。
@EnableAutoConfiguration
這個注解需要重點(diǎn)分析
@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 {};
}
重點(diǎn)分析@AutoConfigurationPackage
,@Import(AutoConfigurationImportSelector.class)
。
自動包規(guī)則原理
@AutoConfigurationPackage
標(biāo)簽名直譯為:自動配置包,指定了默認(rèn)的包規(guī)則。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class})
public @interface AutoConfigurationPackage {String[] basePackages() default {};Class<?>[] basePackageClasses() default {};
}
- @Import({Registrar.class})利用Registrar給容器中導(dǎo)入一系列組件
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {Registrar() {}public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));}public Set<Object> determineImports(AnnotationMetadata metadata) {return Collections.singleton(new AutoConfigurationPackages.PackageImports(metadata));}}
Registrar.class 作用:將主啟動類的所在包及包下面所有子包里面的所有組件掃描到Spring容器
初始加載自動配置類
@Import(AutoConfigurationImportSelector.class)
AutoConfigurationImportSelector :自動配置導(dǎo)入選擇器,那么它會導(dǎo)入哪些組件的選擇器呢?我們點(diǎn)擊去這個類看源碼:
1、這個類中有一個這樣的方法
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {if (!this.isEnabled(annotationMetadata)) {return EMPTY_ENTRY;} else {AnnotationAttributes attributes = this.getAttributes(annotationMetadata);List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);configurations = this.removeDuplicates(configurations);Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);this.checkExcludedClasses(configurations, exclusions);configurations.removeAll(exclusions);configurations = this.getConfigurationClassFilter().filter(configurations);this.fireAutoConfigurationImportEvents(configurations, exclusions);return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);}}
2getAutoConfigurationEntry中調(diào)用了getCandidateConfigurations
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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 correct.");return configurations;}
3 這個方法又調(diào)用了SpringFactoriesLoader 類的靜態(tài)方法!我們進(jìn)入SpringFactoriesLoader類loadFactoryNames() 方法
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {String factoryTypeName = factoryType.getName();return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());}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");LinkedMultiValueMap 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()) {Entry<?, ?> entry = (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);}}}
發(fā)現(xiàn)一個多次出現(xiàn)的文件:spring.factories,全局搜索它
spring.factories
文件里面寫死了spring-boot一啟動就要給容器中加載的所有配置類
我們根據(jù)源頭打開spring.factories , 看到了很多自動配置的文件;這就是自動配置根源所在!
這個spring.factories文件也是一組一組的key=value的形式,其中一個key是EnableAutoConfiguration類的全類名,而它的value是一個xxxxAutoConfiguration的類名的列表,這些類名以逗號分隔,如下圖所示:
@Import(AutoConfigurationImportSelector.class)
-
AutoConfigurationImportSelector類中利用
getAutoConfigurationEntry(annotationMetadata);
給容器中批量導(dǎo)入一些組件 -
getAutoConfigurationEntry方法中通過調(diào)用
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
獲取到所有需要導(dǎo)入到容器中的配置類-
SpringFactoriesLoader利用工廠加載
Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader);
得到所有的組件-
從
META-INF/spring.factories
位置來加載一個文件。 -
默認(rèn)掃描我們當(dāng)前系統(tǒng)里面所有
META-INF/spring.factories
位置的文件
-
-
spring-boot-autoconfigure-2.3.4.RELEASE.jar
包里面也有META-INF/spring.factories
# 文件里面寫死了spring-boot一啟動就要給容器中加載的所有配置類
# spring-boot-autoconfigure-2.3.4.RELEASE.jar/META-INF/spring.factories
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
...
雖然我們127個場景的所有自動配置啟動的時候默認(rèn)全部加載,但是xxxxAutoConfiguration
按照條件裝配規(guī)則(@Conditional
),最終會按需配置。
springboot所有的自動配置都是在啟動的時候掃描并加載,掃描了spring.properties配置文件,所有的自動配置類都在這里面,但是不定生效,因為要判斷條件是否成立,只要導(dǎo)入了對應(yīng)的start,就有對應(yīng)的啟動器,有了啟動器我們自動裝配就會生效,然后就配置成功
按需配置的例子
AopAutoConfiguration
類:
@Configuration(proxyBeanMethods = false
)
@ConditionalOnProperty(prefix = "spring.aop",name = "auto",havingValue = "true",matchIfMissing = true
)
public class AopAutoConfiguration {public AopAutoConfiguration() {}...
}
- prefix為配置文件中的前綴,
- name為配置的名字
- havingValue是與配置的值對比值,當(dāng)兩個值相同返回true,配置類生效.
- matchIfMissing表示如果沒有這么配置的默認(rèn)值
自動配置流程
以DispatcherServletAutoConfiguration
的內(nèi)部類DispatcherServletConfiguration
為例子:
@Bean
@ConditionalOnBean(MultipartResolver.class) //容器中有這個類型組件
@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) //容器中沒有這個名字 multipartResolver 的組件
public MultipartResolver multipartResolver(MultipartResolver resolver) {// Detect if the user has created a MultipartResolver but named it incorrectlyreturn resolver;//給容器中加入了文件上傳解析器;
}
- 給@Bean標(biāo)注的方法傳入了對象參數(shù),這個參數(shù)的值就會從容器中找。
- 方法名為multipartResolver ,SpringMVC multipartResolver防止有些用戶配置的文件上傳解析器不符合規(guī)范
SpringBoot默認(rèn)會在底層配好所有的組件,但是如果用戶自己配置了以用戶的優(yōu)先。
總結(jié):
- SpringBoot先加載所有的自動配置類 xxxxxAutoConfiguration
- 每個自動配置類按照條件進(jìn)行生效,默認(rèn)都會綁定配置文件指定的值。(xxxxProperties里面讀取,xxxProperties和配置文件進(jìn)行了綁定)
- 生效的配置類就會給容器中裝配很多組件
- 只要容器中有這些組件,相當(dāng)于這些功能就有了
- 定制化配置
- 用戶直接自己@Bean替換底層的組件
- 用戶去看這個組件是獲取的配置文件什么值就去修改。
xxxxxAutoConfiguration —> 組件 —> xxxxProperties里面拿值 ----> application.properties
面試官問你你可以這樣說,springboot是通過main方法下的SpringApplication.run方法啟動的,啟動的時候他會調(diào)用refshContext方法,先刷新容器,然后根據(jù)解析注解或者解析配置文件的形式注冊bean,還會它是通過啟動類的SpringBootApplication注解進(jìn)行開始解析的,他會根據(jù)EnableAutoConfiguration開啟自動化配置,里面有個核心方法ImportSelect選擇性的導(dǎo)入,根據(jù)loadFactoryNames根據(jù)classpath路徑以MATA-INF/spring.factorces下面以什么什么EnableAutoConfiguration開頭的key去加載里面所有對應(yīng)的自動化配置,他并不是把這一百二十多個自動化配置全部導(dǎo)入,在他每個自動化配置里面都有條件判斷注解,先判斷是否引入相互的jar包,再判斷容器是否有bean再進(jìn)行注入到bean容器