前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >spring-boot-starter大力出奇迹

spring-boot-starter大力出奇迹

作者头像
阿豪聊干货
发布2018-08-09 09:49:50
9300
发布2018-08-09 09:49:50
举报
文章被收录于专栏:Java后端技术Java后端技术

一、前言

​  上篇文章我们已经聊了SpringBoot的启动过程中的各类扩展点,那么从http://start.spring.io上我们生成的demo项目中,到目前就剩下了maven工程的pom.xml还没有进行探索了,那么本文我们就来看看这里面到底都有啥,把大力出奇迹的常见spring-boot-starter来聊一聊,以便更好地使用SpringBoot.

二、SpringBoot项目的pom.xml文件解析

​   首先,我们还是按照一贯的作风,先上源码,再解析:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
            http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.hafiz</groupId>
    <artifactId>springboot-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>springboot-demo</name>
    <description>Demo project for Spring Boot</description>

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

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

​  我们可以看到所有的结构都是我们熟悉的。首先映入眼帘的是:<parent></parent>标签,熟悉Maven的朋友都知道,这个标签用来定义要继承的父pom的信息,它用来定义SpringBoot项目可能用到的依赖和插件声明以及一些资源文件声明,这样我们就可以在自己的SpringBoot项目中用到这些依赖或者插件的时候直接饮用,而不用指定版本号,正如我们上面看到的spring-boot-starter-webspring-boot-starter-test依赖以及spring-boot-maven-plugin插件一样,父pom.xml的源码如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>1.5.13.RELEASE</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>
    <url>http://projects.spring.io/spring-boot/</url>
    <organization>
        <name>Pivotal Software, Inc.</name>
        <url>http://www.spring.io</url>
    </organization>
    <properties>
        <java.version>1.6</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>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-core</artifactId>
                <version>${spring.version}</version>
                <exclusions>
                    <exclusion>
                        <groupId>commons-logging</groupId>
                        <artifactId>commons-logging</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <build>
        <!-- Turn on filtering by default for application properties -->
        <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>
                <!-- Apply more sensible defaults for user projects -->
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-failsafe-plugin</artifactId>
                    <executions>
                        <execution>
                            <goals>
                                <goal>integration-test</goal>
                                <goal>verify</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-jar-plugin</artifactId>
                    <configuration>
                        <archive>
                            <manifest>
                                <mainClass>${start-class}</mainClass>
                                <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                            </manifest>
                        </archive>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <configuration>
                        <includes>
                            <include>**/*Tests.java</include>
                            <include>**/*Test.java</include>
                        </includes>
                        <excludes>
                            <exclude>**/Abstract*.java</exclude>
                        </excludes>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-war-plugin</artifactId>
                    <configuration>
                        <failOnMissingWebXml>false</failOnMissingWebXml>
                        <archive>
                            <manifest>
                                <mainClass>${start-class}</mainClass>
                                <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                            </manifest>
                        </archive>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>exec-maven-plugin</artifactId>
                    <configuration>
                        <mainClass>${start-class}</mainClass>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-resources-plugin</artifactId>
                    <version>2.6</version>
                    <configuration>
                        <delimiters>
                            <delimiter>${resource.delimiter}</delimiter>
                        </delimiters>
                        <useDefaultDelimiters>false</useDefaultDelimiters>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>pl.project13.maven</groupId>
                    <artifactId>git-commit-id-plugin</artifactId>
                    <executions>
                        <execution>
                            <goals>
                                <goal>revision</goal>
                            </goals>
                        </execution>
                    </executions>
                    <configuration>
                        <verbose>true</verbose>
                        <dateFormat>yyyy-MM-dd'T'HH:mm:ssZ</dateFormat>
                        <generateGitPropertiesFile>true</generateGitPropertiesFile>
                        <generateGitPropertiesFilename>${project.build.outputDirectory}/git.properties</generateGitPropertiesFilename>
                    </configuration>
                </plugin>
                <!-- Support our own plugin -->
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <executions>
                        <execution>
                            <goals>
                                <goal>repackage</goal>
                            </goals>
                        </execution>
                    </executions>
                    <configuration>
                        <mainClass>${start-class}</mainClass>
                    </configuration>
                </plugin>
                <!-- Support shade packaging (if the user does not want to use our plugin) -->
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-shade-plugin</artifactId>
                    <dependencies>
                        <dependency>
                            <groupId>org.springframework.boot</groupId>
                            <artifactId>spring-boot-maven-plugin</artifactId>
                            <version>1.5.13.RELEASE</version>
                        </dependency>
                    </dependencies>
                    <configuration>
                        <keepDependenciesWithProvidedScope>true</keepDependenciesWithProvidedScope>
                        <createDependencyReducedPom>true</createDependencyReducedPom>
                        <filters>
                            <filter>
                                <artifact>*:*</artifact>
                                <excludes>
                                    <exclude>META-INF/*.SF</exclude>
                                    <exclude>META-INF/*.DSA</exclude>
                                    <exclude>META-INF/*.RSA</exclude>
                                </excludes>
                            </filter>
                        </filters>
                    </configuration>
                    <executions>
                        <execution>
                            <phase>package</phase>
                            <goals>
                                <goal>shade</goal>
                            </goals>
                            <configuration>
                                <transformers>
                                    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                                        <resource>META-INF/spring.handlers</resource>
                                    </transformer>
                                    <transformer implementation="org.springframework.boot.maven.PropertiesMergingResourceTransformer">
                                        <resource>META-INF/spring.factories</resource>
                                    </transformer>
                                    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                                        <resource>META-INF/spring.schemas</resource>
                                    </transformer>
                                    <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
                                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                        <mainClass>${start-class}</mainClass>
                                    </transformer>
                                </transformers>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

  但是我们发现,该父pom文件还有自己的父pom,作用类似,不再详解,感兴趣的可以自己去翻阅源码。那么这样看来我们自己的SpringBoot项目中的pom.xml文件就剩下显眼的两个依赖以及一个插件了(没有指定版本号的原因前面已经解释了),那我们接下来就来聊一聊这些非常重要的spring-boot-starter依赖。

三、不可或缺的spring-boot-starter

​  我们从前面就知道了,SpringBoot能够如此方便便捷,其实都是得益于这些“开箱即用”的依赖模块,那SpringBoot设计者约定这些“开箱即用”的依赖模块的命名都以spring-boot-starter-开始,并且这些模块都位于org.springframework.boot包或者命名空间下面。我们也可以模仿者来实现自己的自动配置依赖模块,也已spring-boot-starter-开头,是不是就很"正宗"呢?(虽然SpringBoot官方不建议我们这样做,以免跟官方提供的混淆,但是其实我们使用自己的groupId,这样命名应该不是啥问题)。

​  这些starter其实都有约定好的默认配置,但是它也允许我们调整这些默认配置,以便完成定制化的需求,我们可以改变默认配置的常见方式有以下几种:

  • 命令行参数(Command Line Args)
  • 系统环境变量(Environment Variables)
  • 位于文件系统中的配置文件
  • 位于classpath中的配置文件
  • 固化到代码中的配置项

  这几种方式从上到下优先级从高到低排列,高优先级的配置会覆盖优先级低的配置。还有就是不管位于文件系统还是classpath中的配置文件,SpringBoot应用默认的文件名称都是application.properties,可以放在当前项目的根目录下或者名称为config的子目录下。

​  SpringBoot其实提供了很多这样的模块,我们就挑几个我们常用的这样的模块来解析,其他的大家就举一反三。以达到在工作和开发中灵活运用这些spring-boot-starter模块的效果。

1. spring-boot-starter-logging以及应用日志

 如果我们在maven依赖中添加了spring-boot-starter-logging:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-logging</artifactId>
</dependency>

  那也就意味着我们的SpringBoot应用自动使用logback作为日志框架,在启动的时候,由org.springframework.boot.logging.LoggingApplicationListener根据情况初始化并使用。默认情况下,SpringBoot已经给我们提供好了很多默认的日志配置,我们只需要将spring-boot-starter-logging作为依赖加入到你的SpringBoot应用就可以了,但是如果我们要对这些默认配置进行定制,可以有两种方式进行:

  • 遵守logback的约定,在classpath中使用定制化的logback.xml配置文件。
  • 在文件系统中任意一个地方提供自己的logback.xml配置文件,然后通过如下配置来application.properties中指定我们日志系统配置文件位置: logging.config=/{your config file location}}/logback.xml

如果我们已经习惯了log4j或log4j2,那我们只需要把spring-boot-starter-logging换成如下的starter就好。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-log4j</artifactId>
</dependency>
或
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
2. 用于快速构建web应用的spring-boot-starter-web

​  现如今,我们在工作中大部分实际用的还是SpringMVC开发的web应用,SpringBoot当然贴心的为我们开发了一个web项目模块,让我们更加方便的开发web应用。maven依赖如下:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

  这样我们就可以得到一个可以直接执行的Web应用,然后我们运行mvn spring-boot:run,就能直接启动一个基于嵌入式tomcat容器的Web应用了,然后就可以像这篇文章中定义controller来供用户访问了。但是呢,这简单的表象之下,其实却隐藏着很多约定,我们要把这些潜规则了解清楚才能更好地应用spring-boot-starter-web

2.1 项目结构的“潜规则”

​   传统的Java Web项目中,我们的静态文件以及页面模板都是放在src/main/webapp目录下,但是在SpringBoot应用中,这些文件被统一放在src/main/resources相应的子目录下:

  • src/main/resources/static目录用于存放各种静态资源,如:js、css、image等。
  • src/main/resources/template目录用于存放模板文件。

细心地我们会发现SpringBoot的web应用已经变成了jar包而再是war包,如果我们还是希望以war包的形式发布也是可以的。

2.2 SpringMVC框架层面的约定及定制

spring-boot-starter-web默认将为我们自动配置如下一些SpringMVC必要的组件:

  • ViewResolver,如:ContentNegotiatingViewResolverBeanNameViewResolver
  • Converter,如:GenericConverterFormatter等bean被注册到IoC容器。
  • 默认添加一系列HttpMessageConverter用于支持对Web请求和相应的类型转换。
  • 自动配置和注册MessageCodesResolver
  • 其他必要组件…
2.3 嵌入式Web容器的约定和定制

​  我们知道spring-boot-starter-web默认把嵌入式tomcat作为web容器来对外提供HTTP服务,默认使用8080端口对外监听和提供服务。这里我们可能会有两个疑问:

  • 我们不想使用默认的嵌入式tomcat容器怎么办? 很简单,我们只需要引入spring-boot-starter-jettyspring-boot-starter-undertow依赖就能替代默认嵌入式tomcat容器了。
  • 我们想要把启动后提供服务的端口改掉怎么办? 我们可以通过在配置文件中修改启动端口就可以了,如: server.port=9000

其实,spring-boot-starter-web提供了很多以server.作为前缀的配置以用来修改嵌入式容器的配置,如:

server.port
server.address
server.ssl.*
server.tomcat.*

那若这些还满足不了你,SpringBoot甚至都允许我们直接对嵌入式Web容器实例进行定制化,我们通过向IoC容器中注册一个EmbeddedServletContainerCustomizer类型的组件来实现:

package com.hafiz.springbootdemo;

import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;

/**
 * @author hafiz.zhang
 * @description: 自定义内嵌容器配置
 * @date Created in 2018/6/10 12:09.
 */
