美文网首页
Spring Boot入门

Spring Boot入门

作者: 清雨季 | 来源:发表于2019-05-09 17:47 被阅读0次

一 快速入门

1.1 最简单的HelloWrold程序

步骤一 在pom中引入以下依赖:

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

这个依赖会自动把spring-web, spring-webmvc, spring-context, tomcat等包引到项目中。
步骤二 新建一个Controller,代码如下:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@EnableAutoConfiguration
public class HelloController {
    @RequestMapping("/")
    public String hello() {
        return "hello";
    }

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

步骤三 运行HelloController中的main方法,访问http://localhost:8080/即可看到页面上输出的结果。
注: Spring官方推荐使用java8.0,并且使用maven3.2+版本。

二 使用SpringBoot整合常见的框架

2.1 使用SpringBoot整合mybatis

首先要引入mybatis-spring-boot-starter依赖和mysql的依赖:

    <dependency>
      <groupId>org.mybatis.spring.boot</groupId>
      <artifactId>mybatis-spring-boot-starter</artifactId>
      <version>2.0.1</version>
    </dependency>
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.16</version>
    </dependency>

注:mybatis-spring-boot-starter是应该是由mybatis提供的,而不是SpringBoot提供的。如果我们不想用mybatis,只想用数据库方面的内容,可以引入SpringBoot提供的spring-boot-starter-data-jdbc依赖
然后要告诉SpringBoot我们数据库的数据源,在resources目录下新建一个文件application.peoperties文件(SpringBoot会默认读取这个文件的配置),然后配置好数据库相关的内容:

spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

同时,还要配置好mybatis相关的内容,主要是要指定mapper文件的位置和类别名的扫描路径:

mybatis.typeAliasesPackage=com.akichyan.domain
mybatis.mapperLocations=classpath:mapper/*.xml

接下来只需要编写好Dao和对应的mapper文件即可,需要注意的是,启动类中要指定好Dao的描扫目录,使用@MapperScan注解,如下代码的第三行:

@RestController
@EnableAutoConfiguration
@MapperScan("com.akichyan.dao")
public class HelloController {
    @Resource
    private UserDao userDao;

    @RequestMapping("/")
    public String hello() {
        return userDao.getUser(1).getName();
    }

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

重新启动即可。

2.2 整合SpringMVC

快速入门中的例子其实就已经是整合了SpringMVC,此处不再重复,但是上述的例子中,HelloController即充当了启动类,又充当了Controller类,我们可以把它拆一下,方便理解:

  • 首先HelloController类只保留Controller的相关代码:
package com.akichyan.web;

import com.akichyan.dao.UserDao;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

@RestController
public class HelloController {
    @Resource
    private UserDao userDao;

    @RequestMapping("/")
    public String hello() {
        return userDao.getUser(1).getName() ;
    }
}

  • 其次再新建一个启动类,在这个类中我们要额外加一@ComponentScan(basePackages = "com.akichyan"),这个注解配置了一个自动扫包,可以让我们上面定义的HelloController被扫描到。
package com.akichyan;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;

@EnableAutoConfiguration
@MapperScan("com.akichyan.dao")
@ComponentScan(basePackages = "com.akichyan")
public class Application extends SpringBootServletInitializer {
    public static void main(String[] args) {
        SpringApplication.run(Application.class);
    }
}

三 SpringBoot中常用的注解及其作用

@SpringBootApplication
等同于同时加上了以下三个注解:

@ComponentScan
@EnableAutoConfiguration
@Configuration

@Configuration
其实就是JavaConfig形式的SpringIoC容器配置的那个@Configuration,SpringBoot是基本JavaConfig形式来实现的。
这个注解表明本类是一个JavaConfig配置类。

@EnableAutoConfiguration
这个注解会去META-INF目录下查找一个叫spring.factories的文件,然后将文件中的org.springframework.boot.autoconfigure.EnableAutoConfiguration对应的条目解析出来,加载对应的类,这些类都是AppConfig类。可以写一个示例代码:

  • 步骤一:新建一个AppConfig类:
package com.akichyan.config;

import com.akichyan.domain.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyAppConfig {
    @Bean
    public User getDefaultUser() {
        return new User();
    }
}
  • 步骤二:在resources目录下新建一个META-INF目录,然后在META-INF目录下新建一个spring.factories文件,指定要加载的配置类:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.akichyan.config.MyAppConfig

可以指定多个,用逗号隔开。

  • 步骤三:在其他类中引入这个User类即可(可以直接debug一下getDefaultUser方法,发现这个方法在启动过程中的确被调用到了)

注意:EnableAutoConfiguration注解会加载所有jar包下的META-INF下的spring.factories文件,在spring-boot-autoconfigure包下有一个自带的spring.factories文件,这个文件的配置会被加载。

@ComponentScan
这个用于指定描包的路径,如:

@ComponentScan(basePackages = "com.akichyan.scan")

我们可以在指定包下加一个类,这个类必需要使用@Component @Controller @Service等注解注册为bean

package com.akichyan.scan;

import org.springframework.stereotype.Component;

@Component
public class ScanBean {
    private String id = "SCAN_BAN_ID";

    public String getId() {
        return id;
    }
}

四 SpringBoot其它关键内容

4.1 SpringBoot配置properties文件

  • 读取默认配置文件中的属性

直接把proerty数据写在spring.properties文件中:

db.username=root
db.password=123456
db.maxIdle=20

然后直接使用@Value注解配置即可:

@RestController
public class HelloController {
    @Value("${db.username}")
    private String dbName;
    @Value("${db.maxIdle}")
    private int maxIdle;

    @RequestMapping("/")
    public String hello() {
        return dbName + ":" +maxIdle;
    }
}
  • 读取指定文件

可以使用@PropertySource注解来读取其他配置文件中的数据:

@Component 
@PropertySource("db.properties")
public class DBConfig {
    @Value("${db.name}")
    private String name;
    @Value("${db.password}")
    private String password;
    @Value("${db.url}")
    private String url;
}

db.properties文件内容:

db.name=root
db.password=123456
db.url=jdbc:mysql://localhost:3306/test

注意这个@PropertySource("db.properties")虽然是放在DBConfig这个类上的,但是其他类中也可以引用db.properties中的数据。

  • 使用@ConfigurationProperties自动映射

上个例子中properties中的数据的key和类对的字段名是有对应关系的,都是多了一个前缀db.,我们可以使用ConfigurationProperties来自动映射,可以避免多处写@Value:

@Component
@Data
@ConfigurationProperties(prefix = "db")
public class DBConfig {
    private String name;
    private String password;
    private String url;
}
  • 使用Environment对象来获取
@Repository
public class DataSourceFactory {
    @Autowired
    private Environment environment;
    public DataSource createDataSource() {
        String name = environment.getProperty("db.name");
        String password = environment.getProperty("db.password");
        String url = environment.getProperty("db.url");
        System.out.println(name + ":" + password + ":" + url);
        return new MyDataSource(name, password, url) ;
    }
}

Environment对象是SpringBoot用于保存properties数据的,直接引入即可,然后就可以使用这个对象来获取对象的property数据。

4.2 使用spring-boot-parent做版本控制

可以使用parent的方式和dependencyManagement的方式:

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.4.RELEASE</version>
  </parent>
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
      </dependency>
    </dependencies>
  </dependencyManagement>

Spring-boot除了基本maven外,还可以基本Gradle来使用,此外还可以使用Spring Boot CLI来使用。
网络上有的文章 说SpringBoot还要执行什么命令之类的,就是直接使用了SpringBoot CLI,如果使用Maven的话不需要执行任何命令

4.3 JavaConfig内容复习

除了使用xml文件配置bean外,SpringIoC还提供了一种JavaConfig的方式,比较简单,示例代码如下:

@Configuration
@ComponentScan("com.akichyan.scan")
@Import(DataSourceFactory.class)
public class MyAppConfig {
    @Bean
    public User emptyUser() {
        return new User();
    }

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyAppConfig.class);
        //.......
        DataSource dataSource = applicationContext.getBean(DataSource.class);
        System.out.println(dataSource);
    }

}
@Configuration
@PropertySource("db.properties")
public class DataSourceFactory {
    @Autowired
    private Environment environment;

    @Bean(name = "dataSource")
    @Profile("prod")
    public DataSource createProdDataSource() {
        System.out.println("Init prod datasource");
        String name = environment.getProperty("db.prod.name");
        String password = environment.getProperty("db.prod.password");
        String url = environment.getProperty("db.prod.url");
        return DataSourceBuilder.create().username(name).password(password).url(url).build();
    }

    @Bean(name = "dataSource")
    @Profile("dev")
    public DataSource createDevDataSource() {
        System.out.println("Init dev datasource");
        String name = environment.getProperty("db.dev.name");
        String password = environment.getProperty("db.dev.password");
        String url = environment.getProperty("db.dev.url");
        return DataSourceBuilder.create().username(name).password(password).url(url).build();
    }
}

启动时需要添加启动参数:

-Dspring.profiles.active="dev" 或 -Dspring.profiles.active="prod"
  • @Configuration: 注解在类上,表明此类是一个JavaConfig类,等同于xml文件中的<beans />标签。
  • @Import: 导入其他的JavaConfig类,类似于xml文件中的<import />标签
  • @Bean: 标记在方法上,这个方法会在Spring容器启动时被调用,方法的返回值会被注册成一个bean,等同于<bean />标签
  • Environment: 这是个类,不是注解,里面保存了properties文件中的数据
  • @PropertySource: 用于引入properties文件
  • @Profile 用于标记环境,在启动参数中激活环境

五 SpringApplication的工作流程

  • \color{red}{步骤一 :推断应该的启动类型。}就是说你要启动的应用到底是个普通的java应用,还是一个Web应用。SpringBoot中定义了三种类型:
public enum WebApplicationType {
    NONE,
    SERVLET,
    REACTIVE;
}

NONE : 就是一个普通的Java应用。
SERVLET:看名字就知道,servlet,一个Web应用。
REACTIVE:嗯,这个东西笔者没接触过,网上查了一下发现是Spring5.0出的响应式流的新框架。

默认值是SERVLET
SpringBoot会尝试去load Servlet和ConfigurableWebApplicationContext这两个类,只要有一个加载失败(就是说你根本就没引对应的jar包),就会认为是NONE类型。

简单重复一下:我们可以写一个类实现ApplicationContextInitializer,配置在spring.factories文件或者application.properties文件中,那Spring在刷新上下文时会调用这个实现类

  • \color{red}{步骤三 :查找所有的ApplicationListener}
    类似于上面的ApplicationListener,这是Spring的监听器,可以配置在spring.factories文件中,SpringBoot会自动查找。SpringBoot默认的配置文件中的监听器配置如下:
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer
  • \color{red}{步骤四 :查找所有启动类}
    SpringBoot先创建了一个RuntimeExecption类,然后拿到调用栈后依次判断涉及到的每个类是否包含main方法,如果包含,则认为那个类为启动类。

以上四步都是SpringApplication在初始化的时候做的事,接下来的步骤会在SpringApplication.run方法中完成

  • \color{red}{步骤五:查找并执行SpringApplicationRunListener的started方法}
    SpringApplicationRunListener与上面的ApplicationListener类似,是一个监听器,这个类中定义了以下几个方法:
public interface SpringApplicationRunListener {
    void starting();
    void environmentPrepared(ConfigurableEnvironment environment);
    void contextPrepared(ConfigurableApplicationContext context);
    void contextLoaded(ConfigurableApplicationContext context);
    void started(ConfigurableApplicationContext context);
    void running(ConfigurableApplicationContext context);
    void failed(ConfigurableApplicationContext context, Throwable exception);
}

同样的可以在spring.factories文件中配置,配置的key就是SpringApplicationRunListener的全类名。
SpringBoot查找到这些类后会马上实例化,并调用这些类的stared方法。

  • \color{red}{步骤六:初始化Environment}

Environment是Spring的环境类,主要是包含了perperties信息。还包含了Spring当前所处的环境信息,如dev,prod等。

  • 首先会根据当前的应用来型来创建不同的对象:
    private ConfigurableEnvironment getOrCreateEnvironment() {
        if (this.environment != null) {
            return this.environment;
        }
        switch (this.webApplicationType) {
        case SERVLET:
            return new StandardServletEnvironment();
        case REACTIVE:
            return new StandardReactiveWebEnvironment();
        default:
            return new StandardEnvironment();
        }
    }

创业对象完成后,会去加载properties文件中的数据

  • \color{red}{步骤七:打印banner}

这一步作者还没有去研究,先贴一下书上说的内容:

如果SpringApplication的showBanner属性被设置为true,则打印banner(SpringBoot 1.3.x版本,这里应该是基于Banner.Mode决定banner的打印行为)。这一步的逻辑其实可以不关心,我认为唯一的用途就是“好玩”(Just For Fun)。

  • \color{red}{步骤八:初始化ApplicationContext对象}

首先会创建ApplicationContext对象,同样的会根据应用类型来使用不同的ApplicationContext实现类。

然后会根据用户的设置来判断是否需要使用指定的beanNameGenerator,以及是否需要使用自定义的resourceLoader。

接着会调用ApplicationContextInitializer的initialize方法
接着会调用SpringApplicationRunListeners的contextPrepared方法
然后会调用ApplicationContext对象的refresh方法(这个方法其实也就是SpringIoC容器初始化的方法,这个方法调用完说明IoC容器完成了)
然后会调用SpringApplicationRunListener的started方法
然后会调用SpringApplicationRunListener的running方法

至此SpringBoot就算启动完成了,以上过程看似复杂,其实大部都是在调用一下Listener和EventListener的相应方法,如果把这些方法去掉,整个启动过程其实可以简化为以下四步:

  • 从配置文件中查找SpringApplicationRunListener对象,ApplicationContextInitializer对象,ApplicationListener对象等。也就是把我们注册的监听器全找出来。
  • 初始化Environment对象,包括加载properties文件,处理profile信息。
  • 初始化ApplicationContext对象。
  • refresh ApplicationContext

    SpringBoot启动流程

相关文章

网友评论

      本文标题:Spring Boot入门

      本文链接:https://www.haomeiwen.com/subject/emrzgqtx.html