SpringBoot 框架

一、SpringBoot 概述

1.1 SpringBoot 概念

SpringBoot提供了一种快速使用Spring的方式,基于约定优于配置的思想,可以让开发人员不必在配置与逻辑业务之间进行思维的切换,全身心的投入到逻辑业务的代码编写中,从而大大提高了开发的效率,一定程度上缩短了项目周期。

2014 年 4 月,Spring Boot 1.0.0 发布。Spring的顶级项目之一(https://spring.io)。

img

1.2 Spring 缺点

1) 配置繁琐

虽然Spring的组件代码是轻量级的,但它的配置却是重量级的。

一开始,Spring用XML配置,而且是很多XML配置。

Spring 2.5 引入了基于注解的组件扫描,这消除了大量针对应用程序自身组件的显式XML配置。

Spring 3.0 引入了基于Java的配置,这是一种类型安全的可重构配置方式,可以代替XML。

所有这些配置都代表了开发时的损耗。因为在思考Spring特性配置和解决业务问题之间需要进行思维切换,所以编写配置挤占了编写应用程序逻辑的时间。和所有框架一样,Spring实用,但它要求的回报也不少。

2)依赖繁琐

项目的依赖管理也是一件耗时耗力的事情。在环境搭建时,需要分析要导入哪些库的坐标,而且还需要分析导入与之有依赖关系的其他库的坐标,一旦选错了依赖的版本,随之而来的不兼容问题就会严重阻碍项目的开发进度。

1.3 SpringBoot 功能

1) 自动配置

Spring Boot的自动配置是一个运行时(更准确地说,是应用程序启动时)的过程,考虑了众多因素,才决定Spring配置应该用哪个,不该用哪个。该过程是SpringBoot自动完成的。

2) 起步依赖

起步依赖本质上是一个Maven项目对象模型(Project Object Model,POM),定义了对其他库的传递依赖,这些东西加在一起即支持某项功能。简单的说,起步依赖就是将具备某种功能的坐标打包到一起,并提供一些默认的功能。

3) 辅助功能

提供了一些大型项目中常见的非功能性特性,如嵌入式服务器、安全、指标,健康检测、外部配置等。

Spring Boot 并不是对 Spring 功能上的增强,而是提供了一种快速使用 Spring 的方式。

1.4 小结

SpringBoot提供了一种快速开发Spring项目的方式,而不是对Spring功能上的增强。
Spring的缺点:

  • 配置繁琐
  • 依赖繁琐

SpringBoot功能:

  • 自动配置
  • 起步依赖:依赖传递
  • 辅助功能

二、SpringBoot 快速入门

2.1、需求

搭建SpringBoot工程,定义HelloController.hello()方法,返回”Hello SpringBoot!”。

2.2、实现步骤

① 创建Maven项目

在porm.xml配置以下代码,导入SpringBoot起步依赖

<!--springboot工程需要继承的父工程-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <version>2.3.0.RELEASE</version>
        <artifactId>spring-boot-starter-parent</artifactId>
 
    </parent>
 
    <dependencies>
    <!--web开发的起步依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

③ 定义Controller

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

④ 编写引导类

引导类作SpringBoot的项目入口

/**
 * 引导类。SpringBoot项目的入口
 */
@SpringBootApplication
public class HelloApplication {
    public static void main(String[] args) {
        SpringApplication.run(HelloApplication.class,args);
    }
}

⑤ 启动测试

http://localhost:8080/hello/

2.3、Spring Initializr创建SpringBoot工程

(1)直接选中Spring Initializr
img

(2)我们这里创建web工程,选中web即可
img(3) 创建完毕,SpringBoot会自动配置好需要的依赖和创建相关目录

(4) 自己创建controller测试即可

2.4、SpringBoot起步依赖原理分析

  • 在spring-boot-starter-parent中定义了各种技术的版本信息,组合了一套最优搭配的技术版本。
  • 在各种starter中,定义了完成该功能需要的坐标合集,其中大部分版本信息来自于父工程。
  • 我们的工程继承parent,引入starter后,通过依赖传递,就可以简单方便获得需要的jar包,并且不会存在版本冲突等问题

2.5、总结

  • SpringBoot在创建项目时,使用jar的打包方式。
  • SpringBoot的引导类,是项目入口,运行main方法就可以启动项目。

