SpringBoot 入门

1. SpringBoot 简介

1.1 SpringBoot 的概念

SpringBoot 被称为搭建程序的 “脚手架”。其最主要作用就是帮我们快速的构建庞大的 Spring 项目,并且尽可能的减少一切 xml 配置,让我们关注于业务而非配置文件。

1.2 SpringBoot 的作用

SpringBoot 主要解决了以下两点问题:

  • 复杂的配置

    项目各种配置其实是开发时的损耗,因为在思考 Spring 特性配置和解决业务问题之间需要进行思维切换,所以写配置挤占了写应用程序逻辑的时间。

  • 混乱的依赖管理

    项目的依赖管理也是件吃力不讨好的事情。决定项目里要用哪些库就已经够让人头痛的了,你还要知道这些库的哪个版本和其他库不会有冲突,这也是件棘手的问题。并且依赖管理也是一种损耗,添加依赖不是写应用程序代码。一旦选错了依赖的版本,随之而来的不兼容问题毫无疑问会是生产力杀手。

1.3 SpringBoot 的特点

Spring Boot 主要特点有:

  • 创建独立的 Spring 应用程序
  • 直接内嵌 tomcat、jetty 和 undertow(不需要打包成 war 包部署)
  • 提供了固定化的 “starter” 配置,以简化构建配置
  • 尽可能的自动配置 Spring 和第三方库
  • 提供产品级的功能,如:安全指标、运行状况监测和外部化配置等
  • 绝对不会生成代码,并且不需要 XML 配置

2. SpringBoot 快速入门

2.1 创建工程

  1. 打开 IDEA --> Create New Project --> Empty Project --> 填写项目名 --> Finish
  2. New Module --> Maven --> Next --> 填写项目信息 --> Finish

2.2 引入依赖

  • SpringBoot 提供了一个名为 spring-boot-starter-parent 的工程,里面已经对各种常用依赖(并非全部)的版本进行了管理,我们的项目需要以这个项目为父工程,这样我们就不用操心依赖的版本问题了

  • 为了让 SpringBoot 帮我们完成各种自动配置,我们必须引入 SpringBoot 提供的自动配置依赖,我们称为 ”启动器“。spring-boot-starter-parent 工程将依赖关系声明为一个或者多个启动器,我们可以根据项目需求引入相应的启动器。因为我们是 web 项目,这里我们引入 web 启动器

<?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.zt</groupId>
    <artifactId>springboot-demo1</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!--所有的 SpringBoot 应用都要以该工程为父工程-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
    </parent>

    <!-- 启动器:每个启动器都有背后都有很多依赖-->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
</project>

2.3 编写 Controller

@RestController
@RequestMapping("/hello")
@EnableAutoConfiguration
public class HelloController {

    @RequestMapping("/show")
    public String show() {
        return "Hello SpringBoot";
    }

    public static void main(String[] args) {
        SpringApplication.run(HelloController.class,args);
    }
}

2.4 启动测试

  1. 点击运行 main 方法

  2. 打开浏览器访问以下地址

    http://localhost:8080/hello/show
    

2.5 注解详解

  1. @EnableAutoConfiguration

    开启 Spring 应用程序的自动配置,SpringBoot 基于你所添加的依赖和你自己定义的 Bean,试图去猜测并配置你想要的配置。

    比如:我们引入了spring-boot-starter-web,而这个启动器中帮我们添加了tomcatSpringMVC的依赖。此时自动配置就知道你是要开发一个 web 应用,所以就帮你完成了 web 及 SpringMVC 的默认配置了

  2. @RestController

    相当于 @Controller + @ResponseBody 两个注解的作用。返回 JSON 数据时,不需要在方法前面加 @ResponseBody 注解了。但使用 @RestController 这个注解,视图解析器就不起作用了,返回的内容就是 return 里的内容。

    比如:return “success”,本来应该到 success.jsp 页面的,则其显示 success

