博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SpringBoot~解决三个疑惑,为什么pom.xml文件中导入依赖不需要版本? 它是如何实现自动配置的? 它是如何启动运行的?
阅读量:4051 次
发布时间:2019-05-25

本文共 6729 字,大约阅读时间需要 22 分钟。

文章目录

为什么pom.xml文件中导入依赖并不需要版本?

  • SpringBoot归根结底是一个Maven项目,我们一般从pom.xml文件探究起;在以前无论是Javaweb还是SSM我们在pom.xml文件中导入依赖都需要实现其版本, 但是在SpringBoot项目中没有版本, 但是他有了一个父依赖
org.springframework.boot
spring-boot-starter-parent
2.2.11.RELEASE
  • 点进去,发现还有一个父依赖
org.springframework.boot
spring-boot-dependencies
2.2.11.RELEASE
../../spring-boot-dependencies
  • 我们再点进行就会发现秘密

    在这里插入图片描述

  • 这里才是真正管理SpringBoot应用里面所有依赖版本的地方,SpringBoot的版本控制中心;

  • 在SpringBoot导入依赖默认是不需要写版本, 它会默认匹配自带的版本号;但是如果导入的包没有在依赖中管理着就需要手动配置版本了;

  • 在pom.xml中还有一个最重要的web启动器

org.springframework.boot
spring-boot-starter-web
  • springboot-boot-starter-xxx:就是spring-boot的场景启动器

  • spring-boot-starter-web:当我们创建SpringBoot项目选择了web依赖的时候, 系统就帮我们导入了web启动器正常运行所依赖的组件;

  • SpringBoot将所有的功能场景都抽取出来,做成一个个的starter (启动器),只需要在项目中引入这些starter即可,所有相关的依赖都会导入进来 , 我们要用什么功能就导入什么样的场景启动器即可

SpringBoot是如何实现自动配置的?

  • 我们接下来看主启动类
//通过这个注解, 标注这个类是一个SpringBoot的应用@SpringBootApplicationpublic class DemoApplication {
public static void main(String[] args) {
//启动SpringBoot SpringApplication.run(DemoApplication.class, args); }}
  • 他主要是通过一个注解 @SpringBootApplication 来表示这是主启动类, 还表明这是个SpringBoot项目
  • 进入这个注解:可以看到上面还有很多其他注解!
@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})})
  • @ComponentScan

    这个注解在Spring中很重要 ,它对应XML配置中的元素。作用:自动扫描并加载符合条件的组件或者bean , 将这个bean定义加载到IOC容器中

  • @SpringBootConfiguration

    作用:SpringBoot的配置类 ,标注在某个类上 , 表示这是一个SpringBoot的配置类;

我们继续进去这个注解查看

