国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語(yǔ)言|JavaScript|易語(yǔ)言|vb.net|

服務(wù)器之家 - 編程語(yǔ)言 - Java教程 - 基于SpringBoot核心原理(自動(dòng)配置、事件驅(qū)動(dòng)、Condition)

基于SpringBoot核心原理(自動(dòng)配置、事件驅(qū)動(dòng)、Condition)

2020-08-27 14:23夜勿語(yǔ) Java教程

這篇文章主要介紹了基于SpringBoot核心原理(自動(dòng)配置、事件驅(qū)動(dòng)、Condition),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧

前言

SpringBoot是Spring的包裝,通過(guò)自動(dòng)配置使得SpringBoot可以做到開(kāi)箱即用,上手成本非常低,但是學(xué)習(xí)其實(shí)現(xiàn)原理的成本大大增加,需要先了解熟悉Spring原理。如果還不清楚Spring原理的,可以先查看博主之前的文章,本篇主要分析SpringBoot的啟動(dòng)、自動(dòng)配置、Condition、事件驅(qū)動(dòng)原理。

正文

啟動(dòng)原理

SpringBoot啟動(dòng)非常簡(jiǎn)單,因其內(nèi)置了Tomcat,所以只需要通過(guò)下面幾種方式啟動(dòng)即可:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@SpringBootApplication(scanBasePackages = {"cn.dark"})
public class SpringbootDemo {
 
 public static void main(String[] args) {
  // 第一種
  SpringApplication.run(SpringbootDemo .class, args);
 
 // 第二種
  new SpringApplicationBuilder(SpringbootDemo .class)).run(args);
 
 // 第三種
  SpringApplication springApplication = new SpringApplication(SpringbootDemo.class);
  springApplication.run();
 }
}

可以看到第一種是最簡(jiǎn)單的,也是最常用的方式,需要注意類上面需要標(biāo)注@SpringBootApplication注解,這是自動(dòng)配置的核心實(shí)現(xiàn),稍后分析,先來(lái)看看SpringBoot啟動(dòng)做了些什么?

在往下之前,不妨先猜測(cè)一下,run方法中需要做什么?對(duì)比Spring源碼,我們知道,Spring的啟動(dòng)都會(huì)創(chuàng)建一個(gè)ApplicationContext的應(yīng)用上下文對(duì)象,并調(diào)用其refresh方法啟動(dòng)容器,SpringBoot只是Spring的一層殼,肯定也避免不了這樣的操作。

另一方面,以前通過(guò)Spring搭建的項(xiàng)目,都需要打成War包發(fā)布到Tomcat才行,而現(xiàn)在SpringBoot已經(jīng)內(nèi)置了Tomcat,只需要打成Jar包啟動(dòng)即可,所以在run方法中肯定也會(huì)創(chuàng)建對(duì)應(yīng)的Tomcat對(duì)象并啟動(dòng)。

以上只是我們的猜想,下面就來(lái)驗(yàn)證,進(jìn)入run方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
public ConfigurableApplicationContext run(String... args) {
// 統(tǒng)計(jì)時(shí)間用的工具類
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
// 獲取實(shí)現(xiàn)了SpringApplicationRunListener接口的實(shí)現(xiàn)類,通過(guò)SPI機(jī)制加載
// META-INF/spring.factories文件下的類
SpringApplicationRunListeners listeners = getRunListeners(args);
 
// 首先調(diào)用SpringApplicationRunListener的starting方法
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
 
// 處理配置數(shù)據(jù)
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
 
// 啟動(dòng)時(shí)打印banner
Banner printedBanner = printBanner(environment);
 
// 創(chuàng)建上下文對(duì)象
context = createApplicationContext();
 
// 獲取SpringBootExceptionReporter接口的類,異常報(bào)告
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
 new Class[] { ConfigurableApplicationContext.class }, context);
 
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
 
// 核心方法,啟動(dòng)spring容器
refreshContext(context);
afterRefresh(context, applicationArguments);
 
// 統(tǒng)計(jì)結(jié)束
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
// 調(diào)用started
listeners.started(context);
 
// ApplicationRunner
// CommandLineRunner
// 獲取這兩個(gè)接口的實(shí)現(xiàn)類,并調(diào)用其run方法
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
 
try {
// 最后調(diào)用running方法
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}

