SpringBoot:认认真真梳理一遍自动装配原理(上)

简介: SpringBoot:认认真真梳理一遍自动装配原理(上)

前言


Spring翻译为中文是“春天”,的确,在某段时间内,它给Java开发人员带来过春天,但是随着我们项目规模的扩大,Spring需要配置的地方就越来越多,夸张点说,“配置两小时,Coding五分钟”。这种纷繁复杂的xml配置随着软件行业一步步地发展,必将逐步退出历史舞台。


SpringBoot介绍


来自:百度百科


Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Spring Boot致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者。


SpringBoot所具备的特征有:


  • 可以创建独立的Spring应用程序,并且基于其Maven或Gradle插件,可以创建可执行的JARs和WARs;
  • 内嵌Tomcat或Jetty等Servlet容器;
  • 提供自动配置的“starter”项目对象模型(POMS)以简化Maven配置;
  • 尽可能自动配置Spring容器;
  • 提供准备好的特性,如指标、健康检查和外部化配置;
  • 绝对没有代码生成,不需要XML配置。


自己的理解:


SpringBoot,顾名思义,给人的感觉就是让Spring启动的这么一个项目。在过去,我们要让一个Spring项目启动,往往需要配置很多的xml配置文件,但是在使用SpringBoot之后,我们甚至无需写一行xml,就可以直接将整个项目启动,这种“零配置”的做法减轻了开发人员很多的工作量,可以让开发人员一心扑在业务逻辑的设计上,使项目的逻辑更加完善。


除此之外,其采用了JavaConfig的配置风格,导入组件的方式也由原来的直接配置改为@EnableXXXX,这种纯Java代码的配置和导入组件的方式,使代码看上去更加的优雅,所以SpringBoot如今受到大小公司和大多数程序员的青睐,不是没有原因的。


SpringBoot之所以可以做到简化配置文件直接启动,无外乎是其内部的两种设计策略:开箱即用和约定大于配置


开箱即用:在开发过程中,通过maven项目的pom文件中添加相关依赖包,然后通过相应的注解来代替繁琐的XML配置以管理对象的生命周期。


约定大于配置:由SpringBoot本身来配置目标结构,由开发者在结构中添加信息的软件设计范式。这一特点虽降低了部分灵活性,增加了BUG定位的复杂性,但减少了开发人员需要做出决定的数量,同时减少了大量的XML配置,并且可以将代码编译、测试和打包等工作自动化。


那么在这篇博客中,我们需要了解的所有东西,就应该从这两个特点出发,一步一步深入SpringBoot自动装配的原理。


开箱即用原理


要理解这一特点,首先要先自己体会开箱即用的整个过程带来的便利。


体验开箱即用


SpringBoot提供了我们快速创建SpringBoot项目的地方:https://start.spring.io/

我们只需要在这个网页中把整个项目起好名字,然后选好我们需要的组件,就可以直接获得一个可以跑起来的SpringBoot项目。


image.png


我们只需要填完上述信息,点击Generate,就可以直接将一个SpringBoot项目下载下来,然后导入我们的IDE,Eclipse或者IDEA都可,之后就可以直接将它运行起来。


全项目结构:



image.png


启动:


image.png


访问:http://localhost:8080/



image.png


代表整个SpringBoot项目启动成功。


开箱即用原理剖析


对比SSM配置


其实在上文的开箱即用中,我们相当于引入了一个SpringMVC的组件,但是大家可以看到,我们没有经过任何的配置就将项目启动了。反观过去SSM框架的SpringMVC配置,我这里有一份留存的大家可以对比一下。


spring-web.xml:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
    <!-- 配置SpringMVC -->
    <!-- 1.开启SpringMVC注解模式 -->
    <!-- 简化配置: (1)自动注册DefaultAnootationHandlerMapping,AnotationMethodHandlerAdapter
        (2)提供一些列:数据绑定,数字和日期的format @NumberFormat, @DateTimeFormat, xml,json默认读写支持 -->
    <mvc:annotation-driven />
    <!-- 2.静态资源默认servlet配置 (1)加入对静态资源的处理:js,gif,png (2)允许使用"/"做整体映射 -->
    <mvc:resources mapping="/resources/**" location="/resources/" />
    <mvc:default-servlet-handler />
    <!-- 3.定义视图解析器 -->
    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/html/"></property>
        <property name="suffix" value=".html"></property>
    </bean>
    <!-- 文件上传解析器 -->
    <bean id="multipartResolver"
        class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="defaultEncoding" value="utf-8"></property>
        <property name="maxUploadSize" value="10485760000"></property><!-- 最大上传文件大小 -->
        <property name="maxInMemorySize" value="20971520"></property>
    </bean>
    <!-- 在spring-mvc.xml文件中加入这段配置后,spring返回给页面的都是utf-8编码了 -->
    <bean
        class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="messageConverters">
            <list>
                <bean
                    class="org.springframework.http.converter.StringHttpMessageConverter">
                    <property name="supportedMediaTypes">
                        <list>
                            <value>text/html;charset=UTF-8</value>
                        </list>
                    </property>
                </bean>
            </list>
        </property>
    </bean>
    <!-- 4.扫描web相关的bean -->
    <context:component-scan base-package="com.SchoolShop.o2o.web" />
    <!-- 5.权限拦截器 -->
</beans>


web.xml:


<servlet>
      <servlet-name>spring-dispatcher</servlet-name>
      <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
      <init-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>classpath:spring/spring-*.xml</param-value>
      </init-param>
  </servlet>
  <servlet-mapping>
      <servlet-name>spring-dispatcher</servlet-name>
      <!-- 默认匹配所有请求 -->
      <url-pattern>/</url-pattern>
  </servlet-mapping>


可以看到,这里需要配置两个文件,web.xml和spring-web.xml,配置可以说是相当繁重。


那么相对于这个,SpringBoot的开箱即用就显得特别方便,那么我们着重聊聊SpringBoot开箱即用的原理。


从pom.xml开始


SpringBoot的项目都会存在一个父依赖,按住Ctrl+鼠标左键,可以点进去。


<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.1.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>


点进去之后发现里面除了一些插件和配置文件的格式之外,还存在一个依赖。


<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.2.1.RELEASE</version>
    <relativePath>../../spring-boot-dependencies</relativePath>
</parent>


于是再点进去,可以发现里面放了很多的依赖和依赖的版本号。由于这个文件实在太长了,所以这里只展示一部分。


image.png


image.png


所以我们可以得出第一个结论:


spring-boot-dependencies:作为父工程,存放了SpringBoot的核心依赖。我们在写或者引入一些SpringBoot依赖的时候,不需要指定版本,正是因为SpringBoot的父依赖已经帮我们维护了一套版本。


另外我们还可以看到,在父依赖中也帮我们写好了资源库,不用我们自己再去配置了。


<resources>
      <resource>
        <filtering>true</filtering>
        <directory>${basedir}/src/main/resources</directory>
        <includes>
            <!-- 可以读取的配置文件有
                application.yml/application.yaml/application.properties
             -->
          <include>**/application*.yml</include>
          <include>**/application*.yaml</include>
          <include>**/application*.properties</include>
        </includes>
      </resource>
      <resource>
        <directory>${basedir}/src/main/resources</directory>
        <excludes>
          <exclude>**/application*.yml</exclude>
          <exclude>**/application*.yaml</exclude>
          <exclude>**/application*.properties</exclude>
        </excludes>
      </resource>
</resources>


启动器


<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
    <version>2.2.1.RELEASE</version>
</dependency>


启动器就是SpringBoot的启动场景,比如我们要使用web相关的,那么就直接引入spring-boor-starter-web,那么他就会帮我们自动导入web环境下所有必需的依赖。


我们来看看启动器中存放了一些什么内容:


以spring-boot-starter为例:


<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot</artifactId>
      <version>2.2.1.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-autoconfigure</artifactId>
      <version>2.2.1.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-logging</artifactId>
      <version>2.2.1.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>jakarta.annotation</groupId>
      <artifactId>jakarta.annotation-api</artifactId>
      <version>1.3.5</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>5.2.1.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.yaml</groupId>
      <artifactId>snakeyaml</artifactId>
      <version>1.25</version>
      <scope>runtime</scope>
    </dependency>


其中存放了自动配置相关的依赖、日志相关依赖、还有Spring-core等依赖,这些依赖我们只需要导入一个spring-boor-starter就可以直接将其全部引入,而不需要再像以前那样逐个导入了。



相关文章
|
3天前
|
安全 Java 数据安全/隐私保护
SpringBoot实现二维码扫码登录的原理与详细步骤
SpringBoot实现二维码扫码登录的原理与详细步骤
122 1
|
3天前
|
XML Java 开发者
Spring Boot中的bean注入方式和原理
Spring Boot中的bean注入方式和原理
134 0
|
3天前
|
缓存 Java Maven
Spring Boot自动配置原理
Spring Boot自动配置原理
52 0
|
3天前
|
前端开发 搜索推荐 Java
【Spring底层原理高级进阶】基于Spring Boot和Spring WebFlux的实时推荐系统的核心:响应式编程与 WebFlux 的颠覆性变革
【Spring底层原理高级进阶】基于Spring Boot和Spring WebFlux的实时推荐系统的核心:响应式编程与 WebFlux 的颠覆性变革
|
2天前
|
Java 开发者 Spring
springboot @RequiredArgsConstructor @Lazy解决循环依赖的原理
【5月更文挑战第16天】在Spring Boot中,@RequiredArgsConstructor 和 @Lazy 是两个有用的注解,它们分别用于简化构造函数的生成和控制Bean的加载时间。下面详细解析这两个注解的概念、优缺点以及在实际应用中的示例。
5 1
|
3天前
|
XML Java 开发者
springboot 启动原理、启动过程、启动机制的介绍
【5月更文挑战第13天】Spring Boot 是一种基于 Java 的框架,用于创建独立的、生产级别的 Spring 应用程序。它的主要目标是简化 Spring 应用的初始搭建和开发过程,同时提供一系列大型项目常见的非功能性特征(如嵌入式服务器、安全性、度量、健康检查和外部化配置)。
18 3
|
3天前
|
XML Java 数据库
【SpringBoot:详解Bean装配】
【SpringBoot:详解Bean装配】
11 3
|
3天前
|
Java
SpringBoot之@Conditional衍生条件装配详解
SpringBoot之@Conditional衍生条件装配详解
|
3天前
|
Java Spring 容器
SpringBoot自动装配原理之@Import注解解析
SpringBoot自动装配原理之@Import注解解析
55 0
|
3天前
|
JSON Java Maven
Javaweb之SpringBootWeb案例之 SpringBoot原理的详细解析
Javaweb之SpringBootWeb案例之 SpringBoot原理的详细解析
45 0
Javaweb之SpringBootWeb案例之 SpringBoot原理的详细解析