2.6 优化入门程序

  1. 提出问题

    如果有多个 Controller 该怎么做呢?

  2. 分析问题

    如果在每一个 Controller 中都添加一个 main 方法和 @EnableAutoConfiguration 注解,那就无法同时启动多个 Controller 了,因为每个 main 方法都监听 8080 端口。所以,一个 SpringBoot 程序应该只有一个 main 方法

  3. 解决问题

    通常情况下,我们都会在一个 SpringBoot 工程中的基包下创建一个全局的引导类,一些 SpringBoot 的全局注解(@EnableAutoConfiguration)以及程序的入口 main 方法都放在该类中。

  4. 实现

    1. 在 SpringBoot 的程序的基包下(引导类和 Controller 包在同级目录下),创建 TestApplication

      /**
       * 引导类:SpringBoot 程序的入口
       */
      @EnableAutoConfiguration // 开启 SpringBoot 自动配置
      @ComponentScan // 指定要扫描的包。如果没有指定,那么将从声明这个注解的类所在的包开始,扫描该包及其子包
      public class TestApplication {
          public static void main(String[] args) {
              SpringApplication.run(TestApplication.class, args);
          }
      }
      
      
    2. 创建两个 Controller

      @RestController
      @RequestMapping("/hello")
      public class HelloController {
      
          @RequestMapping("/show")
          public String show() {
              return "Hello SpringBoot";
          }
      
      }
      
      
      @RestController
      @RequestMapping("/hello2")
      public class Hello2Controller {
      
          @RequestMapping("/show")
          public String show() {
              return "Hello SpringBoot 2";
          }
      
      }
      
      
    3. 启动项目测试

      1. 点击运行 main 方法

      2. 打开浏览器访问以下地址

        http://localhost:8080/hello/show
        
        http://localhost:8080/hello2/show
        

2.7 进一步优化入门程序

我们现在的引导类中使用了 @EnableAutoConfiguration 和 @ComponentScan 注解,还是有点麻烦。SpringBoot 提供了一个简单的注解:@SpringBootApplication

/**
 * 引导类:SpringBoot 程序的入口
 */
@SpringBootApplication
public class TestApplication {
    public static void main(String[] args) {
        SpringApplication.run(TestApplication.class, args);
    }
}

@SpringBootApplication 是一个组合注解,其中重点的注解有 3 个:

  • @SpringBootConfiguration:声明当前类是 SpringBoot 应用的配置类,项目中只能有一个
  • @EnableAutoConfiguration:开启自动配置
  • @ComponentScan:开启注解扫描

3. SpringBoot 配置 Bean

3.1 回顾 Spring 历史

事实上,在 Spring 3.0 开始,Spring 官方就已经开始推荐使用 Java 配置来代替传统的 xml 配置了,我们不妨来回顾一下 Spring 的历史:

  • Spring 1.0 时代

    在此时因为 jdk1.5 刚刚出来,注解开发并未盛行,因此一切 Spring 配置都是 xml 格式,想象一下所有的 bean 都用 xml 配置,细思极恐啊,心疼那个时候的程序员2秒

  • Spring 2.0 时代

    Spring 引入了注解开发,但是因为并不完善,因此并未完全替代 xml,此时的程序员往往是把 xml 与注解进行结合,貌似我们之前都是这种方式。

  • Spring 3.0 及以后

    3.0 以后 Spring 的注解已经非常完善了,因此 Spring 推荐大家使用完全的 Java 配置来代替以前的 xml,不过似乎在国内并未推广盛行。然后当 SpringBoot 来临,人们才慢慢认识到 Java 配置的优雅。

3.2 Java 配置 Bean

Java 配置主要靠 Java 类和一些注解来达到和 xml 配置一样的效果,比较常用的注解有:

  • @Configuration:声明一个类作为配置类,代替 xml 文件
  • @Bean:声明在方法上,将方法的返回值加入 bean 容器,代替 bean 标签
  • @Value:属性注入
  • @PropertySource:指定外部属性文件。

我们接下来用 Java 配置来尝试实现连接池配置:

  1. 引入依赖

    <dependency>
        <groupId>com.github.drtrang</groupId>
        <artifactId>druid-spring-boot2-starter</artifactId>
        <version>1.1.10</version>
    </dependency>
    
  2. 添加 jdbc.properties 到 resources 中

    jdbc.driverClassName=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://127.0.0.1:3306/test
    jdbc.username=root
    jdbc.password=123456
    
  3. 配置数据源

    @Configuration
    @PropertySource("jdbc.properties")
    public class JdbcConfiguration {
        @Value("${jdbc.driverClassName}")
        private String driverClassName;
        @Value("${jdbc.url}")
        private String url;
        @Value("${jdbc.username}")
        private String username;
        @Value("${jdbc.password}")
        private String password;
    
        @Bean
        public DataSource dataSource() {
            DruidDataSource druidDataSource = new DruidDataSource();
            druidDataSource.setDriverClassName(driverClassName);
            druidDataSource.setUrl(url);
            druidDataSource.setUsername(username);
            druidDataSource.setPassword(password);
    
            return druidDataSource;
        }
    }
    
    
  4. 自动注入数据

    @RestController
    @RequestMapping("/hello2")
    public class Hello2Controller {
    
        @Autowired
        private DataSource dataSource;
    
        @RequestMapping("/show")
        public String show() {
            return "Hello SpringBoot 2";
        }
    
    }
    
    
  5. 测试

    1. 在 Hello2Controller 的 show 方法上打一个断点,然后 debug 运行 main 方法

    2. 打开浏览器访问以下地址

      http://localhost:8080/hello2/show
      
    3. 查看 dataSource 属性注入成功