SpringBoot的啟動(dòng)流程就是這個(gè)方法,先看getRunListeners方法,這個(gè)方法就是去拿到所有的SpringApplicationRunListener實(shí)現(xiàn)類,這些類是用于SpringBoot事件發(fā)布的,關(guān)于事件驅(qū)動(dòng)稍后分析,這里主要看這個(gè)方法的實(shí)現(xiàn)原理:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
 
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 加載上來(lái)后反射實(shí)例化
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
 
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
 
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
 
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()) {
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;
}
}

一步步追蹤下去可以看到最終就是通過(guò)SPI機(jī)制根據(jù)接口類型從META-INF/spring.factories文件中加載對(duì)應(yīng)的實(shí)現(xiàn)類并實(shí)例化,SpringBoot的自動(dòng)配置也是這樣實(shí)現(xiàn)的。

為什么要這樣實(shí)現(xiàn)呢?通過(guò)注解掃描不可以么?當(dāng)然不行,這些類都在第三方j(luò)ar包中,注解掃描實(shí)現(xiàn)是很麻煩的,當(dāng)然你也可以通過(guò)@Import注解導(dǎo)入,但是這種方式不適合擴(kuò)展類特別多的情況,所以這里采用SPI的優(yōu)點(diǎn)就顯而易見(jiàn)了。

回到run方法中,可以看到調(diào)用了createApplicationContext方法,見(jiàn)名知意,這個(gè)就是去創(chuàng)建應(yīng)用上下文對(duì)象:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."
+ "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";
 
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
 contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
 break;
case REACTIVE:
 contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
 break;
default:
 contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
 "Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}

注意這里通過(guò)反射實(shí)例化了一個(gè)新的沒(méi)見(jiàn)過(guò)的上下文對(duì)象AnnotationConfigServletWebServerApplicationContext,這個(gè)是SpringBoot擴(kuò)展的,看看其構(gòu)造方法:

?
1
2
3
4
public AnnotationConfigServletWebServerApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}

如果你有看過(guò)Spring注解驅(qū)動(dòng)的實(shí)現(xiàn)原理,這兩個(gè)對(duì)象肯定不會(huì)陌生,一個(gè)實(shí)支持注解解析的,另外一個(gè)是掃描包用的。上下文創(chuàng)建好了,下一步自然就是調(diào)用refresh方法啟動(dòng)容器:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private void refreshContext(ConfigurableApplicationContext context) {
refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
}
 
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext) applicationContext).refresh();
}

 

這里首先會(huì)調(diào)用到其父類中ServletWebServerApplicationContext:

?
1
2
3
4
5
6
7
8
9
public final void refresh() throws BeansException, IllegalStateException {
try {
super.refresh();
}
catch (RuntimeException ex) {
stopAndReleaseWebServer();
throw ex;
}
}

可以看到是直接委托給了父類:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
 
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
 
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
 
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
 
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
 
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
 
// Initialize message source for this context.
initMessageSource();
 
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
 
// Initialize other special beans in specific context subclasses.
onRefresh();
 
// Check for listener beans and register them.
registerListeners();
 
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
 
// Last step: publish corresponding event.
finishRefresh();
}
 
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
 logger.warn("Exception encountered during context initialization - " +
 "cancelling refresh attempt: " + ex);
}
 
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
 
// Reset 'active' flag.
cancelRefresh(ex);
 
// Propagate exception to caller.
throw ex;
}
 
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}

這個(gè)方法不會(huì)陌生吧,之前已經(jīng)分析過(guò)了,這里不再贅述,至此SpringBoot的容器就啟動(dòng)了,但是Tomcat啟動(dòng)是在哪里呢?run方法中也沒(méi)有看到。實(shí)際上Tomcat的啟動(dòng)也是在refresh流程中,這個(gè)方法其中一步是調(diào)用了onRefresh方法,在Spring中這是一個(gè)沒(méi)有實(shí)現(xiàn)的模板方法,而SpringBoot就通過(guò)這個(gè)方法完成了Tomcat的啟動(dòng):

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
protected void onRefresh() {
super.onRefresh();
try {
createWebServer();
}
catch (Throwable ex) {
throw new ApplicationContextException("Unable to start web server", ex);
}
}
 
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = getServletContext();
if (webServer == null && servletContext == null) {
ServletWebServerFactory factory = getWebServerFactory();
// 主要看這個(gè)方法
this.webServer = factory.getWebServer(getSelfInitializer());
}
else if (servletContext != null) {
try {
getSelfInitializer().onStartup(servletContext);
}
catch (ServletException ex) {
throw new ApplicationContextException("Cannot initialize servlet context", ex);
}
}
initPropertySources();
}