三、配置

3.1 配置文件分类

SpringBoot是基于约定的,所以很多配置都有默认值,但如果想使用自己的配置替换默认配置的话,就可以使用 application.properties或者application.yml(application.yaml)进行配置。
properties:

server.port=8080

yaml:

server:
  port: 8080

总结:

  • SpringBoot提供了2种配置文件类型:properteis和yml/yaml
  • 默认配置文件名称:application
  • 在同一级目录下优先级为:properties > yml > yaml

3.2 yaml

yaml:YAML全称是 YAML Ain’t Markup Language 。YAML是一种直观的能够被电脑识别的的数据数据序列化格式,并且容易被人类阅读,容易和脚本语言交互的,可以被支持YAML库的不同的编程语言程序导入,比如: C/C++, Ruby, Python, Java, Perl, C#, PHP等。YML文件是以数据为核心的,比传统的xml方式更加简洁。 YAML文件的扩展名可以使用.yml或者.yaml。

对比:

properties:

server.port=8080
server.address=127.0.0.1

xml:

<server>
    <port>8080</port>
    <address>127.0.0.1</address>
</server>

yaml:

server:
  port: 8080
  address: 127.0.0.1

可以看出:对比其他两种方式,yaml更简洁,以数据为核心

yaml基本语法

  • 大小写敏感
  • 数据值前边必须有空格,作为分隔符
  • 使用缩进表示层级关系
  • 缩进时不允许使用Tab键,只允许使用空格(各个系统 Tab对应的 空格数目可能不同,导致层次混乱)。
  • 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
  • # 表示注释,从这个字符一直到行尾,都会被解析器忽略。
server:  
  port: 8080
  address: 127.0.0.1
name: abc

yaml数据格式

对象(map):键值对的集合

person:
  name: zhangsan
# 行内写法
person: {name: zhangsan}

数组:一组按次序排列的值

address:
  - beijing
  - shanghai
# 行内写法
address: [beijing,shanghai]

纯量:单个的,不可再分的值

msg1: 'hello \n world' # 单引忽略转义字符
msg2: "hello \n world" # 双引识别转义字符

yaml参数引用

name: lisi

person:
  name: ${name} # 引用上边定义的name值

3.3 读取配置文件内容

先预先准备好测试的ymal文件:

name: xpp

person:
  name: ${name}
  age: 23
  address:
    - benjing
    - shanghai

address:
  - benjing
  - shanghai

msg1: 'hello \n springboot'
msg2: "hello \n springboot"

@Value

@Value("${name}")
private String name;
@Value("${person.name}")
private String name1;
@Value(("${address[0]}"))
private String address1;
@Value("${msg1}")
private String msg1;
@Value("${msg2}")
private String msg2;

@RequestMapping("/hello2")
public String hello2(){
    System.out.println(name);
    System.out.println(name1);
    System.out.println(address1);
    System.out.println(msg1);
    System.out.println(msg2);
    return "Hello SpringBoot !";
}

输出结果:
xpp
xpp
benjing
hello \n springboot
hello
springboot

Environment

Environment读取yaml配置文件

@Autowired
private Environment env;

@RequestMapping("/hello2")
public String hello2(){
    System.out.println(env.getProperty("name"));
    System.out.println(env.getProperty("person.age"));
    System.out.println(env.getProperty("address[0]"));

    return "Hello SpringBoot !";
}

输出:
xpp
23
benjing

@ConfigurationProperties

我们使用 @Value 注解或着使用 Spring Environment bean 访问这些属性,这种注入配置方式有时显得很笨重。我们将使用更安全的方式(@ConfigurationProperties )来获取这些属性

准备一个Person类:

@Component//表示这个类被spring识别了
@ConfigurationProperties(prefix = "person")//绑定前缀
//下面四个注解为LomBok提供的,简化开发,自动帮我们写好get,set,有参,无参和toString方法
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Person {
    private String name;
    private Integer age;
    private String[] address;
}

测试:

@Autowired
private Person person;

@RequestMapping("/hello2")
public String hello2(){
    System.out.println(person);
    return "Hello SpringBoot !";
}

输出结果:
Person(name=xpp, age=23, address=[benjing, shanghai])

3.4 profile

