SprintBoot学习笔记-02 自动配置简析

1.SpringBoot依赖管理

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

我们引入了很多包,但是我们都没有写名版本号,这是因为他依赖于父项目对包版本进行管理,我们进入父项目:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.4.2</version>
  </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>
    <java.version>1.8</java.version>
    <resource.delimiter>@</resource.delimiter>
    <maven.compiler.source>${java.version}</maven.compiler.source>
    <maven.compiler.target>${java.version}</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  </properties>
.............

会发现他还有个父项目spring-boot-dependencies,我们再进入:

<properties>
    <activemq.version>5.16.0</activemq.version>
    <antlr2.version>2.7.7</antlr2.version>
    <appengine-sdk.version>1.9.84</appengine-sdk.version>
    <artemis.version>2.15.0</artemis.version>
    <aspectj.version>1.9.6</aspectj.version>
    <assertj.version>3.18.1</assertj.version>
    <atomikos.version>4.0.6</atomikos.version>
    <awaitility.version>4.0.3</awaitility.version>
    <bitronix.version>2.1.4</bitronix.version>
    <build-helper-maven-plugin.version>3.2.0</build-helper-maven-plugin.version>
    <byte-buddy.version>1.10.19</byte-buddy.version>
    <caffeine.version>2.8.8</caffeine.version>
    <cassandra-driver.version>4.9.0</cassandra-driver.version>
    <classmate.version>1.5.1</classmate.version>
    <commons-codec.version>1.15</commons-codec.version>
    <commons-dbcp2.version>2.8.0</commons-dbcp2.version>
    <commons-lang3.version>3.11</commons-lang3.version>
    <commons-pool.version>1.6</commons-pool.version>
    <commons-pool2.version>2.9.0</commons-pool2.version>
    <couchbase-client.version>3.0.10</couchbase-client.version>
    <db2-jdbc.version>11.5.5.0</db2-jdbc.version>
    <dependency-management-plugin.version>1.0.11.RELEASE</dependency-management-plugin.version>
    <derby.version>10.14.2.0</derby.version>
    <dropwizard-metrics.version>4.1.17</dropwizard-metrics.version>
    <ehcache.version>2.10.6</ehcache.version>
    <ehcache3.version>3.9.0</ehcache3.version>
    <elasticsearch.version>7.9.3</elasticsearch.version>
    <embedded-mongo.version>2.2.0</embedded-mongo.version>
    <flyway.version>7.1.1</flyway.version>
    <freemarker.version>2.3.30</freemarker.version>
    <git-commit-id-plugin.version>3.0.1</git-commit-id-plugin.version>
    <glassfish-el.version>3.0.3</glassfish-el.version>
    <glassfish-jaxb.version>2.3.3</glassfish-jaxb.version>
    <groovy.version>2.5.14</groovy.version>
    <gson.version>2.8.6</gson.version>
    <h2.version>1.4.200</h2.version>
    <hamcrest.version>2.2</hamcrest.version>
    <hazelcast.version>4.0.3</hazelcast.version>
    <hazelcast-hibernate5.version>2.1.1</hazelcast-hibernate5.version>
    <hibernate.version>5.4.27.Final</hibernate.version>
    <hibernate-validator.version>6.1.7.Final</hibernate-validator.version>
    <hikaricp.version>3.4.5</hikaricp.version>
    <hsqldb.version>2.5.1</hsqldb.version>

会发现此处管理了大量的包版本,是当前版本 SpringBoot 自动仲裁机制提供的版本,在SpringBoot父项目中,通过引用定义的版本号进行依赖包管理。

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>${mysql.version}</version>
        <exclusions>
          <exclusion>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java</artifactId>
          </exclusion>
        </exclusions>
    </dependency>

如果我们不想使用SpringBoot的默认包版本,我们也可以重写版本号(覆盖版本外部定义即可):

A.查看包版本命名

<properties>
    <mysql.version>8.0.22</mysql.version>
</properties>

B.在自己项目的pom.xml中重写版本命名和版本号

<properties>
    <mysql.version>5.1.43</mysql.version>
</properties>

[注]:当然了,如果我们导入的包并不在SpringBoot管理之内,还是必须要写版本号的。

2.SpringBoot场景启动器

SpringBoot将各种开发环境封装为一个个场景,以前我们在开发web的时候需要导入一大堆依赖包,而现在,只需要通过导入一个启动器(spring-boot-starter-*),SpringBoot就会自动帮我们把该场景的常规依赖包导入:

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

SpringBoot支持的所有场景启动器:https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-starter

还有一些非SpringBoot官方的场景启动器: *-spring-boot-starter。

我们以Spring-boot-starter-web为例,看一下依赖结构:

很明显,通过一个starter,我们导入了很多的web开发常规依赖包。

3.SpringBoot自动配置

以web应用程序为例,一个spring-boot-starter-web需要配置很多东西:

A.Tomcat自动配置

1. Tomcat包的引入(在父项目中定义)

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
        <version>2.4.2</version>
    </dependency>

2. Tomcat的配置

B.SpringMVC自动配置

1.SpringMVC包的引入

2.自动配置SpringMVC的功能组件

以前我们需要在web.xml中配置DispatcherServlet、characterEncodingFilter(字符编码过滤器),在SpringBoot中,只要我们启动了web场景,就是自动配置的。

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        ApplicationContext ctx = SpringApplication.run(DemoApplication.class, args);
        String[] beanDefinitionNames = ctx.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
    }

}

注:run()方法返回的是Spring IoC容器。

3.默认扫包规则

以前我们需要在配置文件中定义包扫描器,而SpringBoot默认的扫包规则是主程序所在包及其子包内的所有组件@Component。

当然,SpringBoot提供了修改扫描路径的方式:

1.修改包路径

现在Controller不在主程序所在包,也不在那包的子包下,默认时扫描不到的。

2.启动Tomcat访问

目前容器里是没有该Controller对应的bean的,自然也就不能处理访问请求。

3.自定义扫描位置

@SpringBootApplication(scanBasePackages = "com")
public class DemoApplication {

    public static void main(String[] args) {
        ApplicationContext ctx = SpringApplication.run(DemoApplication.class, args);
        String[] beanDefinitionNames = ctx.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
    }

}

@SpringBootApplication有一个属性--String[] scanBasePackages() default {};用于指定要自定义扫描的包,这个属性是个数组,可以赋多个值。

4.重启访问

[注]:之前在学习Spring时我们提到过,现在的Spring正提倡去配置化,我们使用@Configuration表明配置类;因此我们也可以在配置类中著名要扫描的包。我们测试一下让配置类注明扫描com.controller,再看看com.zzt.controller内的controller是否会被扫描到

package com.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @RequestMapping("/hello")
    public String hello(){
        return "Hello,StringBoot";
    }

}
package com.zzt.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class AnotherController {

    @RequestMapping("/hello2")
    public String hello(){
        return "Hello,StringBoot 第二个";
    }

}
package com.zzt.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(value = "com.controller")
public class MyWebConfiguration {

}

注:为了使配置类生效,我们还是要将配置类放置在默认位置让主程序能够扫描到的位置。

可见,尽管我们使用配置类自定义了扫描路径,最终扫描的位置是默认位置和配置类配置路径的并集。

[注]:我们无法在主程序上增加@ComponentScan注解,这是因为主程序自带的注解 @SpringBootApplication 中带有 @ComponentScan ,会有冲突。

如果一定要在主程序上自定义包,还想使用 @ComponentScan 注解,我们需要将 @SpringBootApplication 拆分为三个小注解:

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.controller")
public class DemoApplication {

    public static void main(String[] args) {
        ApplicationContext ctx = SpringApplication.run(DemoApplication.class, args);
        String[] beanDefinitionNames = ctx.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
    }

}

需要注意的是,一旦我们使用这种方式,SpringBoot就只会扫描我们定义的位置了:

我们可以使用数组的方式赋予多个扫描路径:

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(value = {"com.controller","com.zzt.controller"})
public class DemoApplication {

    public static void main(String[] args) {
        ApplicationContext ctx = SpringApplication.run(DemoApplication.class, args);
        String[] beanDefinitionNames = ctx.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
    }

}

当然了,简单起见我们也可以定义扫描总包:(实际开发中不会推荐,因为微服务架构的存在,各个小场景之间应该避免耦合)

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(value = "com")
public class DemoApplication {

    public static void main(String[] args) {
        ApplicationContext ctx = SpringApplication.run(DemoApplication.class, args);
        String[] beanDefinitionNames = ctx.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
    }

}

4.各项配置默认值

SpringBoot还为我们配置好了一些项目相关的默认值:如Tomcat的端口默认值

server.port=8081

我们在配置文件中,对着属性 server.port 操作 ctrl + 左键,会进入到相应类的set方法

    public void setPort(Integer port) {
        this.port = port;
    }

prefix就是在配置文件中的属性值前缀--server,用yaml就是对应的yaml对象的名称。

server:
  port: 8081

这些属性的配置,最后会赋值到容器创建的对应类的实体bean上。

5.SpringBoot自动配置功能

当我们引入一个场景--starter后,它对应的自动配置功能就会开启;以web为例:

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

它依赖于另一个包:

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
      <version>2.4.2</version>
      <scope>compile</scope>
    </dependency>

进去之后发现,有一个包:

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-autoconfigure</artifactId>
      <version>2.4.2</version>
      <scope>compile</scope>
    </dependency>

这个包就负责为我们完成自动配置。

这个包内部集成了很多的自动配置方案,使用 @ConditionalOnXXX 来配置该类是否生效。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值