這里首先拿到TomcatServletWebServerFactory對(duì)象,通過(guò)該對(duì)象再去創(chuàng)建和啟動(dòng)Tomcat:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public WebServer getWebServer(ServletContextInitializer... initializers) {
if (this.disableMBeanRegistry) {
Registry.disableRegistry();
}
Tomcat tomcat = new Tomcat();
File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
tomcat.setBaseDir(baseDir.getAbsolutePath());
Connector connector = new Connector(this.protocol);
connector.setThrowOnFailure(true);
tomcat.getService().addConnector(connector);
customizeConnector(connector);
tomcat.setConnector(connector);
tomcat.getHost().setAutoDeploy(false);
configureEngine(tomcat.getEngine());
for (Connector additionalConnector : this.additionalTomcatConnectors) {
tomcat.getService().addConnector(additionalConnector);
}
prepareContext(tomcat.getHost(), initializers);
return getTomcatWebServer(tomcat);
}

上面的每一步都可以對(duì)比Tomcat的配置文件,需要注意默認(rèn)只支持了http協(xié)議:

 

?
1
2
3
4
Connector connector = new Connector(this.protocol);
 
 private String protocol = DEFAULT_PROTOCOL;
 public static final String DEFAULT_PROTOCOL = "org.apache.coyote.http11.Http11NioProtocol";

如果想要擴(kuò)展的話則可以對(duì)additionalTomcatConnectors屬性設(shè)置值,需要注意這個(gè)屬性沒(méi)有對(duì)應(yīng)的setter方法,只有addAdditionalTomcatConnectors方法,也就是說(shuō)我們只能通過(guò)實(shí)現(xiàn)BeanFactoryPostProcessor接口的postProcessBeanFactory方法,而不能通過(guò)BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法,因?yàn)榍罢呖梢酝ㄟ^(guò)傳入的BeanFactory對(duì)象提前獲取到TomcatServletWebServerFactory對(duì)象調(diào)用addAdditionalTomcatConnectors即可;而后者只能拿到BeanDefinition對(duì)象,該對(duì)象只能通過(guò)setter方法設(shè)置值。

事件驅(qū)動(dòng)

Spring原本就提供了事件機(jī)制,而在SpringBoot中又對(duì)其進(jìn)行擴(kuò)展,通過(guò)發(fā)布訂閱事件在容器的整個(gè)生命周期的不同階段進(jìn)行不同的操作。我們先來(lái)看看SpringBoot啟動(dòng)關(guān)閉的過(guò)程中默認(rèn)會(huì)發(fā)布哪些事件,使用下面的代碼即可:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
@SpringBootApplication
public class SpringEventDemo {
 
 public static void main(String[] args) {
  new SpringApplicationBuilder(SpringEventDemo.class)
    .listeners(event -> {
     System.err.println("接收到事件:" + event.getClass().getSimpleName());
    })
    .run()
    .close();
 }
 
}

這段代碼會(huì)在控制臺(tái)打印所有的事件名稱,按照順序如下:

ApplicationStartingEvent:容器啟動(dòng)

ApplicationEnvironmentPreparedEvent:環(huán)境準(zhǔn)備好

ApplicationContextInitializedEvent:上下文初始化完成

ApplicationPreparedEvent:上下文準(zhǔn)備好

ContextRefreshedEvent:上下文刷新完

ServletWebServerInitializedEvent:webServer初始化完成

ApplicationStartedEvent:容器啟動(dòng)完成

ApplicationReadyEvent:容器就緒

ContextClosedEvent:容器關(guān)閉

以上是正常啟動(dòng)關(guān)閉,如果發(fā)生異常還有發(fā)布ApplicationFailedEvent事件。事件的發(fā)布遍布在整個(gè)容器的啟動(dòng)關(guān)閉周期中,事件發(fā)布對(duì)象剛剛我們也看到了是通過(guò)SPI加載的SpringApplicationRunListener實(shí)現(xiàn)類EventPublishingRunListener,同樣事件監(jiān)聽(tīng)器也是在spring.factories文件中配置的,默認(rèn)實(shí)現(xiàn)了以下監(jiān)聽(tīng)器:

?
1
2
3
4
5
6
7
8
9
10
11
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener

可以看到有用于文件編碼的(FileEncodingApplicationListener),有加載日志框架的(LoggingApplicationListener),還有加載配置的(ConfigFileApplicationListener)等等一系列監(jiān)聽(tīng)器,SpringBoot也就是通過(guò)這系列監(jiān)聽(tīng)器將必要的配置和組件加載到容器中來(lái),這里不再詳細(xì)分析,感興趣的讀者可以通過(guò)其實(shí)現(xiàn)的onApplicationEvent方法看到每個(gè)監(jiān)聽(tīng)器究竟是監(jiān)聽(tīng)的哪一個(gè)事件,當(dāng)然事件發(fā)布和監(jiān)聽(tīng)我們自己也是可以擴(kuò)展的。

自動(dòng)配置原理

SpringBoot最核心的還是自動(dòng)配置,為什么它能做到開(kāi)箱即用,不再需要我們手動(dòng)使用@EnableXXX等注解來(lái)開(kāi)啟?這一切的答案就在@SpringBootApplication注解中:

?
1
2
3
4
5
6
7
8
9
@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 {}

這里重要的注解有三個(gè):@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan。@ComponentScan就不用再說(shuō)了,@SpringBootConfiguration等同于@Configuration,而@EnableAutoConfiguration就是開(kāi)啟自動(dòng)配置:

?
1
2
3
4
5
6
7
8
9
10
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
 
}
 
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
 
}

@AutoConfigurationPackage注解的作用就是將該注解所標(biāo)記類所在的包作為自動(dòng)配置的包,簡(jiǎn)單看看就行,主要看AutoConfigurationImportSelector,這個(gè)就是實(shí)現(xiàn)自動(dòng)配置的核心類,注意這個(gè)類是實(shí)現(xiàn)的DeferredImportSelector接口。在這個(gè)類中有一個(gè)selectImports方法。

這個(gè)方法在我之前的文章這一次搞懂Spring事務(wù)注解的解析也有分析過(guò),只是實(shí)現(xiàn)類不同,它同樣會(huì)被ConfigurationClassPostProcessor類調(diào)用,先來(lái)看這個(gè)方法做了些什么:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
// 獲取所有的自動(dòng)配置類
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
 
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// SPI獲取EnableAutoConfiguration為key的所有實(shí)現(xiàn)類
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
// 把某些自動(dòng)配置類過(guò)濾掉
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
// 包裝成自動(dòng)配置實(shí)體類
return new AutoConfigurationEntry(configurations, exclusions);
}
 
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
// SPI獲取EnableAutoConfiguration為key的所有實(shí)現(xiàn)類
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;
}

追蹤源碼最終可以看到也是從META-INF/spring.factories文件中拿到所有EnableAutoConfiguration對(duì)應(yīng)的值(在spring-boot-autoconfigure中)并通過(guò)反射實(shí)例化,過(guò)濾后包裝成AutoConfigurationEntry對(duì)象返回。

看到這里你應(yīng)該會(huì)覺(jué)得自動(dòng)配置的實(shí)現(xiàn)就是通過(guò)這個(gè)selectImports方法,但實(shí)際上這個(gè)方法通常并不會(huì)被調(diào)用到,而是會(huì)調(diào)用該類的內(nèi)部類AutoConfigurationGroup的process和selectImports方法,前者同樣是通過(guò)getAutoConfigurationEntry拿到所有的自動(dòng)配置類,而后者這是過(guò)濾排序并包裝后返回。

下面就來(lái)分析ConfigurationClassPostProcessor是怎么調(diào)用到這里的,直接進(jìn)入processConfigBeanDefinitions方法:

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
 List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
 String[] candidateNames = registry.getBeanDefinitionNames();
 
 for (String beanName : candidateNames) {
 BeanDefinition beanDef = registry.getBeanDefinition(beanName);
 if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
 if (logger.isDebugEnabled()) {
  logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
 }
 }
 else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
 configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
 }
 }
 
 // Return immediately if no @Configuration classes were found
 if (configCandidates.isEmpty()) {
 return;
 }
 
 // Sort by previously determined @Order value, if applicable
 configCandidates.sort((bd1, bd2) -> {
 int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
 int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
 return Integer.compare(i1, i2);
 });
 
 // Detect any custom bean name generation strategy supplied through the enclosing application context
 SingletonBeanRegistry sbr = null;
 if (registry instanceof SingletonBeanRegistry) {
 sbr = (SingletonBeanRegistry) registry;
 if (!this.localBeanNameGeneratorSet) {
 BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
  AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
 if (generator != null) {
  this.componentScanBeanNameGenerator = generator;
  this.importBeanNameGenerator = generator;
 }
 }
 }
 
 if (this.environment == null) {
 this.environment = new StandardEnvironment();
 }
 
 // Parse each @Configuration class
 ConfigurationClassParser parser = new ConfigurationClassParser(
 this.metadataReaderFactory, this.problemReporter, this.environment,
 this.resourceLoader, this.componentScanBeanNameGenerator, registry);
 
 Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
 Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
 do {
 parser.parse(candidates);
 parser.validate();
 
 Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
 configClasses.removeAll(alreadyParsed);
 
 // Read the model and create bean definitions based on its content
 if (this.reader == null) {
 this.reader = new ConfigurationClassBeanDefinitionReader(
  registry, this.sourceExtractor, this.resourceLoader, this.environment,
  this.importBeanNameGenerator, parser.getImportRegistry());
 }
 this.reader.loadBeanDefinitions(configClasses);
 alreadyParsed.addAll(configClasses);
 
 // 省略。。。。
 }