3.3 SpringBoot 的属性注入

在上面的案例中,我们实现了 Java 配置 Bean 的方式。但我们是使用 @Value 注入属性的,如果这时我们又有一个类要注入同样的属性,那我们又要写一遍 @Value,这显然会造成冗余代码。我们应该在一个属性读取类中读取属性,这样在任何类中都可以使用这些属性了。

3.3.1 属性读取类

新建一个属性读取类:

@ConfigurationProperties(prefix = "jdbc")
public class JdbcProperties {
    private String driverClassName;
    private String url;
    private String username;
    private String password;

    public String getDriverClassName() {
        return driverClassName;
    }

    public void setDriverClassName(String driverClassName) {
        this.driverClassName = driverClassName;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

注意:

  • @ConfigurationProperties:声明当前类为属性读取类
  • prefix = “jdbc”:读取配置文件中指定前缀为 jdbc 的值
  • 在类中定义的属性名称也必须与配置文件中 jdbc 后面部分一致,并且必须具有 getter 和 setter 方法
  • 这里我们并没有指定属性文件的地址,SpringBoot 默认会读取文件名为 application.properties 的资源文件,所以我们把 jdbc.properties 名称改为 application.properties,通常 SpringBoot 项目也只有 application.properties 这一个配置文件

3.3.2 四种属性注入

接下来要在 JdbcConfiguration 类注入 JdbcProperties 属性,可以通过以下四种方式:

  1. @Autowired 注入(最常用)

    @Configuration
    @EnableConfigurationProperties(JdbcProperties.class)
    public class JdbcConfiguration {
    
        @Autowired
        private JdbcProperties jdbcProperties;
    
        @Bean
        public DataSource dataSource() {
            DruidDataSource druidDataSource = new DruidDataSource();
            druidDataSource.setDriverClassName(jdbcProperties.getDriverClassName());
            druidDataSource.setUrl(jdbcProperties.getUrl());
            druidDataSource.setUsername(jdbcProperties.getUsername());
            druidDataSource.setPassword(jdbcProperties.getPassword());
    
            return druidDataSource;
        }
    }
    
    
  2. 构造函数注入

    @Configuration
    @EnableConfigurationProperties(JdbcProperties.class)
    public class JdbcConfiguration {
    
        private JdbcProperties jdbcProperties;
    
        public JdbcConfiguration(JdbcProperties jdbcProperties) {
            this.jdbcProperties = jdbcProperties;
        }
    
        @Bean
        public DataSource dataSource() {
            DruidDataSource druidDataSource = new DruidDataSource();
            druidDataSource.setDriverClassName(jdbcProperties.getDriverClassName());
            druidDataSource.setUrl(jdbcProperties.getUrl());
            druidDataSource.setUsername(jdbcProperties.getUsername());
            druidDataSource.setPassword(jdbcProperties.getPassword());
    
            return druidDataSource;
        }
    }
    
    
  3. 通过 Bean 方法的形参注入

    @Configuration
    @EnableConfigurationProperties(JdbcProperties.class)
    public class JdbcConfiguration {
    
        @Bean
        public DataSource dataSource(JdbcProperties jdbcProperties) {
            DruidDataSource druidDataSource = new DruidDataSource();
            druidDataSource.setDriverClassName(jdbcProperties.getDriverClassName());
            druidDataSource.setUrl(jdbcProperties.getUrl());
            druidDataSource.setUsername(jdbcProperties.getUsername());
            druidDataSource.setPassword(jdbcProperties.getPassword());
    
            return druidDataSource;
        }
    }
    
    
  4. 直接在方法上使用 @ConfigurationProperties(prefix = “jdbc”),SpringBoot 就会自动调用这个 Bean 的 set 方法,然后完成注入,但前提是该类必须有对应属性的 set 方法,这种方式显然有一定的局限性

    @Configuration
    public class JdbcConfiguration {
    
        @ConfigurationProperties(prefix = "jdbc")
        @Bean
        public DataSource dataSource() {
            DruidDataSource druidDataSource = new DruidDataSource();
            return druidDataSource;
        }
    }
    
    

注意:

  • @EnableConfigurationProperties 注解的作用是:让使用 @ConfigurationProperties 注解的类生效。
  • 如果一个配置类只配置 @ConfigurationProperties 注解,而没有使用 @Component,那么在 IOC 容器中是获取不到这个 Bean 的,@EnableConfigurationProperties 相当于把使用 @ConfigurationProperties 的类进行了一次注入。

3.3.3 测试

  1. 在 Hello2Controller 的 show 方法上打一个断点,然后 debug 运行 main 方法

  2. 打开浏览器访问以下地址

    http://localhost:8080/hello2/show
    
  3. 查看 dataSource 属性注入成功

4. SpringBoot 默认配置原理

通过刚才的学习,我们知道 @EnableAutoConfiguration 会开启 SpringBoot 的自动配置,并且根据你引入的依赖来生效对应的默认配置。那么问题来了:

  1. 这些默认配置是怎么配置的,在哪里配置的呢?

    在我们的项目中,已经引入了一个依赖:spring-boot-autoconfigure,其中定义了大量自动配置类

    在这里插入图片描述

  2. 为何引入依赖就会触发配置呢?

    引入相关依赖后,就会满足默认配置上的一些条件注释,于是就会触发配置,如 WebMvcAutoConfiguration 上就有条件注释,如下:

    @ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
    
  3. 这些默认配置的属性来自哪里呢?

    在 WebMvcAutoConfiguration 类中通过 @EnableConfigurationProperties 引入了两个属性读取类,如下:

    @EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class})
    

    接下来我们看看 WebMvcProperties

    @ConfigurationProperties(
        prefix = "spring.mvc"
    )
    public class WebMvcProperties {
        private Format messageCodesResolverFormat;
        private Locale locale;
        private WebMvcProperties.LocaleResolver localeResolver;
        private String dateFormat;
        private boolean dispatchTraceRequest;
        private boolean dispatchOptionsRequest;
        private boolean ignoreDefaultModelOnRedirect;
        private boolean publishRequestHandledEvents;
        private boolean throwExceptionIfNoHandlerFound;
        private boolean logResolvedException;
        private String staticPathPattern;
        private final WebMvcProperties.Async async;
        private final WebMvcProperties.Servlet servlet;
        private final WebMvcProperties.View view;
        private final WebMvcProperties.Contentnegotiation contentnegotiation;
        private final WebMvcProperties.Pathmatch pathmatch;
    
        public WebMvcProperties() {
            this.localeResolver = WebMvcProperties.LocaleResolver.ACCEPT_HEADER;
            this.dispatchTraceRequest = false;
            this.dispatchOptionsRequest = true;
            this.ignoreDefaultModelOnRedirect = true;
            this.publishRequestHandledEvents = true;
            this.throwExceptionIfNoHandlerFound = false;
            this.logResolvedException = false;
            this.staticPathPattern = "/**";
            this.async = new WebMvcProperties.Async();
            this.servlet = new WebMvcProperties.Servlet();
            this.view = new WebMvcProperties.View();
            this.contentnegotiation = new WebMvcProperties.Contentnegotiation();
            this.pathmatch = new WebMvcProperties.Pathmatch();
        }
       ...
    }
    

    WebMvcProperties 中已经配置好了默认的属性,如果我们要覆盖这些默认属性,只需要在 application.properties 中定义与其前缀 prefix 和字段名一致的属性即可

5. 总结

前面说到了 SpringBoot 主要解决了以下两点问题,现在再来看看 SpringBoot 是怎样解决两点问题的:

  • 复杂的配置

    SpringBoot 采用默认配置,我们也可以在 application.properties 文件来覆盖这些默认属性,这样虽然使用的还是默认配置,但是配置中的值改成了我们自定义的。

  • 混乱的依赖管理

    SpringBoot 提供了 stater(启动器),引入后就会自动管理依赖及版本了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bm1998

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值