【spring-boot 源码解析】spring-boot 依赖管理

关键词:spring-boot 依赖管理、spring-boot-dependencies、spring-boot-parent

问题

maven 工程,依赖管理是非常基本又非常重要的功能,现在的工程越来越庞大,依赖越来越多,各种二方包、三方包太多太多,依赖冲突处理起来真是让人头疼,经常需要涉及到多个地方需要调整。

微信公众号:逸飞兮(专注于java知识领域的源码分析,从源码中理解框架/工具原理、验证CS专业知识)

解决方案

使用统一的依赖管理模块来管理工程中的所有依赖。

spring-boot 工程常使用 spring-boot-dependencies、spring-boot-starter-parent 管理工程依赖。

spring-boot 的最上级工程是 spring-boot-build,以下开始一步一步深入了解 spring-boot 依赖解决方案。

spring-boot 中的方案

spring-boot-build

spring-boot 的最上层工程,指定了 maven profiles、maven repositories、maven pluginRepositories、maven build pluginManagement。

  • profiles:中包含代码风格检查、代码风格 format;更方便导入 eclipse;maven 仓库
  • repositories:允许在开发过程中导入快照和里程碑 BOM。这个部分在 install/deploy 期间被 flatten 插件删除。包含 maven 中央仓库、spring 快照仓库、spring 里程碑仓库
  • pluginRepositories:插件仓库,包含 maven 中央仓库、spring 快照仓库、spring 里程碑仓库
  • pluginManagement:构建插件管理,这个插件的配置只用于存储 Eclipse m2e 设置,它对 Maven 构建本身没有影响。

spring-boot-dependencies

dependencies 的父工程是spring-boot-build,不包含代码,只用 pom 来管理依赖,pom.xml 如下:

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-build</artifactId>
        <version>${revision}</version>
        <relativePath>../..</relativePath>
</parent>
<artifactId>spring-boot-dependencies</artifactId>
<packaging>pom</packaging>
<dependencyManagement>
  <!-- 省略具体依赖管理 -->
</dependencyManagement>
<build>
  <pluginManagement>
    <!-- 省略具体构建插件管理 -->
  </pluginManagement>
  <plugins>
    <!-- 省略具体构建插件 -->
  </plugins>
</build>

从 pom 中可以看出,spring-boot-dependencies 中除了引入了(3 个)插件,更多的是做版本的管理。

其中,引入的插件是:

  • flatten-maven-plugin:对 pom 精简插件
  • xml-maven-plugin:1. 根据 schema 验证 XML 文件;2. 使用 XSLT 样式转换 XML 文件
  • build-helper-maven-plugin:指定多个源码目录

dependencyManagement 中差不多管理了 spring-boot 工程中所有的依赖。

pluginManagement 中管理了常用的各种 maven 插件,这里就不详述了。

其中包含了 maven-clean-plugin、maven-compiler-plugin、maven-assembly-plugin、maven-war-plugin、maven-jar-plugin、spring-boot-maven-plugin,其中 spring-boot-maven-plugin 插件对于 spring-boot 工程非常重要,会把 maven 打包成的 jar 重新打包成可执行 jar。

spring-boot-starter-parent(重要)

既然有了 spring-boot-dependencies 这么丰富的依赖、插件版本管理,那么还搞一个 spring-boot-starter-parent 呢?

spring-boot-starter-parent 的父工程是spring-boot-dependencies,不包含代码,只用 pom 来管理依赖,pom.xml 如下:

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-dependencies</artifactId>
  <version>${revision}</version>
  <relativePath>../../spring-boot-dependencies</relativePath>
</parent>
<artifactId>spring-boot-starter-parent</artifactId>
<packaging>pom</packaging>
<name>Spring Boot Starter Parent</name>
<description>Parent pom providing dependency and plugin management for applications
  built with Maven</description>
<properties>
  <main.basedir>${basedir}/../../..</main.basedir>
  <java.version>1.8</java.version>
  <!-- 资源分隔符 -->
  <resource.delimiter>@</resource.delimiter> <!-- delimiter that doesn't clash with Spring ${} placeholders -->
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  <maven.compiler.source>${java.version}</maven.compiler.source>
  <maven.compiler.target>${java.version}</maven.compiler.target>
</properties>
<build>
  <resources>
    <resource>
      <directory>${basedir}/src/main/resources</directory>
      <filtering>true</filtering>
      <includes>
        <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>
  <pluginManagement>
    <plugins>
      <!-- 省略其它不用太关心的 plugin -->
      <!-- spring-boot 提供的 maven 重打包插件,重要!!! -->
      <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <executions>
              <execution>
                <id>repackage</id>
                <goals>
                  <goal>repackage</goal>
                </goals>
              </execution>
            </executions>
            <configuration>
              <mainClass>${start-class}</mainClass>
            </configuration>
          </plugin>
    </plugins>
  </pluginManagement>
  <plugins>
            <!-- 引入公共插件:flatten-maven-plugin、xml-maven-plugin -->
  </plugins>