前面一大段主要是拿到合格的Configuration配置類,主要邏輯是在ConfigurationClassParser.parse方法中,該方法完成了對(duì)@Component、@Bean、@Import、@ComponentScans等注解的解析,這里主要看對(duì)@Import的解析,其它的讀者可自行分析。

一步步追蹤,最終會(huì)進(jìn)入到processConfigurationClass方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
 
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
if (configClass.isImported()) {
if (existingClass.isImported()) {
 existingClass.mergeImportedBy(configClass);
}
// Otherwise ignore new imported config class; existing non-imported class overrides it.
return;
}
else {
// Explicit bean definition found, probably replacing an import.
// Let's remove the old one and go with the new one.
this.configurationClasses.remove(configClass);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
}
 
// Recursively process the configuration class and its superclass hierarchy.
SourceClass sourceClass = asSourceClass(configClass);
do {
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
 
this.configurationClasses.put(configClass, configClass);
}

這里需要注意this.conditionEvaluator.shouldSkip方法的調(diào)用,這個(gè)方法就是進(jìn)行Bean加載過(guò)濾的,即根據(jù)@Condition注解的匹配值判斷是否加載該Bean,具體實(shí)現(xiàn)稍后分析,繼續(xù)跟蹤主流程doProcessConfigurationClass:

?
1
2
3
4
5
6
7
8
9
10
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
省略....
 
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), true);
 
省略....
return null;
}

這里就是完成對(duì)一系列注解的支撐,我省略掉了,主要看processImports方法,這個(gè)方法就是處理@Import注解的:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
 
if (importCandidates.isEmpty()) {
return;
}
 
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
 if (candidate.isAssignable(ImportSelector.class)) {
 // Candidate class is an ImportSelector -> delegate to it to determine imports
 Class<?> candidateClass = candidate.loadClass();
 ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
 this.environment, this.resourceLoader, this.registry);
 if (selector instanceof DeferredImportSelector) {
 this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
 }
 else {
 String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
 Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
 processImports(configClass, currentSourceClass, importSourceClasses, false);
 }
 }
 else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
 Class<?> candidateClass = candidate.loadClass();
 ImportBeanDefinitionRegistrar registrar =
 ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
  this.environment, this.resourceLoader, this.registry);
 configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
 }
 else {
 this.importStack.registerImport(
 currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
 processConfigurationClass(candidate.asConfigClass(configClass));
 }
}
}
}
}

剛剛我提醒過(guò)AutoConfigurationImportSelector是實(shí)現(xiàn)DeferredImportSelector接口的,如果不是該接口的實(shí)現(xiàn)類則是直接調(diào)用selectImports方法,反之則是調(diào)用DeferredImportSelectorHandler.handle方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>();
 
public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(
 configClass, importSelector);
if (this.deferredImportSelectors == null) {
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
handler.register(holder);
handler.processGroupImports();
}
else {
this.deferredImportSelectors.add(holder);
}
}

首先創(chuàng)建了一個(gè)DeferredImportSelectorHolder對(duì)象,如果是第一次執(zhí)行則是添加到deferredImportSelectors屬性中,等到ConfigurationClassParser.parse的最后調(diào)用process方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public void parse(Set<BeanDefinitionHolder> configCandidates) {
省略.....
 
this.deferredImportSelectorHandler.process();
}
 
public void process() {
List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
this.deferredImportSelectors = null;
try {
if (deferredImports != null) {
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
deferredImports.forEach(handler::register);
handler.processGroupImports();
}
}
finally {
this.deferredImportSelectors = new ArrayList<>();
}
}

