美文网首页
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