java 自动装载_springboot自动装载
代碼分析版本為2.1.4.RELEASE
! V: P8 _??m??d% `' d: C$ N. ~springboot是spring的拓展框架,不需要再寫xml文件,來配置bean的加載,使開發更加便捷和高效。
4 I$ W* y* t6 S1 }/ K8 }1. 從哪里加載bean?
( E9 Q8 s; ]: W9 e
2 g# R) w( s3 W! E$ ^??K從注解開始分析
1 V9 h" o* e. [+ n5 d' v$ O% g; N6 O??z5 i) W5 ]
7 V9 W, I0 r4 o9 {5 H, r& JSpringBootApplication.java:
+ t* h0 h) G1 u) i0 @' n0 Z/ M@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 { …… }??分別查看SpringBootApplication上的注解,發現EnableAutoConfiguration.java有比較重要的信息:. x( }* m! E: {0 h/ Z1 {3 `/ g
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited//重點看這里@AutoConfigurationPackage//重點看這里@Import(AutoConfigurationImportSelector.class)public @interface EnableAutoConfiguration {? ? String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";? ? /**? ???* Exclude specific auto-configuration classes such that they will never be applied.? ???* @return the classes to exclude? ???*/? ? Class[] exclude() default {};? ? /**? ???* Exclude specific auto-configuration class names such that they will never be? ???* applied.? ???* @return the class names to exclude? ???* @since 1.3.0? ???*/? ? String[] excludeName() default {};}@AutoConfigurationPackage:表示將該類所對應的包加入到自動配置。即將MainApplication.java對應的包名加入到自動裝配。@Import(AutoConfigurationImportSelector.class) :這里在程序初始化的時候,會執行AutoConfigurationImportSelector.AutoConfigurationGroup.process,自動裝載bean,詳情邏輯請繼續看下面。
3 ~, _8 b3 r??W1 qAutoConfigurationImportSelector.java:
& X/ f8 ~8 |1 f: B; dpublic class AutoConfigurationImportSelector? ?? ???implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,? ?? ???BeanFactoryAware, EnvironmentAware, Ordered {}AutoConfigurationImportSelector的類圖:
. ^5 F" N" F( D: Q
2 ]. L9 |) u% C' ~; D3 T. {0 b
可見其實現了DeferredImportSelector類,而DeferredImportSelector又繼承ImportSelector類。該實現關系請記住,將有利于下面的代碼分析。
& p4 J6 n2 @0 ]在這里,先跟大家說一下,程序初始化的時候會執行AutoConfigurationImportSelector.AutoConfigurationGroup.process(為什么會執行該方法?詳情查看2)+ {* U& K/ j( {2 P
那么該方法實現了什么邏輯呢?& [: U5 l$ p$ e* g
@Override? ?? ???public void process(AnnotationMetadata annotationMetadata,? ?? ?? ?? ?? ? DeferredImportSelector deferredImportSelector) {? ?? ?? ?? ?Assert.state(? ?? ?? ?? ?? ?? ???deferredImportSelector instanceof AutoConfigurationImportSelector,? ?? ?? ?? ?? ?? ???() -> String.format("Only %s implementations are supported, got %s",? ?? ?? ?? ?? ?? ?? ?? ?? ? AutoConfigurationImportSelector.class.getSimpleName(),? ?? ?? ?? ?? ?? ?? ?? ?? ? deferredImportSelector.getClass().getName()));? ?? ?? ?? ?//重點看這里:獲取自動裝配實體? ?? ?? ?? ?AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)? ?? ?? ?? ?? ?? ???.getAutoConfigurationEntry(getAutoConfigurationMetadata(),? ?? ?? ?? ?? ?? ?? ?? ?? ? annotationMetadata);? ?? ?? ?? ?this.autoConfigurationEntries.add(autoConfigurationEntry);? ?? ?? ?? ?for (String importClassName : autoConfigurationEntry.getConfigurations()) {? ?? ?? ?? ?? ? this.entries.putIfAbsent(importClassName, annotationMetadata);? ?? ?? ?? ?}? ?? ???}其中再看一下getAutoConfigurationEntry方法:
& e+ q# a2 y& z+ h/**? ???* Return the {@link AutoConfigurationEntry} based on the {@link AnnotationMetadata}? ???* of the importing {@link Configuration @Configuration} class.? ???* @param autoConfigurationMetadata the auto-configuration metadata? ???* @param annotationMetadata the annotation metadata of the configuration class? ???* @return the auto-configurations that should be imported? ???*/? ? protected AutoConfigurationEntry getAutoConfigurationEntry(? ?? ?? ?? ?AutoConfigurationMetadata autoConfigurationMetadata,? ?? ?? ?? ?AnnotationMetadata annotationMetadata) {? ?? ???if (!isEnabled(annotationMetadata)) {? ?? ?? ?? ?return EMPTY_ENTRY;? ?? ???}? ?? ???AnnotationAttributes attributes = getAttributes(annotationMetadata);? ?? ? //猜測:獲取配置類,從哪里獲取?再細看這里的代碼? ?? ???List configurations = getCandidateConfigurations(annotationMetadata,? ?? ?? ?? ?? ? attributes);? ?? ?//刪除重復名稱的bean? ?? ???configurations = removeDuplicates(configurations);? ?? ?//獲取元數據的不應包括的類名(excludeName、exclude)? ?? ???Set exclusions = getExclusions(annotationMetadata, attributes);? ?? ???checkExcludedClasses(configurations, exclusions);? ?? ?//刪除不應包括的類名? ?? ???configurations.removeAll(exclusions);? ?? ?//過濾需要過濾的配置類? ?? ???configurations = filter(configurations, autoConfigurationMetadata);? ?? ???fireAutoConfigurationImportEvents(configurations, exclusions);? ?? ???return new AutoConfigurationEntry(configurations, exclusions);? ? }下面來重點看看該方法的實現:$ y2 j, l) D' P$ C
//猜測:獲取配置類,從哪里獲取?再細看這里的代碼? ?? ???List configurations = getCandidateConfigurations(annotationMetadata,? ?? ?? ?? ?? ? attributes);org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#getCandidateConfigurations:
% e* z6 o$ r- P( X4 f8 c) A/**? ???* Return the auto-configuration class names that should be considered. By default? ???* this method will load candidates using {@link SpringFactoriesLoader} with? ???* {@link #getSpringFactoriesLoaderFactoryClass()}.? ???* @param metadata the source metadata? ???* @param attributes the {@link #getAttributes(AnnotationMetadata) annotation? ???* attributes}? ???* @return a list of candidate configurations? ???*/? ? protected List getCandidateConfigurations(AnnotationMetadata metadata,? ?? ?? ?? ?AnnotationAttributes attributes) {? ?? ? //實質調用了SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class, this.beanClassLoader);? ?? ???List 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;? ? }??/**? ???* Return the class used by {@link SpringFactoriesLoader} to load configuration? ???* candidates.? ???* @return the factory class? ???*/? ? protected Class getSpringFactoriesLoaderFactoryClass() {? ?? ???return EnableAutoConfiguration.class;? ? }從上面的代碼注解中,繼續深入loadFactoryNames方法,即獲取EnableAutoConfiguration為key的所有類名4 p4 ]2 c1 W7 o, m??n
org.springframework.core.io.support.SpringFactoriesLoader#loadFactoryNames:
3 a* H& _1 Q' a- }: J* ^0 O# Spublic static List loadFactoryNames(Class factoryClass, @Nullable ClassLoader classLoader) {? ?? ???String factoryClassName = factoryClass.getName();? ?? ???return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());? ? }? ? private static Map loadSpringFactories(@Nullable ClassLoader classLoader) {? ?? ???MultiValueMap result = cache.get(classLoader);? ?? ???if (result != null) {? ?? ?? ?? ?return result;? ?? ???}? ?? ???try {? ?? ?? ?? ?Enumeration urls = (classLoader != null ?? ?? ???//注解1:FACTORIES_RESOURCE_LOCATION=META-INF/spring.factories,即從該路徑下獲取類? ?? ?? ?? ?? ?? ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :? ?? ?? ?? ?? ?? ???ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));? ?? ?? ?? ?result = new LinkedMultiValueMap();? ?? ?? ?? ?while (urls.hasMoreElements()) {? ?? ?? ?? ?? ? URL url = urls.nextElement();? ?? ?? ?? ?? ? UrlResource resource = new UrlResource(url);? ?? ?? ?? ?? ? Properties properties = PropertiesLoaderUtils.loadProperties(resource);? ?? ?? ?? ?? ? for (Map.Entry entry : properties.entrySet()) {? ?? ?? ?? ?? ?? ???String factoryClassName = ((String) entry.getKey()).trim();? ?? ?? ?? ?? ?? ???for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {? ?? ?? ?? ?? ?? ?? ?? ?result.add(factoryClassName, factoryName.trim());? ?? ?? ?? ?? ?? ???}? ?? ?? ?? ?? ? }? ?? ?? ?? ?}? ?? ?? ?? ?cache.put(classLoader, result);? ?? ?? ?? ?return result;? ?? ???}? ?? ???catch (IOException ex) {? ?? ?? ?? ?throw new IllegalArgumentException("Unable to load factories from location [" +? ?? ?? ?? ?? ?? ???FACTORIES_RESOURCE_LOCATION + "]", ex);? ?? ???}? ? }注解1:就是加載所有包的spring.factories文件,然后逐個解釋7 y% [0 H) L: J8 n- U: s0 G
其中:" K# H9 y6 U' D8 _% p2 Y
Properties properties = PropertiesLoaderUtils.loadProperties(resource);# b/ p' K3 m; ]/ J??v4 K???
解釋spring.factories文件" ^* ^: T9 \+ U7 P" }5 C) A1 ?
如下圖所示,某個包下的spring.factories文件:
: K1 e6 @- _0 f
轉化為# E9 K3 o* u7 c. T" M- M/ v
org.springframework.boot.autoconfigure.EnableAutoConfiguration->
2 ]$ @' X4 F2 Q2 xorg.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
% a7 F4 Q0 b) R; H4 I) T4 e6 }9 p0 T' l相關流程圖如下:
" U8 c$ h4 l8 S* c# L
; J??y, j$ c" i
2. 為什么會執行AutoConfigurationImportSelector.AutoConfigurationGroup.process?' Q6 b$ \/ Y/ x+ ^5 |7 J/ Z
5 E8 Z2 }" v, b- U* D4 ^9 S* e4 s9 V
從springApplication.run開始:" s6 G( Y* S# b0 A+ K+ l
5 G0 x' r1 u7 ~. h% M
代碼太多,挑重點的說:
6 `; _# s# k" R0 e' ?org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass6 x3 Q) {??J+ A4 f/ w
會處理如下圖所示的注解,在分析@Import注解時,會查看該類是不是實現DeferredImportSelector類,如果是,則會調用this.deferredImportSelectorHandler.process()。很明顯,在前面提到,AutoConfigurationImportSelector實現了DeferredImportSelector,所以在后面的邏輯中,會調用AutoConfigurationImportSelector.AutoConfigurationGroup.process方法9 p- z% w4 U; D; Y$ W; n' h
總結:
3 J; c# d8 a* p) Q??d) g- U4 C0 a??~$ u?????G, O5 |9 e! A: `
springboot會自動掃描mainApplication類所在包的所有bean- N+ v9 I& m' R7 T# P% Q, i! d
springboot會自動掃描jar包下面的/METF/spring.factories文件,將EnableAutoConfiguration為key的所有類名加載出來,并進行去重、過濾
) q3 r* ~+ D6 m% A3 X??x6 i
( U; M3 z??I??`' ^5 e! A7 r; d! hJava吧 收集整理 java論壇 www.java8.com
總結
以上是生活随笔為你收集整理的java 自动装载_springboot自动装载的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java11模块化开发_【JDK 11】
- 下一篇: mysql数据漂移_第28问:SIP 漂