我们在开发Spring Boot应用时,通常同一套程序会被安装到不同环境,比如:开发、测试、生产等。其中数据库地址、服务器端口等等配置都不同,如果每次打包时,都要修改配置文件,那么非常麻烦。profile功能就是来进行动态配置切换的。

profile配置方式

(1)多profile文件方式

提供多个配置文件,每一个代表一种环境:

  • application-dev.properties/yml 开发环境
  • application-test.properties/yml 测试环境
  • application-pro.properties/yml 生产环境

注意!:格式必须为application-xxx.properties/yml

img
在主配置文件application.properties选择用哪种环境:

格式:spring.profiles.active=xxx

spring.profiles.active=dev

(2)yaml多文档方式

---用来划分yaml文件区域

---
server:
  port: 8081
spring:
  config:
    activate:
      on-profile: dev
---
server:
  port: 8082
spring:
  config:
    activate:
      on-profile: test
---
server:
  port: 8083
spring:
  config:
    activate:
      on-profile: pro
---
spring:
  profiles:
    active: test

profile激活方式

(1)配置文件
即上面所讲的:在配置文件中配置:spring.profiles.active=dev

(2)虚拟机
在VM options 指定:-Dspring.profiles.active=xxx

①直接在Program arguments配置
img

②打包方式配置

img

进入target文件夹(快捷键Ctrl+Alt+F12)

img

在当前目录打开cmd

输入java –jar xxx.jar启动SpringBoot项目

输入java –jar xxx.jar --spring.profiles.active=xxx即可更改环境

3.5 内置配置加载顺序

Springboot程序启动时,会从以下位置加载配置文件:

  1. file:./config/:当前项目下的/config目录下
  2. file:./ :当前项目的根目录
  3. classpath:/config/:classpath的/config目录
  4. classpath:/ :classpath的根目录(之前我们用的就是这种)

加载顺序为上文的排列顺序,高优先级配置的属性会生效

img

3.6 外部配置加载顺序

命令行参数

通过官网查看外部属性加载顺序:

https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html

四、整合其他框架

4.1 整合Junit

  1. 搭建SpringBoot工程

  2. 引入starter-test起步依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
  1. 编写测试类
@Service
public class UserService {
    public void add(){
        System.out.println("add...");
    }
}

  1. 编写测试方法
@SpringBootTest(classes = SpringbootTestApplication.class)
//这里加不加classes取决于当前测试类包所在的位置
//在引导类所在包的子包或同级则不需要加(会自动找引导类),否则要加
class SpringbootRedisApplicationTests {

    @Autowired
    UserService userService;
    @Test
    void contextLoads() {
        userService.add();
    }
}

4.2 整合Redis

  1. 搭建SpringBoot工程

  2. 引入redis起步依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
  1. 配置redis相关属性
spring:
  redis:
    host: 127.0.0.1 #redis的主机ip
    port: 6379
  1. 注入RedisTemplate模板

  2. 编写测试方法,测试(记得打开本机的redis)

@SpringBootTest
class SpringbootRedisApplicationTests {

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public void testSet(){
        //存数剧
        redisTemplate.boundValueOps("name").set("zhangsan");
    }
    @Test void testGet(){
        //获取数据
        Object name = redisTemplate.boundValueOps("name").get();
        System.out.println(name);
    }
}

4.3 整合MyBatis

  1. 搭建SpringBoot工程

  2. 引入mybatis起步依赖,添加mysql驱动

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.2.0</version>
</dependency>

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

  1. 编写DataSource和MyBatis相关配置

DataSource配置信息:

spring:
  datasource:
    url: jdbc:mysql:///mzz
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver

用注解开发可以不用写MyBatis的配置xml开发MyBatis相关配置

