日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring Boot 到底是怎么做到自动配置的?

發布時間:2025/3/21 javascript 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring Boot 到底是怎么做到自动配置的? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

作者:祖大帥

juejin.im/post/5b679fbc5188251aad213110

SpringBoot的故事從一個面試題開始

Spring Boot、Spring MVC 和 Spring 有什么區別?

分開描述各自的特征:

Spring 框架就像一個家族,有眾多衍生產品例如 boot、security、jpa等等。但他們的基礎都是Spring 的ioc和 aop,ioc 提供了依賴注入的容器, aop解決了面向橫切面的編程,然后在此兩者的基礎上實現了其他延伸產品的高級功能。

Spring MVC提供了一種輕度耦合的方式來開發web應用。它是Spring的一個模塊,是一個web框架。通過Dispatcher Servlet, ModelAndView 和 View Resolver,開發web應用變得很容易。解決的問題領域是網站應用程序或者服務開發——URL路由、Session、模板引擎、靜態Web資源等等。

Spring Boot實現了自動配置,降低了項目搭建的復雜度。它主要是為了解決使用Spring框架需要進行大量的配置太麻煩的問題,所以它并不是用來替代Spring的解決方案,而是和Spring框架緊密結合用于提升Spring開發者體驗的工具。同時它集成了大量常用的第三方庫配置(例如Jackson, JDBC, Mongo, Redis, Mail等等),Spring Boot應用中這些第三方庫幾乎可以零配置的開箱即用(out-of-the-box)。

所以,用最簡練的語言概括就是:

  • Spring 是一個“引擎”;

  • Spring MVC 是基于Spring的一個 MVC 框架;

  • Spring Boot 是基于Spring4的條件注冊的一套快速開發整合包。

SpringBoot到底是怎么做到自動配置的?

從代碼里看項目SpringBoot的項目啟動類只有一個注解@SpringBootApplication和一個run方法。