特性

  • 默认编译版本:Java 1.8
  • 源码编码:UTF-8
  • 继承自 spring-boot-dependencies 的 dependencyManagement
  • spring-boot-maven-plugin 的 goal 设置为 repackage
  • maven 资源过滤(application*.yml、application*.yaml、application*.properties 等)、插件配置
  • 资源分隔符:“@”,在 application*.yml 中使用@来引用 maven 属性,常见用法如下:[email protected]@

Note that, since the application.properties and application.yml files accept Spring style placeholders (${…}), the Maven filtering is changed to use @[email protected]placeholders. (You can override that by setting a Maven property called resource.delimiter.)

译:

注意,由于 application.properties 和 application.yml 文件接受 spring 样式的占位符($…),所以 maven filter 将更改为使用@…@占位符。(可以通过设置名为 resource.delimiter 的 maven 属性来覆盖该属性。)

spring-boot-parent

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>${revision}</version>
        <relativePath>../spring-boot-dependencies</relativePath>
</parent>
<artifactId>spring-boot-parent</artifactId>
<packaging>pom</packaging>
<dependencyManagement>
  <!-- 省略具体依赖管理 -->
</dependencyManagement>
<dependencies>
  <!-- 省略具体依赖 -->
</dependencies>
<build>
  <pluginManagement>
    <!-- 省略具体构建插件管理 -->
  </pluginManagement>
  <plugins>
    <!-- 省略具体构建插件 -->
  </plugins>
  <profiles>
    <!-- 省略具体 profile -->
  </profiles>
</build>

dependencyManagement

包含两个部分:

  • 内部未发布的 spring-boot 依赖
  • 附加的 Spring 引导依赖项 (对用户无效)

因此,这里所加入的依赖管理,用户不需要关心,很好,省心。

dependencies

公共的依赖,主要是一些测试依赖,如:junit、hamcrest、mockito、spring-test,还有断言依赖:assertj。

plugins

添加了 spring-boot 公用的一些插件,如:maven-compiler-plugin、maven-jar-plugin、maven-war-plugin、maven-source-plugin 等

profiles

用户基本不用关心。省略

选择

spring-boot-dependencies 和 spring-boot-starter-parent、 spring-boot-parent 都提供了依赖管理的功能,那我们在开发的过程中,到底使用哪个呢?

  • spring-boot-parent :目的不是提供给用户使用的,使用 spring-boot 开源项目用于管理 spring-boot-project 整个大工程中的除了 spring-boot-starters (提供给我们使用的各个开箱即用的三方包) 的其他模块的。
  • spring-boot-starter-parent:我们通过 Spring Initializr 构建一个 spring-boot 项目的时候,官方默认是让我们使用的 spring-boot-starter-parent ,大致可以认为官方建议使用此方式管理依赖,毕竟此方式提供的依赖、插件管理更多,更适合使用。
  • spring-boot-dependencies:若在使用的时候,工程不想指定父工程,或者必须使用公司的父工程,可以通过 dependencyManagement 引入此依赖管理。

使用 spring-boot-dependencies,相比较 spring-boot-starter-parent 的时候特别注意要加上spring-boot-maven-plugin,如下:

<build>
  <plugins>
    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
  </plugins>
  <pluginManagement>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <version>${springboot.version}</version>
      </plugin>
    </plugins>
  </pluginManagement>
</build>

至于 spring-boot-starter-parent 的其他额外指定的 jar,按需添加。

实际使用

在工程中使用的时候,所有的二方、三方 jar 都应该统一管理,除了 spring-boot 提供的依赖,我们还有很多 jar 需要管理,如:mysql 驱动包、mybatis 包、各种工具包或者公司内的二方包等。因此,最好使用一个单独的模块来构建自己的 dependencies 或 parent。

待续

em……写到这里就结束了吗?似乎还没有,还需要细致分析下一些具体依赖是如何选择的,比如:spring-boot 选择的是什么日志框架,logback?log4j2?log4j?那对于代码中不是用 spring-boot 指定的日志实现时,spring-boot 又是怎么做的呢?期待后续更新?更或者不更新,谁知道呢?

专注于java知识领域的源码分析,从源码中理解框架/工具原理、验证CS专业知识的应用

原文地址:https://www.cnblogs.com/lw5946/p/11444634.html

时间: 2024-10-13 01:43:53

【spring-boot 源码解析】spring-boot 依赖管理的相关文章

spring boot 源码解析 启动流程