mybatis:
  mapper-locations: classpath:mapper/*Mapper.xml #mapper映射文件路径
  type-aliases-package: com.itheima.springbootmybatis.domain #配置别名
#config-location: 指定mybatis的核心配置文件
  1. 定义表和实体类

USE `mzz`;

DROP TABLE IF EXISTS `t_user`;

CREATE TABLE `t_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `password` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

insert  into `t_user`(`id`,`username`,`password`) values (1,'zhangsan','123'),(2,'lisi','234');

实体类

@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Integer id;
    private String username;
    private String password;
}

  1. 编写dao和mapper文件/纯注解开发

xml开发:

@Mapper
@Repository
public interface UserXmlMapper {
    public List<User> findAll();
}

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.springbootmybatis.mapper.UserXmlMapper">
    <select id="findAll" resultType="user">
        select * from t_user
    </select>
</mapper>

纯注解开发:

@Mapper
@Repository//这里可加可不加,mybatis提供@Mapper可以代替
public interface UserMapper {
    @Select("select * from t_user")
    public List<User> findAll();
}

  1. 测试
@SpringBootTest
class SpringbootMybatisApplicationTests {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserXmlMapper userXmlMapper;

    @Test
    void testFindAll() {
        List<User> res = userMapper.findAll();
        for (User user : res) {
            System.out.println(user);
        }
    }

    @Test
    void testFindAll1() {
        List<User> res = userXmlMapper.findAll();
        for (User user : res) {
            System.out.println(user);
        }
    }
}

五、SpringBoot自动配置

5.1 Condition

Condition 是在Spring 4.0 增加的条件判断功能,通过这个可以功能可以实现选择性的创建 Bean 操作。

满足条件才创建,不满足不创建。

思考:

SpringBoot是如何知道要创建哪个Bean的?比如SpringBoot是如何知道要创建RedisTemplate的?

引出问题

看一个栗子:

当我们没导入redis-start时,会报错

@SpringBootApplication
public class SpringbootDemo01Application {

    public static void main(String[] args) {
        //启动SpringBoot应用,返回Spring的IOC容器
        ConfigurableApplicationContext run = SpringApplication.run(SpringbootDemo01Application.class, args);
        //获取Bean,redisTemplate
        Object redisTemplate = run.getBean("redisTemplate");
        System.out.println(redisTemplate);

    }
}

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'redisTemplate' available

当导入redis起步依赖后

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

org.springframework.data.redis.core.RedisTemplate@b7ff25

问题:

SpringBoot是怎么知道我们导入redis坐标的呢?

案例

需求

在 Spring 的 IOC 容器中有一个 User 的 Bean,现要求:

  1. 导入Jedis坐标后,加载该Bean,没导入,则不加载。
  2. 将类的判断定义为动态的。判断哪个字节码文件存在可以动态指定。

bean:

public class User {
}
//自定义注解可以合并多个注解

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
// 将自定义注解放到@Conditional中
@Conditional(ClassCondition.class)
public @interface ConditionOnClass {
    String[] value();
}

@Configuration
public class UserConfig {
    @Bean
    //@Conditional(ClassCondition.class)
    //有Jedis字节码
    @ConditionOnClass("redis.clients.jedis.Jedis")
    public User user(){
        return new User();
    }
}

自定义注解:

public class ClassCondition implements Condition {

    /**
     * @param context  上下文对象,用于获取环境,ClassLoader对象
     * @param metadata 注解的元对象,可以用于注解定义的属性值
     * @return
     */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment environment = context.getEnvironment();

        //1.需求:导入指定坐标后创建Bean
        //思路:判断指定坐标文件是否存在

        //获取注解属性值 value
        Map<String, Object> map = metadata.getAnnotationAttributes(ConditionOnClass.class.getName());
        String[] value = (String[]) map.get("value");
        boolean flag = true;
        try {
            for (String className : value) {
                // 获得class对象
                Class<?> cls = Class.forName(className);
            }
        } catch (ClassNotFoundException e) {
            //异常报错
            flag = false;
        }
        return flag;
    }
}

总结

自定义条件:

① 定义条件类:自定义类实现Condition接口,重写 matches 方法,在 matches 方法中进行逻辑判断,返回 boolean值 。 matches 方法两个参数:

  • context:上下文对象,可以获取属性值,获取类加载器,获取BeanFactory等。
  • metadata:元数据对象,用于获取注解属性。

② 判断条件:在初始化Bean时,使用 @Conditional(条件类.class)注解

SpringBoot 提供的常用条件注解:

  • ConditionalOnProperty:判断配置文件中是否有对应属性和值才初始化Bean
@Bean
@ConditionalOnProperty(name = "itcast",havingValue = "itheima")
public User user1(){
    return new User();
}

当配置文件中有一个键为itcast,有一个值为itheima时才会去加载对应的这个bean。

