版权声明:本文为CSDN博主「大神,快来碗里」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处连接及本声明。
原文连接:https://blog.csdn.net/cowbin2012/article/details/88861160面试
Spring Boot方式的项目开发已经逐步成为Java应用开发领域的主流框架,它不只能够方便地建立生产级的Spring应用程序,还能轻松地经过一些注解配置与目前比较流行的微服务框架SpringCloud快速地集成。
在咱们实际使用Spring Boot进行项目开发的过程当中,每每只须要几个很简单的注解配置就可以将应用启动运行了,相比于传统的Spring项目而已,这种提高大大地提升了咱们的研发效率。然而,这种便捷性则是经过高度地上层封装来实现的,如:大量的注解封装、约定大于配置的原则等手段。因此,也许你已经使用Spring Boot开发不少个项目了,但对Spring Boot的运行原理真的搞清楚了吗?若是,面试中有人问你Spring Boot的实现原理是什么?你能正确地回答出来吗?
与大部分其余框架及技术的使用场景同样,咱们每每过多地专一于使用层面,以便快速地完成业务开发,却每每忽略了对框架底层运行原理的关注,因此面试中被怼也就不足为奇了。不过不要紧,在今天的文章中,小码哥将为你们全方位地梳理下Spring Boot的底层运行原理,并经过图文结合的方式给你们进行展现,但愿对您的工做或者面试可以有所帮助!
Spring Boot运行原理
实际上Spring Boot并非要替代Spring框架,咱们知道在JDK1.5推出注解功能之后,Spring框架实现了大量的注解来替代原有的基于XML的配置,主要用于配置管理、Bean的注入以及AOP等相关功能的实现。然而,随着Spring注解的数量愈来愈多,而且被大量的使用,尤为是相同的多个注解会被大量重复地用到各个类或者方法中。这样就致使了繁琐的配置及大量冗余的代码。
到这里你也许就会想到既然这么多Spring注解很繁琐,那么可不能够将其组合一下呢?经过定义一些新的注解,将功能进行分类,不一样的Spring注解经过新的注解定义进行必定的组合,这样对于大部分通用场景下,只须要引入一个新的注解,就自动包含了与之相关的其余Spring注解?没错!Spring Boot说到底就是这么个玩意!
可是,要实现注解的组合并非简单的把多个注解牵强的叠加在一块儿,这里涉及到一些编程语言上的实现,例如要组合一个注解,那么该注解是否支持注解到别的注解上呢(略微有点拗口)?还有若是组合注解后,由于注解的背后还涉及到Spring容器上下文的初始化以及Bean注入相关的逻辑,若是一个A注解涉及的Bean,涉及到另一个B注解涉及到的Bean的初始化;也就意味着A注解的Bean初始化,须要在B注解的Bean初始化完成后才能进行注入,不然就会致使Bean依赖注入的失败。
Spring Boot框架本质上就是经过组合注解的方式实现了诸多Spring注解的组合,从而极大地简化了Spring框架自己的繁琐配置,实现快速的集成和开发。只是要这样实现,也须要必定的基础条件!
元注解
说到底Spring Boot框架是在Spring框架的基础上作了一层二次封装,最重要的特色就是Spring Boot框架定义了一些新的注解来实行一些Spring注解的组合,而Spring注解则是基于JDK1.5+后的注解功能的支持来完成的。
关于JDK的注解若是想要注解到别的注解上,就须要将其定义为元注解,所谓的元注解,就是能够注解到其余注解上的注解,被注解的注解就是咱们上面说到的组合注解。而Spring框架的不少注解都是能够做为元注解的,而且Spring框架自己也实现了不少组合注解,例如咱们经常使用的注解@Configuration就是一个这样的组合注解。所以,有了这样一个条件Spring Boot的实现才有了基础条件!
条件注解@Conditional
Spring 4提供了一个通用的基于条件的注解@Conditional。该注解能够根据知足某一个特定条件与否来决定是否建立某个特定的Bean,例如,某个依赖包jar在一个类路径的时候,自动配置一个或多个Bean时,能够经过注解@Conditional注解来实现只有某个Bean被建立时才会建立另一个Bean,这样就能够依据特定的条件来控制Bean的建立行为,这样的话咱们就能够利用这样一个特性来实现一些自动的配置。
而这一点对于Spring Boot实现自动配置来讲是一个核心的基础能力,从本质上来讲Spring Boot之因此能够实现自动注解配置很大程度上也是基于这一能力。在Spring Boot中以@Conditional为元注解又从新定义了一组针对不一样场景的组合条件注解,它们分别是:
@ConditionalOnBean:当容器中有指定Bean的条件下进行实例化。
@ConditionalOnMissingBean:当容器里没有指定Bean的条件下进行实例化。
@ConditionalOnClass:当classpath类路径下有指定类的条件下进行实例化。
@ConditionalOnMissingClass:当类路径下没有指定类的条件下进行实例化。
@ConditionalOnWebApplication:当项目是一个Web项目时进行实例化。
@ConditionalOnNotWebApplication:当项目不是一个Web项目时进行实例化。
@ConditionalOnProperty:当指定的属性有指定的值时进行实例化。
@ConditionalOnExpression:基于SpEL表达式的条件判断。
@ConditionalOnJava:当JVM版本为指定的版本范围时触发实例化。
@ConditionalOnResource:当类路径下有指定的资源时触发实例化。
@ConditionalOnJndi:在JNDI存在的条件下触发实例化。
@ConditionalOnSingleCandidate:当指定的Bean在容器中只有一个,或者有多个可是指定了首选的Bean时触发实例化。
纵观Spring Boot的一些核心注解,基于注解@Conditional元注解的组合注解就占了很大部分,因此Spring Boot的核心功能基于就是这些注解实现的。在Spring Boot源码项目“spring-boot-autoconfigure”中,随意打开一个AutoConfiguration文件,咱们都会看到有上述条件注解的使用。如:
@Configuration
@ConditionalOnClass(DSLContext.class)
@ConditionalOnBean(DataSource.class)
@AutoConfigureAfter({ DataSourceAutoConfiguration.class,
TransactionAutoConfiguration.class })
public class JooqAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public DataSourceConnectionProvider dataSourceConnectionProvider(
DataSource dataSource) {
return new DataSourceConnectionProvider(
new TransactionAwareDataSourceProxy(dataSource));
}
@Bean
@ConditionalOnBean(PlatformTransactionManager.class)
public SpringTransactionProvider transactionProvider(
PlatformTransactionManager txManager) {
return new SpringTransactionProvider(txManager);
}
....
}spring
Spring Boot运行原理
在前面的篇幅中咱们重点阐述了为何Spring Boot能够实现高度地自动化配置。那么,接下来咱们就结合Spring Boot最核心的组合注解@SpringBootApplication来分析下Spring Boot的项目究竟是怎么启动运行的。
在这里插入图片描述
@SpringBootApplication注解其实是一个组合注解,除了对应用开放的@ComponentScan注解(实现对开发者自定义的应用包扫描)外,其最核心的注解就是注解@EnableAutoConfiguration,该注解表示开启自动配置功能,而在具体的实现上则是经过导入注解@Import(EnableAutoConfigurationImportSelector.class)类的实例,在逻辑上实现了对所依赖的核心jar下META-INF/spring.factories文件的扫描,该文件则声明了有哪些自动配置须要被Spring容器加载,从而Spring Boot应用程序就能自动加载Spring核心容器配置,以及其余依赖的项目组件配置,从而最终完成应用的自动初始化,经过这种方法就向开发者屏蔽了启动加载的过程。
如“spring-boot-autoconfigure”核心包中的META-INF/spring.factories文件就是定义了须要加载的Spring Boot项目所依赖的基础配置类,如Spring的容器初始化配置类等。如:
# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer
.....编程
而对于大部分第三方须要与Spring Boot集成的框架,或者咱们平常开发中须要进行抽象的公共组件而言,得益于这种机制,也能够很容易地定制成开箱即用的各类Starter组件。而使用这些组件的用户,每每只须要将依赖引入就好,再也不须要进行任何额外的配置了!
Spring Boot后记
以上就是Spring Boot运行的基本原理了,但愿这篇文章可以对你有所帮助!实际上学习Spring Boot进行项目开发关键就是要掌握各类Spring及Spring Boot的各类注解,特别是一些关键核心注解。一样在进行基于Spring Cloud微服务的开发中,也是须要理解Spring Cloud相关组件所提供的各类核心注解,只有这样才能更好的理解框架的原理及使用,而不仅是云里雾里地进行各类似懂非懂的Copy开发。
框架