javascript
springboot aop使用_Spring Boot 的自动配置,是如何实现的?
點擊上方"IT牧場",選擇"設為星標"技術干貨每日送達!
作者 | 祖大帥
鏈接 | juejin.im/post/5b679fbc5188251aad213110SpringBoot 的故事從一個面試題開始
Spring Boot、Spring MVC 和 Spring 有什么區別?
先來個 SpringBoot 的啟動結構圖
分開描述各自的特征
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)。
Tips:關注微信公眾號:Java后端,每日技術博文推送。
所以,用最簡練的語言概括就是
. Spring 是一個“引擎”;. Spring MVC 是基于Spring的一個 MVC 框架;. Spring Boot 是基于Spring4的條件注冊的一套快速開發整合包。
SpringBoot到底是怎么做到自動配置的?
從代碼里看項目SpringBoot的項目啟動類只有一個注解@SpringBootApplication和一個run方法。
@SpringBootApplicationpublic?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"?>"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.xsd
????????????http://www.springframework.org/schema/aop
????????????http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
????????????http://www.springframework.org/schema/context
????????????http://www.springframework.org/schema/context/spring-context-3.0.xsd
????????????http://www.springframework.org/schema/tx
????????????http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">"app"?class="com..."?/>
用一個過濾器舉例,JavaConfig的配置方式是這樣
@Configurationpublic?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的啟動類最好是放在rootpackage下,因為默認不指定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??List loadFactories(Class<T>?factoryClass,?ClassLoader?classLoader)?{????????...
????}public?static?List 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 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 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.bootgroupId><artifactId>mybatis-spring-boot-starterartifactId>dependency>因為maven依賴的傳遞性,我們只要依賴starter就可以依賴到所有需要自動配置的類,實現開箱即用的功能。也體現出Springboot簡化了Spring框架帶來的大量XML配置以及復雜的依賴管理,讓開發人員可以更加關注業務邏輯的開發。
干貨分享
最近將個人學習筆記整理成冊,使用PDF分享。關注我,回復如下代碼,即可獲得百度盤地址,無套路領取!
?001:《Java并發與高并發解決方案》學習筆記;?002:《深入JVM內核——原理、診斷與優化》學習筆記;?003:《Java面試寶典》?004:《Docker開源書》?005:《Kubernetes開源書》?006:《DDD速成(領域驅動設計速成)》?007:全部?008:加技術討論群
近期熱文
?安裝單機版Consul?微服務治理實踐:探尋業務的單點異常自愈能力?支付寶的架構到底有多牛逼!還沒看完我就跪了!?配置熱更新,不想重啟,如何更新Bean的狀態??如何模擬 5 萬的并發用戶?一篇文章搞定:掃碼登錄實現原理
想知道更多?長按/掃碼關注我吧↓↓↓>>>技術討論群<<<喜歡就點個"在看"唄^_^
總結
以上是生活随笔為你收集整理的springboot aop使用_Spring Boot 的自动配置,是如何实现的?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python编程快速上手_给Python
- 下一篇: extern 定义_Essential