itcast=itheima

  • ConditionalOnClass:判断环境中是否有对应字节码文件才初始化Bean

  • ConditionalOnMissingBean:判断环境中没有对应Bean才初始化Bean

5.2 切换内置web服务器

SpringBoot的web环境中默认使用tomcat作为内置服务器,其实SpringBoot提供了4中内置服务器供我们选择,我们可 以很方便的进行切换。

image-20220425132501138

默认Tomcat

在这里插入图片描述

如果要使用其他的服务器

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <!--排除tomcat依赖-->
    <exclusions>
        <exclusion>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <groupId>org.springframework.boot</groupId>
        </exclusion>
    </exclusions>
</dependency>
<!--引入相应服务器的依赖-->
<dependency>
    <artifactId>spring-boot-starter-jetty</artifactId>
    <groupId>org.springframework.boot</groupId>
</dependency>

在这里插入图片描述

5.3 @Enable*注解

SpringBoot中提供了很多Enable开头的注解,这些注解都是用于动态启用某些功能的。而其底层原理是使用@Import注 解导入一些配置类,实现Bean的动态加载。

提问:SpringBoot 工程是否可以直接获取jar包中定义的Bean?

答:不可以

案例:

两个子模块,自己构造一个@Enable注解

①子模块要得到②子模块的User类的bean(这里用编号表示)

①导入②的依赖:

<dependency>
    <groupId>com.itheima</groupId>
    <artifactId>springboot-embal</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

①的引导类

/**
 * 不能的原因在于 @ComponentScan
 * @ComponentScan扫描范围:当前引导类所在包及其子包
 * //1.使用@ComponentScan扫描com.itheima.springbooyembal包
 * //2.可以使用@Import注解,加载类,这些类都会被Spring创建,并放入IOC容器。
 * //3.可以对@Import注解进行封装
 */

@SpringBootApplication
//@ComponentScan("com.itheima.springbooyembal")
//@Import(UserConfig.class)
@EnableUser
public class SpringbootDemo01Application {

    public static void main(String[] args) {
        //启动SpringBoot应用,返回Spring的IOC容器
        ConfigurableApplicationContext run = SpringApplication.run(SpringbootDemo01Application.class, args);

        Object user = run.getBean("user");
        System.out.println(user);

    }
}

②的配置类

@Configuration
public class UserConfig {
    @Bean
    public User user(){
        return new User();
    }
}

②的自定义@EnableUser注解

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(UserConfig.class)
public @interface EnableUser {
}

5.4 @Import注解

@Enable*底层依赖于@Import注解导入一些类,使用@Import导入的类会被Spring加载到IOC容器中。而@Import提供4中用法:

导入Bean 【@Import(User.classs)

导入配置类 【@Import(UserConfig.class)

导入 ImportSelector 实现类。一般用于加载配置文件中的类

@Import(MyImportSelector.class)

public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[{"com.itheima.springbooyembal.domain.User","com.itheima.springbooyembal.domain.Role"};
    }
}

导入 ImportBeanDefinitionRegistrar 实现类。

@Import(MyImportBeanDefinitionRegistrar.class)

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition();
        registry.registerBeanDefinition("user",beanDefinition);
    }
}

5.5 @EnableAutoConfiguration

  • @EnableAutoConfiguration 注解内部使用 @Import(AutoConfigurationImportSelector.class)来加载配置类。
  • 配置文件位置:META-INF/spring.factories,该配置文件中定义了大量的配置类,当 SpringBoot 应用启动时,会自动加载 这些配置类,初始化Bean
  • 并不是所有的Bean都会被初始化,在配置类中使用Condition来加载满足条件的Bean

5.6 starter案例

需求

自定义redis-starter。要求当导入redis坐标时,SpringBoot自动创建Jedis的Bean

实现步骤

① 创建 redis-spring-boot-autoconfigure 模块

image-20221024094229414

<!--引入jedis依赖-->
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency>

② 创建 redis-spring-boot-starter 模块吗,依赖 redis-spring-boot-autoconfigure的模块

image-20221024095641398

<!--引入自定义的autocongifure-->
<dependency>
    <groupId>com.ithiema</groupId>
    <artifactId>redis-spring-boot-autocongifure</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

③ 在 redis-spring-boot-autoconfigure 模块中初始化 Jedis 的 Bean。并定义META-INF/spring.factories 文件