public class DemoEmbeddedTomcatCustomizer implements EmbeddedServletContainerCustomizer {
    @Override
    public void customize(ConfigurableEmbeddedServletContainer container) {
        container.setPort(9111);
        container.setContextPath("/demo");
        // ...
    }
}

如果还要再深入的定制,那就需要实现对应内嵌容器的Factory并注册到IoC容器:

  • TomcatEmbeddedServletContainerFactory
  • JettyEmbeddedServletContainerFactory
  • UndertowEmbeddedServletContainerFactory

  但是,我们几乎没有可能需要这样的定制化,也不建议这样的定制化,使用SpringBoot默认的spring-boot-starter-web提供的配置项列表已经很简单、很完整了。

3. 用于数据访问的spring-boot-starter-jdbc

  我们知道,现实中大多数的Java应用都需要访问数据库,那SpringBoot肯定不会放过这个组件,它会很贴心的为我们自动配置好相应的数据访问工具。我们只需要在pom.xml中添加以下依赖就好了:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

  这样,在我们没有配置任何DataSource的情况下,SpringBoot会默认为我们自动配置一个基于嵌入式数据的DataSource,这种自动配置适合于测试场景,生产环境不适合。大多数情况下,我们都会自己配置DataSource实例,或通过自动配置模块提供的配置参数对DataSource实例配置自定义的参数。