@SpringBootApplication public?class?Application?{public?static?void?main(String[]?args)?{SpringApplication.run(Application.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?{@AliasFor(annotation?=?EnableAutoConfiguration.class)Class<?>[]?exclude()?default?{};@AliasFor(annotation?=?EnableAutoConfiguration.class)String[]?excludeName()?default?{};@AliasFor(annotation?=?ComponentScan.class,attribute?=?"basePackages")String[]?scanBasePackages()?default?{};@AliasFor(annotation?=?ComponentScan.class,attribute?=?"basePackageClasses")Class<?>[]?scanBasePackageClasses()?default?{}; }

@SpringBootApplication:包含了@SpringBootConfiguration(打開是@Configuration),@EnableAutoConfiguration,@ComponentScan注解。

@Configuration

JavaConfig形式的Spring Ioc容器的配置類使用的那個@Configuration,SpringBoot社區推薦使用基于JavaConfig的配置形式,所以,這里的啟動類標注了@Configuration之后,本身其實也是一個IoC容器的配置類。

對比一下傳統XML方式和config配置方式的區別:

XML聲明和定義配置方式:

<?xml?version="1.0"?encoding="UTF-8"?> <beans?xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"?xmlns:aop="http://www.springframework.org/schema/aop"xmlns:context="http://www.springframework.org/schema/context"?xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beans?http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/aop?http://www.springframework.org/schema/aop/spring-aop-3.0.xsdhttp://www.springframework.org/schema/context?http://www.springframework.org/schema/context/spring-context-3.0.xsdhttp://www.springframework.org/schema/tx?http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"><bean?id="app"?class="com..."?/>

用一個過濾器舉例,JavaConfig的配置方式是這樣:

@Configuration public?class?DruidConfiguration?{????@Beanpublic?FilterRegistrationBean?statFilter(){//創建過濾器FilterRegistrationBean?filterRegistrationBean?=?new?FilterRegistrationBean(new?WebStatFilter());//設置過濾器過濾路徑filterRegistrationBean.addUrlPatterns("/*");//忽略過濾的形式filterRegistrationBean.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");return?filterRegistrationBean;} }

任何一個標注了@Configuration的Java類定義都是一個JavaConfig配置類。

任何一個標注了@Bean的方法,其返回值將作為一個bean定義注冊到Spring的IoC容器,方法名將默認成該bean定義的id。

@ComponentScan

@ComponentScan對應XML配置中的元素,@ComponentScan的功能其實就是自動掃描并加載符合條件的組件(比如@Component和@Repository等)或者bean定義,最終將這些bean定義加載到IoC容器中。

我們可以通過basePackages等屬性來細粒度的定制@ComponentScan自動掃描的范圍,如果不指定,則默認Spring框架實現會從聲明@ComponentScan所在類的package進行掃描。

注:所以SpringBoot的啟動類最好是放在root package下,因為默認不指定basePackages。

@EnableAutoConfiguration

(核心內容)看英文意思就是自動配置,概括一下就是,借助@Import的幫助,將所有符合自動配置條件的bean定義加載到IoC容器。

@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?{}; }

里面最關鍵的是@Import(EnableAutoConfigurationImportSelector.class),借助EnableAutoConfigurationImportSelector,@EnableAutoConfiguration可以幫助SpringBoot應用將所有符合條件的@Configuration配置都加載到當前SpringBoot創建并使用的IoC容器。該配置模塊的主要使用到了SpringFactoriesLoader。

SpringFactoriesLoader詳解

SpringFactoriesLoader為Spring工廠加載器,該對象提供了loadFactoryNames方法,入參為factoryClass和classLoader即需要傳入工廠類名稱和對應的類加載器,方法會根據指定的classLoader,加載該類加器搜索路徑下的指定文件,即spring.factories文件,傳入的工廠類為接口,而文件中對應的類則是接口的實現類,或最終作為實現類。

public?abstract?class?SpringFactoriesLoader?{//...public?static?<T>?List<T>?loadFactories(Class<T>?factoryClass,?ClassLoader?classLoader)?{...}public?static?List<String>?loadFactoryNames(Class<?>?factoryClass,?ClassLoader?classLoader)?{....} }

所以文件中一般為如下圖這種一對多的類名集合,獲取到這些實現類的類名后,loadFactoryNames方法返回類名集合,方法調用方得到這些集合后,再通過反射獲取這些類的類對象、構造方法,最終生成實例。

下圖有助于我們形象理解自動配置流程(盜個圖)

AutoConfigurationImportSelector

繼續上面講的AutoConfigurationImportSelector.class。該類主要關注selectImports方法

public?String[]?selectImports(AnnotationMetadata?annotationMetadata)?{if?(!this.isEnabled(annotationMetadata))?{return?NO_IMPORTS;}?else?{AutoConfigurationMetadata?autoConfigurationMetadata?=?AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);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.filter(configurations,?autoConfigurationMetadata);this.fireAutoConfigurationImportEvents(configurations,?exclusions);return?StringUtils.toStringArray(configurations);}}

該方法在springboot啟動流程——bean實例化前被執行,返回要實例化的類信息列表。如果獲取到類信息,spring可以通過類加載器將類加載到jvm中,現在我們已經通過spring-boot的starter依賴方式依賴了我們需要的組件,那么這些組件的類信息在select方法中就可以被獲取到。

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?is?correct.");return?configurations;}

方法中的getCandidateConfigurations方法,其返回一個自動配置類的類名列表,方法調用了loadFactoryNames方法,查看該方法

public?static?List<String>?loadFactoryNames(Class<?>?factoryClass,?@Nullable?ClassLoader?classLoader)?{String?factoryClassName?=?factoryClass.getName();return?(List)loadSpringFactories(classLoader).getOrDefault(factoryClassName,?Collections.emptyList());}

自動配置器會跟根據傳入的factoryClass.getName()到項目系統路徑下所有的spring.factories文件中找到相應的key,從而加載里面的類。我們就選取這個mybatis-spring-boot-autoconfigure下的spring.factories文件

#?Auto?Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

進入org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration中,又是一堆注解

@org.springframework.context.annotation.Configuration @ConditionalOnClass({SqlSessionFactory.class,?SqlSessionFactoryBean.class}) @ConditionalOnBean({DataSource.class}) @EnableConfigurationProperties({MybatisProperties.class}) @AutoConfigureAfter({DataSourceAutoConfiguration.class}) public?class?MybatisAutoConfiguration {private?static?final?Logger?logger?=?LoggerFactory.getLogger(MybatisAutoConfiguration.class);private?final?MybatisProperties?properties;private?final?Interceptor[]?interceptors;private?final?ResourceLoader?resourceLoader;private?final?DatabaseIdProvider?databaseIdProvider;private?final?List<ConfigurationCustomizer>?configurationCustomizers;

@Spring的Configuration是一個通過注解標注的springBean,

@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class})這個注解的意思是:當存在SqlSessionFactory.class, SqlSessionFactoryBean.class這兩個類時才解析MybatisAutoConfiguration配置類,否則不解析這一個配置類。我們需要mybatis為我們返回會話對象,就必須有會話工廠相關類

@CondtionalOnBean(DataSource.class):只有處理已經被聲明為bean的dataSource

@ConditionalOnMissingBean(MapperFactoryBean.class)這個注解的意思是如果容器中不存在name指定的bean則創建bean注入,否則不執行

以上配置可以保證sqlSessionFactory、sqlSessionTemplate、dataSource等mybatis所需的組件均可被自動配置,@Configuration注解已經提供了Spring的上下文環境,所以以上組件的配置方式與Spring啟動時通過mybatis.xml文件進行配置起到一個效果。

只要一個基于SpringBoot項目的類路徑下存在SqlSessionFactory.class, SqlSessionFactoryBean.class,并且容器中已經注冊了dataSourceBean,就可以觸發自動化配置,意思說我們只要在maven的項目中加入了mybatis所需要的若干依賴,就可以觸發自動配置,但引入mybatis原生依賴的話,每集成一個功能都要去修改其自動化配置類,那就得不到開箱即用的效果了。

所以Spring-boot為我們提供了統一的starter可以直接配置好相關的類,觸發自動配置所需的依賴(mybatis)如下:

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

因為maven依賴的傳遞性,我們只要依賴starter就可以依賴到所有需要自動配置的類,實現開箱即用的功能。也體現出Springboot簡化了Spring框架帶來的大量XML配置以及復雜的依賴管理,讓開發人員可以更加關注業務邏輯的開發。

再貼個盜的圖SpringBoot的啟動結構圖

總結

以上是生活随笔為你收集整理的Spring Boot 到底是怎么做到自动配置的?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。