作用:

把需要加载的bean的配置类加入到EnableAutoConfiguration中
springboot启动时会加载这些配置类,放入IOC容器中

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.ithiema.redis.config.RedisAutoConfiguration
// 以redis开头的配置 会和RedisProperties相绑定
@ConfigurationProperties(prefix = "redis")
@Data
public class RedisProperties {
    // 用户不配置 默认为本机
    private String host="localhost";
    private Integer port=6379;
    
    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public int getPort() {
        return port;
    }

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

}
@Configuration
// 启用RedisProperties 被spring识别
@EnableConfigurationProperties(RedisProperties.class)
@ConditionalOnClass(Jedis.class)
public class RedisAutoConfiguration {
    /**
     *提供Jedis的bean
     */
    @Bean
    @ConditionalOnMissingBean(name="jedis")
    public Jedis jedis(RedisProperties redisProperties){
        System.out.println("xppmzz");
        return new Jedis(redisProperties.getHost(),redisProperties.getPort());
    }
}

④ 在测试模块中引入自定义的 redis-starter 依赖,测试获取 Jedis 的Bean,操作 redis。

<dependency>
    <groupId>com.itheima</groupId>
    <artifactId>redis-sping-boot-start</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>
@SpringBootApplication
public class SpringbootEnablrApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(SpringbootEnablrApplication.class, args);
        Jedis jedis = run.getBean(Jedis.class);
        jedis.set("name11", "xppmzz");
        System.out.println(jedis);
    }
}

六、SpringBoot 监听机制

6.1 Java 监听机制

SpringBoot 的监听机制,其实是对Java提供的事件监听机制的封装。

Java中的事件监听机制定义了以下几个角色:

① 事件:Event,继承 java.util.EventObject 类的对象

② 事件源:Source ,任意对象Object

③ 监听器:Listener,实现 java.util.EventListener 接口 的对象

6.2 SpringBoot监听机制

SpringBoot 在项目启动时,会对几个监听器进行回调,我们可以实现这些监听器接口,在项目启动时完成 一些操作。 ApplicationContextInitializer、SpringApplicationRunListener、CommandLineRunner、ApplicationRunner

ApplicationContextInitializer

不是监听器,但可以当做监听器来用

// 在banner 图标之后 就开始初始化
// 用于项目还没有准备IOC容器之前,去检测一些资源是否存在
@Component
public class MyApplicationContextInitializer implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        System.out.println("ApplicationContextInitializer...initialize");
    }
}

SpringApplicationRunListener

public class MySpringApplicationRunListener implements SpringApplicationRunListener {
    public MySpringApplicationRunListener(SpringApplication application,String[] args) {
    }

    @Override
    public void starting(ConfigurableBootstrapContext bootstrapContext) {
        SpringApplicationRunListener.super.starting(bootstrapContext);
    }

    @Override
    public void starting() {
        System.out.println("starting...项目启动中");
    }

    @Override
    public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
        SpringApplicationRunListener.super.environmentPrepared(bootstrapContext, environment);
    }

    @Override
    public void environmentPrepared(ConfigurableEnvironment environment) {
        System.out.println("environmentPrepared...环境对象开始准备");
    }

    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
        System.out.println("contextPrepared...上下文对象开始准备");
    }

    @Override
    public void contextLoaded(ConfigurableApplicationContext context) {
        //到此时,IOC容器已经初始化好了
        System.out.println("contextLoaded...上下文对象开始加载");
    }

    @Override
    public void started(ConfigurableApplicationContext context) {
        System.out.println("started...上下文对象加载完成");
    }

    @Override
    public void running(ConfigurableApplicationContext context) {
        System.out.println("running...项目启动完成,开始运行");
    }

    @Override
    public void failed(ConfigurableApplicationContext context, Throwable exception) {
        System.out.println("failed...项目启动失败");

    }
}

CommandLineRunner

@Component
public class MyCommandLineRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("CommandLineRunner...run");
        System.out.println(Arrays.asList(args));
    }
}

ApplicationRunner

/**
 * 当项目启动后执行run方法
 * 可以用于提前加载缓存redis 缓存预热
 */
@Component
public class MyApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("ApplicationRunner...run");
        System.out.println(Arrays.asList(args.getSourceArgs()));
    }
}