若我们的SpringBoot应用只依赖一个数据库,那我们直接使用自动配置模块提供的配置参数最方便快捷:

spring.datasource.url=jdbc:mysql://{db host}:{db port}/{db name}
spring.datasource.username={db user name}
spring.datasource.password={db password}

  有的小伙伴说了:那我自己配置一个DataSource行不行?答案是当然可以,SpringBoot会很智能的优先选择使用我们自己配置的这个DataSource,但是感觉多此一举!你要知道,SpringBoot除了自动帮我们配置DataSource以外,还自动帮我们配置了相应的JdbcTemplate以及DataSourceTransactionManager等相关的组件,我们只需要在需要使用的地方直接使用@Autowired注解引用就好了。

​  那SpringBoot是不是一直贴心呢?很明显不是的,如果我们的单个项目需要依赖和访问多个数据库,这个时候就不行了,就算是我们在ApplicationContext中配置了多个DataSource实例来访问多个数据库:

@Bean
public DataSource dataSource1() throws Throwable {
    DruidDataSource ds = new DruidDataSource();
    ds.setUrl(...);
    ds.setUsername(...);
    ds.setPassword(...);
    // set other db setting
    return ds;
}
@Bean
public DataSource dataSource2() throws Throwable {
    DruidDataSource ds = new DruidDataSource();
    ds.setUrl(...);
    ds.setUsername(...);
    ds.setPassword(...);
    // set other db setting
    return ds;
}