反之則是直接執(zhí)行,首先通過(guò)register拿到AutoConfigurationGroup對(duì)象:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void register(DeferredImportSelectorHolder deferredImport) {
Class<? extends Group> group = deferredImport.getImportSelector()
.getImportGroup();
DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent(
(group != null ? group : deferredImport),
key -> new DeferredImportSelectorGrouping(createGroup(group)));
grouping.add(deferredImport);
this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
deferredImport.getConfigurationClass());
}
 
public Class<? extends Group> getImportGroup() {
return AutoConfigurationGroup.class;
}

然后在processGroupImports方法中進(jìn)行真正的處理:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public void processGroupImports() {
for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
grouping.getImports().forEach(entry -> {
 ConfigurationClass configurationClass = this.configurationClasses.get(
 entry.getMetadata());
 try {
 processImports(configurationClass, asSourceClass(configurationClass),
 asSourceClasses(entry.getImportClassName()), false);
 }
 catch (BeanDefinitionStoreException ex) {
 throw ex;
 }
 catch (Throwable ex) {
 throw new BeanDefinitionStoreException(
 "Failed to process import candidates for configuration class [" +
  configurationClass.getMetadata().getClassName() + "]", ex);
 }
});
}
}
 
public Iterable<Group.Entry> getImports() {
for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
this.group.process(deferredImport.getConfigurationClass().getMetadata(),
 deferredImport.getImportSelector());
}
return this.group.selectImports();
}

在getImports方法中就完成了對(duì)process和selectImports方法的調(diào)用,拿到自動(dòng)配置類后再遞歸調(diào)用調(diào)用processImports方法完成對(duì)自動(dòng)配置類的加載。

至此,自動(dòng)配置的加載過(guò)程就分析完了,下面是時(shí)序圖:

基于SpringBoot核心原理(自動(dòng)配置、事件驅(qū)動(dòng)、Condition)

Condition注解原理

在自動(dòng)配置類中有很多Condition相關(guān)的注解,以AOP為例:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {
 
 @Configuration(proxyBeanMethods = false)
 @ConditionalOnClass(Advice.class)
 static class AspectJAutoProxyingConfiguration {
 
 @Configuration(proxyBeanMethods = false)
 @EnableAspectJAutoProxy(proxyTargetClass = false)
 @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
 matchIfMissing = false)
 static class JdkDynamicAutoProxyConfiguration {
 
 }
 
 @Configuration(proxyBeanMethods = false)
 @EnableAspectJAutoProxy(proxyTargetClass = true)
 @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
 matchIfMissing = true)
 static class CglibAutoProxyConfiguration {
 
 }
 }
 
 @Configuration(proxyBeanMethods = false)
 @ConditionalOnMissingClass("org.aspectj.weaver.Advice")
 @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
 matchIfMissing = true)
 static class ClassProxyingConfiguration {
 
 ClassProxyingConfiguration(BeanFactory beanFactory) {
 if (beanFactory instanceof BeanDefinitionRegistry) {
 BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
 AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
 AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
 }
 }
 
 }
 
}

這里就能看到@ConditionalOnProperty、@ConditionalOnClass、@ConditionalOnMissingClass,另外還有@ConditionalOnBean、@ConditionalOnMissingBean等等很多條件匹配注解。這些注解表示條件匹配才會(huì)加載該Bean,以@ConditionalOnProperty為例,表明配置文件中符合條件才會(huì)加載對(duì)應(yīng)的Bean,prefix表示在配置文件中的前綴,name表示配置的名稱,havingValue表示配置為該值時(shí)才匹配,matchIfMissing則是表示沒(méi)有該配置是否默認(rèn)加載對(duì)應(yīng)的Bean。

其它注解可類比理解記憶,下面主要來(lái)分析該注解的實(shí)現(xiàn)原理。

這里注解點(diǎn)進(jìn)去看會(huì)發(fā)現(xiàn)每個(gè)注解上都標(biāo)注了@Conditional注解,并且value值都對(duì)應(yīng)一個(gè)類,比如OnBeanCondition,而這些類都實(shí)現(xiàn)了Condition接口,看看其繼承體系:

基于SpringBoot核心原理(自動(dòng)配置、事件驅(qū)動(dòng)、Condition)

上面只展示了幾個(gè)實(shí)現(xiàn)類,但實(shí)際上Condition的實(shí)現(xiàn)類是非常多的,我們還可以自己實(shí)現(xiàn)該接口來(lái)擴(kuò)展@Condition注解。