@Target({
ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Configurationpublic @interface SpringBootConfiguration {
@AliasFor( annotation = Configuration.class ) boolean proxyBeanMethods() default true;}
  • 进去之后我们发现这里有一个 @Configuration,说明这是一个配置类 ,配置类就是对应Spring的xml 配置文件;也就是这也只是一个SpringBoot的配置类, 我们再进去
@Target({
ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Componentpublic @interface Configuration {
@AliasFor( annotation = Component.class ) String value() default ""; boolean proxyBeanMethods() default true;}
  • 里面的 @Component 这就说明,启动类本身也是Spring中的一个组件而已,负责启动应用的时候去加载一些配置文件!

  • 我们回到 SpringBootApplication 注解中继续看。

  • 有一个 @EnableAutoConfiguration 我们顾名思义这应该是实现自动装配的配置注解, @EnableAutoConfiguration告诉SpringBoot开启自动配置功能,这样自动配置才能生效, 我们点进去看看

@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 {
};}
  • 发现有一个@AutoConfigurationPackage :自动配置包, 我们再点进去
@Import({
Registrar.class})public @interface AutoConfigurationPackage {
}
  • @import :Spring底层注解@import , 作用就是让Spring识别给容器中导入一个组件

  • Registrar.class 作用:将主启动类的所在包及包下面所有子包里面的所有组件扫描到Spring容器

  • 这个分析完了,退到上一步,继续看

  • @Import({AutoConfigurationImportSelector.class}) :给容器导入组件 AutoConfigurationImportSelector :自动配置导入选择器,那么它会导入哪些组件的选择器呢?我们点击去这个类看源码:

  • 进入这个类后我们更具方法名字很容易判断出这个类是在干什么, 若果想要知道更多可以继续点进行看, 但是我们会发现一个很重要的方法 getAutoConfigurationEntry 这个方法是获得自动配置的入口, 里面有一个方法 getCandidateConfigurations 获取候选配置

    在这里插入图片描述

  • 我们进入 getCandidateConfigurations 获取候选配置这个方法

    在这里插入图片描述

  • 我们再进去SpringFactoriesLoader 加载器中

在这里插入图片描述

  • 我们发现很多加载的地方都用到了一个字符串路径spring.factories, 好 我们搜索这个路径,就会发发现终极秘密
    在这里插入图片描述
  • 我们根据源头打开spring.factories , 看到了很多自动配置的文件;这就是自动配置根源所在!
    在这里插入图片描述
  • 我们打开我们使用的web的配置 WebMvcAutoConfiguration
@Configuration(    proxyBeanMethods = false)@ConditionalOnWebApplication(    type = Type.SERVLET)@ConditionalOnClass({
Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})@ConditionalOnMissingBean({
WebMvcConfigurationSupport.class})@AutoConfigureOrder(-2147483638)@AutoConfigureAfter({
DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class})public class WebMvcAutoConfiguration {
public static final String DEFAULT_PREFIX = ""; public static final String DEFAULT_SUFFIX = ""; private static final String[] SERVLET_LOCATIONS = new String[]{
"/"}; public WebMvcAutoConfiguration() {
} @Bean @ConditionalOnMissingBean({
HiddenHttpMethodFilter.class}) @ConditionalOnProperty( prefix = "spring.mvc.hiddenmethod.filter", name = {
"enabled"}, matchIfMissing = false )
  • 可以看到最开始使用了@Configuration表明这是一个JavaConfig配置类,而且个个组件都使用了@Bean注入到了Spring中
  • 这时我们就会发现貌似是这样的, 自动配置真正实现是从classpath中搜寻所有的META-INF/spring.factories配置文件 ,并将其中对应的 org.springframework.boot.autoconfigure. 包下的配置项,通过反射实例化 为对应标注了 @Configuration的JavaConfig形式的配置类 , 然后将这些都汇总成为一个实例并以Bean的形式加载到IOC容器中。
  • 那我们点开我们没有导入启动器的配置类又会如何
    在这里插入图片描述
  • 这个配置文件是不会生效的, 因为在其内部的注解需要的类是找不到, 那我们也可以这样想, 这个spring.factories文件中的所有配置类不会都实现, 只有导入了对应的启动器才会生效.

结论:

SpringBoot所有的自动配置 都是在启动的时候扫描并加载,META-INF/spring.factories中所有的内容, 但并不是所有的自动配置类都生效, 其内部会有一个判断条件, 判断条件是 是否导入了这个配置对应的start启动器, 如果导入了有了启动器才会进行自动配置

  1. SpringBoot在启动的时候, 从类路径下/META-INF/spring-factories获取指定的值
  2. 将这些自动配置的类导入容器,自动配置类就会生效, 帮我们进行自动配置
  3. 以前我们配置的那一堆东西, 现在都是springBoot帮我们做了
  4. 整合整个javaEE的所有解决方案和自动配置都在spring.autoconfigure-2.2.11.RELEASE.jar这个包下
  5. 他会把所有需要导入的组件一类名的方式返回 ,这些组件就会被添加到容器中
  6. 容器中又会有很多的XXXAutoConfiguation的文件(@Bean), 就是这些类给容器导入了某个场景需要的组件, 并自动配置 @Configuation
  7. 有了自动配置就省去了我们自动配置的麻烦事

它是如何启动运行的?

  • SpringApplication.run分析
  • SpringBoot的启动主要是通过实例化SpringApplication来启动的,启动过程主要做了以下几件事情
  1. 使用构造函数加载初初始化, 在这里他会判断是不是web项目, 如果是web项目就不会自动中断程序, 如果不是那等程序main结束就会结束这个程序
  2. 获取监听器,发布应用开始启动事件
  3. 初始化输入参数、配置环境,
  4. 输出banner、创建上下文、预处理上下文、刷新上下文、再刷新上下文、发布应用已经启动事件、发布应用启动完成事件。

在这里插入图片描述

  • 在SpringBoot中启动tomcat的工作在刷新上下这一步。而tomcat的启动主要是实例化两个组件:Connector、Container,一个tomcat实例就是一个Server,一个Server包含多个Service,也就是多个应用程序,每个Service包含多个Connector和一个Container,而一个Container下又包含多个子容器。

  • tomcat本身就是一个web容器, 他使用socket编程实现处理请求和返回响应的数据封装, 所以在springboot中就使用tomcat源码实现这个逻辑

  • 而其中我们常用的有两个:TomcatServletWebServerFactory和JettyServletWebServerFactory。

  • 开发阶段对我们来说使用内置的tomcat是非常够用了,当然也可以使用jetty。

  • getWebServer这个方法创建了Tomcat对象, 返回的就是一个TomcatWebServer。

  • tomcat结构图

    在这里插入图片描述

  • tomcat最顶层容器是Server,代表着整个服务器,一个Server包含多个Service。从上图可以看除Service主要包括多个Connector和一个Container。Connector用来处理连接相关的事情,并提供Socket到Request和Response相关转化。Container用于封装和管理Servlet,以及处理具体的Request请求。

  • 综上所述,一个tomcat只包含一个Server,一个Server可以包含多个Service,一个Service只有一个Container,但有多个Connector,这样一个服务可以处理多个连接。

  • 多个Connector和一个Container就形成了一个Service,有了Service就可以对外提供服务了,但是Service要提供服务又必须提供一个宿主环境,那就非Server莫属了,所以整个tomcat的声明周期都由Server控制。

转载地址:http://znsci.baihongyu.com/

你可能感兴趣的文章
利用HTTP Cache来优化网站
查看>>
利用负载均衡优化和加速HTTP应用
查看>>
消息队列设计精要
查看>>
分布式缓存负载均衡负载均衡的缓存处理:虚拟节点对一致性hash的改进
查看>>
分布式存储系统设计(1)—— 系统架构
查看>>
MySQL数据库的高可用方案总结
查看>>
常用排序算法总结(一) 比较算法总结
查看>>
SSH原理与运用
查看>>
SIGN UP BEC2
查看>>
S3C2440中对LED驱动电路的理解
查看>>
《天亮了》韩红
查看>>
Windows CE下USB摄像头驱动开发(以OV511为例,附带全部源代码以及讲解) [转]
查看>>
出现( linker command failed with exit code 1)错误总结
查看>>
iOS开发中一些常见的并行处理
查看>>
iOS获取手机的Mac地址
查看>>
ios7.1发布企业证书测试包的问题
查看>>
如何自定义iOS中的控件
查看>>
iOS 开发百问
查看>>
Mac环境下svn的使用
查看>>
github简单使用教程
查看>>