Spring Boot入门

2019-05-09  本文已影响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类,我们可以把它拆一下,方便理解:

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() ;
    }
}

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类。可以写一个示例代码:

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();
    }
}
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.akichyan.config.MyAppConfig

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

注意: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中的数据。

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

@Component
@Data
@ConfigurationProperties(prefix = "db")
public class DBConfig {
    private String name;
    private String password;
    private String url;
}
@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"

五 SpringApplication的工作流程

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在刷新上下文时会调用这个实现类

org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer

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

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方法。

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文件中的数据

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

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

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

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

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

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

上一篇 下一篇

猜你喜欢

热点阅读