ApplicationContextInitializer、SpringApplicationRunListener使用需要在META-INF中配置。

org.springframework.context.ApplicationContextInitializer=com.itheima.springbootlistener.listener.MyApplicationContextInitializer

org.springframework.boot.SpringApplicationRunListener=com.itheima.springbootlistener.listener.MySpringApplicationRunListener

6.3 SpringBoot启动流程

SpringBoot启动流程

6.4 SpringBoot Actuator

SpringBoot自带监控功能Actuator,可以帮助实现对程序内部运行情况监控,比如监控状况、Bean加载情况、配置属性 、日志信息等。

  1. 使用步骤

① 导入依赖坐标

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

② 访问http://localhost:8080/actuator

  1. SpringBoot 监控使用
路径描述
/beans描述应用程序上下文里全部的Bean,以及它们的关系
/env获取全部环境属性
/env/{name}根据名称获取特定的环境属性值
/health报告应用程序的健康指标,这些值由HealthIndicator的实现类提供
/info获取应用程序的定制信息,这些信息由info打头的属性提供
/mappings描述全部的URI路径,以及它们和控制器(包含Actuator端点)的映射关系
/metrics报告各种应用程序度量信息,比如内存用量和HTTP请求计数
/metrics/{name}报告指定名称的应用程序度量值
/trace提供基本的HTTP请求跟踪信息(时间戳、HTTP头等)

6.5 SpringBoot Admin

Spring Boot Admin是一个开源社区项目,用于管理和监控SpringBoot应用程序。
Spring Boot Admin 有两个角色,客户端(Client)和服务端(Server)。
应用程序作为Spring Boot Admin Client向为Spring Boot Admin Server注册
Spring Boot Admin Server 的UI界面将Spring Boot Admin Client的Actuator Endpoint上的一些监控信息

admin-server

① 创建 admin-server 模块

② 导入依赖坐标 admin-starter-server

<dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-starter-server</artifactId>
</dependency>

③ 在引导类上启用监控功能@EnableAdminServer

@SpringBootApplication
@EnableAdminServer
public class SpringbootAdminServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootAdminServerApplication.class, args);
    }
}

admin-client

① 创建 admin-client 模块

② 导入依赖坐标 admin-starter-client

<dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-starter-client</artifactId>
</dependency>

③ 配置相关信息:server地址等

#指定admin.server地址
spring.boot.admin.client.url=http://localhost:9000
#展示健康检查详细详细展示出来
management.endpoint.health.show-details=always
#开启所有配置
management.endpoints.web.exposure.include=*

④ 启动server和client服务,访问server

image-20221025100651781

七、SpringBoot 项目部署

SpringBoot 项目开发完毕后,支持两种方式部署到服务器:

① jar包(官方推荐)

② war包

jar类型项目会打成jar包:jar类型项目使用SpringBoot打包插件打包时,会在打成的jar中内置一个tomcat的jar。所以我们可以使用jdk直接运行该jar项目可,jar项目中有一个功能,将功能代码放到其内置的tomcat中运行。我们直接使用浏览器访问即可。

war类型项目会打成war包:在打包时需要将内置的tomcat插件排除,配置servlet的依赖。将war正常的放到tomcat服务器中运行即可。

7.1 jar打包方式

  1. 创建 spring-boot-deploy 模块

  2. 将当前模块打包

    image-20221025101053783

  3. 控制台打包成功,显示target目录

    image-20221025101551301

  4. 把jar包放在需要的目录,在当前目录打开cmd,输入java -jar .\jar包名称,启动成功

7.2 war打包方式

  1. pom.xml里更改打包方式
<packaging>war</packaging>
  1. 在引导类继承SpringBootServletInitializer类,并重写configure方法
@SpringBootApplication
public class SpringBootDeployApplication extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootDeployApplication.class, args);
    }
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(SpringBootDeployApplication.class);
    }
}
  1. 控制台打包成功,显示target目录

image-20221025101923042

  1. 将其放在tomcat目录下的webapps目录下

    image-20221025101956115

  2. 启动tomcat即可

image-20221025102020368

  1. 此时浏览器访问需要加项目的名称,因为WEB-INF文件在其之下
posted @ 2021-12-26 21:20  王陸  阅读(970)  评论(0编辑  收藏  举报