Condition接口中有一個(gè)matches方法,這個(gè)方法返回true則表示匹配。該方法在ConfigurationClassParser中多處都有調(diào)用,也就是剛剛我提醒過(guò)的shouldSkip方法,具體實(shí)現(xiàn)是在ConditionEvaluator類中:

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
 if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
 return false;
 }
 
 if (phase == null) {
 if (metadata instanceof AnnotationMetadata &&
  ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
 return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
 }
 return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
 }
 
 List<Condition> conditions = new ArrayList<>();
 for (String[] conditionClasses : getConditionClasses(metadata)) {
 for (String conditionClass : conditionClasses) {
 Condition condition = getCondition(conditionClass, this.context.getClassLoader());
 conditions.add(condition);
 }
 }
 
 AnnotationAwareOrderComparator.sort(conditions);
 
 for (Condition condition : conditions) {
 ConfigurationPhase requiredPhase = null;
 if (condition instanceof ConfigurationCondition) {
 requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
 }
 if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
 return true;
 }
 }
 
 return false;
 }

再來(lái)看看matches的實(shí)現(xiàn),但OnBeanCondition類中沒(méi)有實(shí)現(xiàn)該方法,而是在其父類SpringBootCondition中:

?
1
2
3
4
5
6
7
8
public final boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String classOrMethodName = getClassOrMethodName(metadata);
try {
ConditionOutcome outcome = getMatchOutcome(context, metadata);
logOutcome(classOrMethodName, outcome);
recordEvaluation(context, classOrMethodName, outcome);
return outcome.isMatch();
}

getMatchOutcome方法也是一個(gè)模板方法,具體的匹配邏輯就在這個(gè)方法中實(shí)現(xiàn),該方法返回的ConditionOutcome對(duì)象就包含了是否匹配和日志消息兩個(gè)字段。進(jìn)入到OnBeanCondition類中:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
ConditionMessage matchMessage = ConditionMessage.empty();
MergedAnnotations annotations = metadata.getAnnotations();
if (annotations.isPresent(ConditionalOnBean.class)) {
Spec<ConditionalOnBean> spec = new Spec<>(context, metadata, annotations, ConditionalOnBean.class);
MatchResult matchResult = getMatchingBeans(context, spec);
if (!matchResult.isAllMatched()) {
String reason = createOnBeanNoMatchReason(matchResult);
return ConditionOutcome.noMatch(spec.message().because(reason));
}
matchMessage = spec.message(matchMessage).found("bean", "beans").items(Style.QUOTE,
 matchResult.getNamesOfAllMatches());
}
if (metadata.isAnnotated(ConditionalOnSingleCandidate.class.getName())) {
Spec<ConditionalOnSingleCandidate> spec = new SingleCandidateSpec(context, metadata, annotations);
MatchResult matchResult = getMatchingBeans(context, spec);
if (!matchResult.isAllMatched()) {
return ConditionOutcome.noMatch(spec.message().didNotFind("any beans").atAll());
}
else if (!hasSingleAutowireCandidate(context.getBeanFactory(), matchResult.getNamesOfAllMatches(),
 spec.getStrategy() == SearchStrategy.ALL)) {
return ConditionOutcome.noMatch(spec.message().didNotFind("a primary bean from beans")
 .items(Style.QUOTE, matchResult.getNamesOfAllMatches()));
}
matchMessage = spec.message(matchMessage).found("a primary bean from beans").items(Style.QUOTE,
 matchResult.getNamesOfAllMatches());
}
if (metadata.isAnnotated(ConditionalOnMissingBean.class.getName())) {
Spec<ConditionalOnMissingBean> spec = new Spec<>(context, metadata, annotations,
 ConditionalOnMissingBean.class);
MatchResult matchResult = getMatchingBeans(context, spec);
if (matchResult.isAnyMatched()) {
String reason = createOnMissingBeanNoMatchReason(matchResult);
return ConditionOutcome.noMatch(spec.message().because(reason));
}
matchMessage = spec.message(matchMessage).didNotFind("any beans").atAll();
}
return ConditionOutcome.match(matchMessage);
}