spring boot 源码解析 启动流程 在面试过程中经常被问到过spring boot的启动流程,今天就翻一下源码整体看一下: 首先,新建一个启动类,可以看到是首先调用的SpringApplication的静态方法run @SpringBootApplication public class SourceReadApplillcation { public static void main(String[] args) { SpringApplication.run(SourceReadAp

Spring IoC源码解析之getBean

一.实例化所有的非懒加载的单实例Bean 从org.springframework.context.support.AbstractApplicationContext#refresh方法开发,进入到实例化所有的非懒加载的单实例Bean的finishBeanFactoryInitialization(beanFactory)的方法: protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory bea

spring mvc源码解析

1.从DispatcherServlet开始     与很多使用广泛的MVC框架一样,SpringMVC使用的是FrontController模式,所有的设计都围绕DispatcherServlet 为中心来展开的.见下图,所有请求从DispatcherServlet进入,DispatcherServlet根据配置好的映射策略确定处理的 Controller,Controller处理完成返回ModelAndView,DispatcherServlet根据配置好的视图策略确定处理的 View,由V

Spring IoC源码解析——Bean的创建和初始化

Spring介绍 Spring(http://spring.io/)是一个轻量级的Java 开发框架,同时也是轻量级的IoC和AOP的容器框架,主要是针对JavaBean的生命周期进行管理的轻量级容器,可以单独使用,也可以和Struts框架,MyBatis框架等组合使用. IoC介绍 IoC是什么 Ioc-Inversion of Control,即"控制反转",不是什么技术,而是一种设计思想.在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控

spring源码解析——spring源码导入eclipse

一.前言     众所周知,spring的强大之处.几乎所有的企业级开发中,都使用了spring了.在日常的开发中,我们是否只知道spring的配置,以及简单的使用场景.对其实现的代码没有进行深入的了解.开卷有益,在我们空闲的时间里面阅读一下spring的源码,对提升我们的自身能力还是还有很大的帮忙.下面总结一下spring源码导入eclipse的具体的操作. 二.spring的特点 spring的的核心就是IOC(控制反转)和AOP(基于切面的编程) 事务管理方面采用了:声明式事务 为各种主流

Spring事务源码解析(二)获取增强

在上一篇文章@EnableTransactionManagement注解解析中,我们搭建了源码阅读的环境,以及解析了开启Spring事务功能的注解@EnableTransactionManagement的实现逻辑 在进行接下来的源码解析之前我想大家应该知道,当我们使用传统的jdbc应用事务的时候是不是做了如下操作: 开启事务 save.update.delete等操作 出现异常进行回滚 正常情况提交事务 而在Spring中我们好像只需要关心第三步,也就是我们的业务,而其他的操作都不需要关心.那么

Spring AOP源码解析——专治你不会看源码的坏毛病!

昨天有个大牛说我啰嗦,眼光比较细碎,看不到重点.太他爷爷的有道理了!要说看人品,还是女孩子强一些. 原来记得看到一个男孩子的抱怨,说怎么两人刚刚开始在一起,女孩子在心里就已经和他过完了一辈子.哥哥们,不想这么远行吗?看看何洁,看看带着俩娃跳楼的妈妈. 所以现在的女孩子是很明白的,有些男孩子个子不高,其貌不扬,但是一看那人品气质就知道能找个不错的女盆友.不过要说看人的技术能力,男孩子确实更胜一筹,咱得努力了. 总结一下要形成的习惯: 有空时隔一段时间要做几道算法题,C语言和JAVA都可以,主要是训

.NET Core实战项目之CMS 第三章 入门篇-源码解析配置文件及依赖注入

作者:依乐祝 原文链接:https://www.cnblogs.com/yilezhu/p/9998021.html 写在前面 上篇文章我给大家讲解了ASP.NET Core的概念及为什么使用它,接着带着你一步一步的配置了.NET Core的开发环境并创建了一个ASP.NET Core的mvc项目,同时又通过一个实战教你如何在页面显示一个Content的列表.不知道你有没有跟着敲下代码,千万不要做眼高手低的人哦.这篇文章我们就会设计一些复杂的概念了,因为要对ASP.NET Core的启动及运行原

spring boot 源码解析52-actuate中MVCEndPoint解析

今天有个bie项目的jolokia的endpoint不能访问,调试源码发现:endpoint.enabled的开关导致的. 前言之前的几篇文章分析了spring boot 中有关endpoint的实现,细心的朋友可以发现,在org.springframework.boot.actuate.endpoint.mvc 包下也有一系列的xxxEndpoint,这又是为什么呢? 原因是: 我们很多情况下,都是访问接口的方式获取应用的监控,之前的分析是其实现的底层,要想实现通过接口访问,还需要对其进行包装