启动项目时,你就会发现如下的异常:

No qualifying bean of type [javax.sql.DataSource] is defined: expected single matching bean but found 2...

那怎么解决这个问题呢?有两种方式:

  • 在SpringBoot的启动类上“动手脚” @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class }) public class DemoSpringBootApplication { public static void main(String[] args) { SpringApplication.run(DemoSpringBootApplication.class, args); } } 这也就是说我们需要排除掉SpringBoot默认的DataSource的相关的自动配置。
  • 使用@primary注解 那我们既要配置两个数据源,又要使用SpringBoot默认的DataSource,这时我们就可以为我们配置的两个DataSource中的任意一个使用@primary注解就可以了。 @Bean @Primary public DataSource dataSource1() throws Throwable { DruidDataSource ds = new DruidDataSource(); ds.setUrl(...); ds.setUsername(...); ds.setPassword(...); // set other db setting return ds; } @Bean public DataSource dataSource2() throws Throwable { DruidDataSource ds = new DruidDataSource(); ds.setUrl(...); ds.setUsername(...); ds.setPassword(...); // set other db setting return ds; } 除此之外,SpringBoot还提供了很多其他数据源访问相关的自动配置模块,如:spring-boot-starter-jpaspring-boot-starter-mongodb等。

四、总结

  除了本文我们介绍的常用的三个spring-boot-starter以外,SpringBoot还提供了很多别的starter,包括spring-boot-starter-aopspring-boot-starter-securityspring-boot-starter-actuator等等。我们通过本文举一反三,可以做到用的时候得心应手。棒!给自己一个赞~

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-06-11 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、前言
  • 二、SpringBoot项目的pom.xml文件解析
  • 三、不可或缺的spring-boot-starter
    • 1. spring-boot-starter-logging以及应用日志
      • 2. 用于快速构建web应用的spring-boot-starter-web
        • 2.1 项目结构的“潜规则”
        • 2.2 SpringMVC框架层面的约定及定制
        • 2.3 嵌入式Web容器的约定和定制
      • 3. 用于数据访问的spring-boot-starter-jdbc
      • 四、总结
      相关产品与服务
      容器服务
      腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档