可以看到該類支持了@ConditionalOnBean、@ConditionalOnSingleCandidate、@ConditionalOnMissingBean注解,主要的匹配邏輯在getMatchingBeans方法中:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
protected final MatchResult getMatchingBeans(ConditionContext context, Spec<?> spec) {
ClassLoader classLoader = context.getClassLoader();
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
boolean considerHierarchy = spec.getStrategy() != SearchStrategy.CURRENT;
Set<Class<?>> parameterizedContainers = spec.getParameterizedContainers();
if (spec.getStrategy() == SearchStrategy.ANCESTORS) {
BeanFactory parent = beanFactory.getParentBeanFactory();
Assert.isInstanceOf(ConfigurableListableBeanFactory.class, parent,
 "Unable to use SearchStrategy.ANCESTORS");
beanFactory = (ConfigurableListableBeanFactory) parent;
}
MatchResult result = new MatchResult();
Set<String> beansIgnoredByType = getNamesOfBeansIgnoredByType(classLoader, beanFactory, considerHierarchy,
spec.getIgnoredTypes(), parameterizedContainers);
for (String type : spec.getTypes()) {
Collection<String> typeMatches = getBeanNamesForType(classLoader, considerHierarchy, beanFactory, type,
 parameterizedContainers);
typeMatches.removeAll(beansIgnoredByType);
if (typeMatches.isEmpty()) {
result.recordUnmatchedType(type);
}
else {
result.recordMatchedType(type, typeMatches);
}
}
for (String annotation : spec.getAnnotations()) {
Set<String> annotationMatches = getBeanNamesForAnnotation(classLoader, beanFactory, annotation,
 considerHierarchy);
annotationMatches.removeAll(beansIgnoredByType);
if (annotationMatches.isEmpty()) {
result.recordUnmatchedAnnotation(annotation);
}
else {
result.recordMatchedAnnotation(annotation, annotationMatches);
}
}
for (String beanName : spec.getNames()) {
if (!beansIgnoredByType.contains(beanName) && containsBean(beanFactory, beanName, considerHierarchy)) {
result.recordMatchedName(beanName);
}
else {
result.recordUnmatchedName(beanName);
}
}
return result;
}

這里邏輯看起來(lái)比較復(fù)雜,但實(shí)際上就做了兩件事,首先通過(guò)getNamesOfBeansIgnoredByType方法調(diào)用beanFactory.getBeanNamesForType拿到容器中對(duì)應(yīng)的Bean實(shí)例,然后根據(jù)返回的結(jié)果判斷哪些Bean存在,哪些Bean不存在(Condition注解中是可以配置多個(gè)值的)并返回MatchResult對(duì)象,而MatchResult中只要有一個(gè)Bean沒(méi)有匹配上就返回false,也就決定了當(dāng)前Bean是否需要實(shí)例化。

總結(jié)

本篇分析了SpringBoot核心原理的實(shí)現(xiàn),通過(guò)本篇相信讀者也將能更加熟練地使用和擴(kuò)展SpringBoot。另外還有一些常用的組件我沒(méi)有展開(kāi)分析,如事務(wù)、MVC、監(jiān)聽(tīng)器的自動(dòng)配置,這些我們有了Spring源碼基礎(chǔ)的話下來(lái)看一下就明白了,這里就不贅述了。最后讀者可以思考一下我們應(yīng)該如何自定義starter啟動(dòng)器,相信看完本篇應(yīng)該難不倒你。

以上這篇基于SpringBoot核心原理(自動(dòng)配置、事件驅(qū)動(dòng)、Condition)就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持服務(wù)器之家。

原文鏈接:https://blog.csdn.net/l6108003/article/details/106966386

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 羞羞视频在线看 | 成人片网址 | 中文字幕日本一区二区 | 91精品免费在线观看 | 毛片免费观看网址 | 免费a视频在线观看 | 精品国产欧美一区二区三区成人 | 视频一区中文字幕 | 日本三级中文在线电影 | 欧美日本在线 | 久久久一二三 | 毛片一级网站 | 深夜在线 | 国产精品久久久久久婷婷天堂 | 激情在线视频 | 亚洲男人在线 | 黄色一级视频在线观看 | 中文字幕日产乱码六区小草 | 亚洲精品日韩激情在线电影 | 亚洲一区二区在线播放 | 亚洲天堂一区 | 亚洲国产婷婷香蕉久久久久久99 | 亚洲二区在线 | 久久久久久久一区 | 成人一区二区在线 | 欧美极品一区二区 | 久久国产免费 | 日韩免费在线观看 | 精品久久久久久久久久 | 欧美综合在线观看 | 天天爽夜夜爽夜夜爽精品视频 | 国产三级一区二区 | 成人av免费观看 | 91九色在线| 五月婷婷综合网 | 91人人 | 中文字幕高清在线观看 | 欧美乱大交xxxxx春色视频 | 中文在线一区二区 | 久草福利在线视频 | 久久久久久99 |