文章引用

同篇文章引自亮哥博客 SpringBoot2.X进阶 : https://haoyongliang.gitee.io

springBoot入门回顾

  1. profile是用来完成不同环境下,配置动态切换功能的。 spring.profiles.active=dev, application-dev
  2. application.properties > application.yml > application.yaml
  3. springboot 整合第三方工具,只需导入starter的依赖包即可

Spring Boot高级

1. SpringBoot 原理分析

1.1 Condition

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

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

案例:需求

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

  1. 导入Jedis坐标后,加载该Bean,没导入,则不加载

  2. 新建maven工程,导入依赖

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    <?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.3.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>springboot-day02</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-day02</name>
    <description>Demo project for Spring Boot</description>

    <properties>
    <java.version>1.8</java.version>
    </properties>

    <dependencies>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    </dependency>
    <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.4</version>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
    <exclusions>
    <exclusion>
    <groupId>org.junit.vintage</groupId>
    <artifactId>junit-vintage-engine</artifactId>
    </exclusion>
    </exclusions>
    </dependency>
    </dependencies>

    <build>
    <plugins>
    <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
    </plugins>
    </build>

    </project>


  3. 编写SpringApplication

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    package com.example.springbootday02;

    import com.example.springbootday02.domain.User;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.ConfigurableApplicationContext;
    import org.springframework.data.redis.core.RedisTemplate;

    @SpringBootApplication
    public class SpringbootDay02Application {

    public static void main(String[] args) {

    ConfigurableApplicationContext run = SpringApplication.run(SpringbootDay02Application.class, args);

    // RedisTemplate redisTemplate = (RedisTemplate) run.getBean("redisTemplate");
    // System.out.println(redisTemplate);

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


    }


  4. 编写ClassCondition

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    package com.example.springbootday02.condition;

    import org.springframework.context.annotation.Condition;
    import org.springframework.context.annotation.ConditionContext;
    import org.springframework.core.type.AnnotatedTypeMetadata;
    import redis.clients.jedis.Jedis;

    public class ClassCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
    try {
    Class.forName("redis.clients.jedis.Jedis");
    } catch (ClassNotFoundException e) {
    e.printStackTrace();
    return false;
    }
    return true;
    }
    }

  5. 编写UserConfig类和User类

    1
    2
    3
    4
    5
    6
    7
    8
    package com.example.springbootday02.domain;


    public class User {

    }


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23




    package com.example.springbootday02.config;

    import com.example.springbootday02.condition.ClassCondition;
    import com.example.springbootday02.domain.User;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Conditional;
    import org.springframework.context.annotation.Configuration;

    @Configuration
    public class UserConfig {

    @Bean("user")
    @Conditional(ClassCondition.class)
    public User getUser(){
    return new User();
    }
    }


    1. 将类的判断定义为动态的。判断哪个字节码文件存在可以动态指定。

    2. 定义注解MyConditionOnClass

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
   package com.example.springbootday02.condition;

import org.springframework.context.annotation.Conditional;

import java.lang.annotation.*;

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(ClassCondition.class)
public @interface MyConditionOnClass {

String[] value();
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package com.example.springbootday02.condition;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.util.MultiValueMap;

import java.util.Map;

public class ClassCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
// try {
// Class.forName("redis.clients.jedis.Jedis");
// } catch (ClassNotFoundException e) {
// e.printStackTrace();
// return false;
// }
// return true;
Map<String, Object> myConditionOnClass = annotatedTypeMetadata.getAnnotationAttributes(MyConditionOnClass.class.getName());
try {
String[] value = (String[]) myConditionOnClass.get("value");
for (String classes : value){
Class.forName(classes);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
return false;
}
return true;
}
}

  1. UserConfig 使用 MyConditionOnClass注解
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    package com.example.springbootday02.config;

    import com.example.springbootday02.condition.ClassCondition;
    import com.example.springbootday02.condition.MyConditionOnClass;
    import com.example.springbootday02.domain.User;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Conditional;
    import org.springframework.context.annotation.Configuration;

    @Configuration
    public class UserConfig {

    @Bean("user")
    // @Conditional(ClassCondition.class)
    @MyConditionOnClass("redis.clients.jedis.Jedis")
    public User getUser(){
    return new User();
    }
    }

    使用springboot提供的注解 实现条件判断
1
2
3
4
5
6
@Bean("user2")
@ConditionalOnProperty(name = "itheima",havingValue = "itcast")
public User getUser2(){
return new User();
}

1
itheima=itcast
1.1.1 Condition – 小结
  1. 自定义条件:
    1. 定义条件类:自定义类实现Condition接口,重写 matches 方法,在 matches 方法中进行逻辑判断,返回 boolean值 。 matches 方法两个参数:
      1. context:上下文对象,可以获取属性值,获取类加载器,获取BeanFactory等。
      2. metadata:元数据对象,用于获取注解属性。
    2. 判断条件: 在初始化Bean时,使用 @Conditional(条件类.class)注解
  2. SpringBoot 提供的常用条件注解:
    1. ConditionalOnProperty:判断配置文件中是否有对应属性和值才初始化Bean
    2. ConditionalOnClass:判断环境中是否有对应字节码文件才初始化Bean
    3. ConditionalOnMissingBean:判断环境中没有对应Bean才初始化Bean

1.2 切换内置web服务器

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-tomcat</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>

1.3 @Enable*注解

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.example.springbootday02enable;

import com.example.springbootday02enableother.config.EnableUser;
import com.example.springbootday02enableother.config.UserConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import org.springframework.stereotype.Component;

/**
* @ComponentScan 扫描范围:当前引导类所在包及其子包
*
* com.itheima.springbootenable
* com.itheima.config
* //1.使用@ComponentScan扫描com.itheima.config包
* //2.可以使用@Import注解,加载类。这些类都会被Spring创建,并放入IOC容器
* //3.可以对Import注解进行封装。
*/
@SpringBootApplication
//@ComponentScan(basePackages="com.example.springbootday02enableother")
//@Import(UserConfig.class)
@EnableUser
public class SpringbootDay02EnableApplication {

public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(SpringbootDay02EnableApplication.class, args);
Object user = run.getBean("user");
System.out.println(user);
}

}

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.example.springbootday02enableother.config;

import org.springframework.context.annotation.Import;

import java.lang.annotation.*;

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.example.springbootday02enableother.config;

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

@Configuration
public class UserConfig {

@Bean("user")
public User getUser(){
return new User();
}
}

1
2
3
4
5
package com.example.springbootday02enableother.domain;

public class User {
}

1.4 @Import注解

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

  1. 导入Bean
  2. 导入配置类
  3. 导入 ImportSelector 实现类。一般用于加载配置文件中的类
  4. 导入 ImportBeanDefinitionRegistrar 实现类。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package com.example.springbootday02enable;

import com.example.springbootday02enableother.config.EnableUser;
import com.example.springbootday02enableother.config.MyImportBeanDefinitionRegistrar;
import com.example.springbootday02enableother.config.MyImportSelector;
import com.example.springbootday02enableother.config.UserConfig;
import com.example.springbootday02enableother.domain.User;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import org.springframework.stereotype.Component;

/**
* @ComponentScan 扫描范围:当前引导类所在包及其子包
*
* com.itheima.springbootenable
* com.itheima.config
* //1.使用@ComponentScan扫描com.itheima.config包
* //2.可以使用@Import注解,加载类。这些类都会被Spring创建,并放入IOC容器
* //3.可以对Import注解进行封装。
*/
/**
* Import4中用法:
* 1. 导入Bean
* 2. 导入配置类
* 3. 导入ImportSelector的实现类。
* 4. 导入ImportBeanDefinitionRegistrar实现类
*/

@SpringBootApplication
//@ComponentScan(basePackages="com.example.springbootday02enableother")
//@Import(UserConfig.class)
//@EnableUser

//@Import(User.class)
//@Import(UserConfig.class)
//@Import(MyImportSelector.class)
@Import(MyImportBeanDefinitionRegistrar.class)
public class SpringbootDay02EnableApplication {

public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(SpringbootDay02EnableApplication.class, args);
Object user = run.getBean(User.class);
System.out.println(user);
Object user1 = run.getBean("user");
System.out.println(user1);
}

}

1
2
3
4
5
6
7
8
9
10
11
12
package com.example.springbootday02enableother.config;

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{"com.example.springbootday02enableother.domain.User"};
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.example.springbootday02enableother.config;

import com.example.springbootday02enableother.domain.User;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

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

1.5 @EnableAutoConfiguration 注解 面试题

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

1.6 案例:需求

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

案例:实现步骤

  1. 创建 redis-spring-boot-autoconfigure 模块

    1. 导入依赖

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      <?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.3.3.RELEASE</version>
      <relativePath/> <!-- lookup parent from repository -->
      </parent>
      <groupId>com.example</groupId>
      <artifactId>redis-spring-boot-autoconfigure</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <name>redis-spring-boot-autoconfigure</name>
      <description>Demo project for Spring Boot</description>

      <properties>
      <java.version>1.8</java.version>
      </properties>

      <dependencies>
      <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
      </dependency>
      <!--引入jedis依赖-->
      <dependency>
      <groupId>redis.clients</groupId>
      <artifactId>jedis</artifactId>
      </dependency>
      </dependencies>

      <build>
      <plugins>
      <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
      </plugins>
      </build>

      </project>


  2. 创建 redis-spring-boot-starter 模块,依赖 redis-springboot-autoconfigure的模块

    1. 导入依赖

      1
      2
      3
      4
      5
      <dependency>
      <groupId>com.example</groupId>
      <artifactId>redis-spring-boot-autoconfigure</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      </dependency>
  3. 在 redis-spring-boot-autoconfigure 模块中初始化 Jedis 的 Bean。并定义META-INF/spring.factories 文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    package com.example.redisspringbootautoconfigure.config;

    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import redis.clients.jedis.Jedis;

    @Configuration
    @EnableConfigurationProperties(RedisProperties.class)
    public class RedisAutoConfiguration {

    @Bean
    public Jedis jedis(RedisProperties redisProperties){
    return new Jedis(redisProperties.getHost(),redisProperties.getPort());
    }
    }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    package com.example.redisspringbootautoconfigure.config;

    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.stereotype.Component;

    @ConfigurationProperties(prefix = "redis")
    public class RedisProperties {

    private String host = "localhost";
    private int 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;
    }
    }

    1
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.example.redisspringbootautoconfigure.config.RedisAutoConfiguration

    META-INF / spring.properties

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    package com.example.springbootday02enable;

    import com.example.springbootday02enableother.config.EnableUser;
    import com.example.springbootday02enableother.config.MyImportBeanDefinitionRegistrar;
    import com.example.springbootday02enableother.config.MyImportSelector;
    import com.example.springbootday02enableother.config.UserConfig;
    import com.example.springbootday02enableother.domain.User;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.ConfigurableApplicationContext;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Import;
    import org.springframework.stereotype.Component;
    import redis.clients.jedis.Jedis;

    /**
    * @ComponentScan 扫描范围:当前引导类所在包及其子包
    *com.itheima.springbootenable

    - com.itheima.config
    - //1.使用@ComponentScan扫描com.itheima.config包
    - //2.可以使用@Import注解,加载类。这些类都会被Spring创建,并放入IOC容器
    - //3.可以对Import注解进行封装。
    */
    /**
    - Import4中用法:
    - 1. 导入Bean
    - 2. 导入配置类
    - 3. 导入ImportSelector的实现类。
    - 4. 导入ImportBeanDefinitionRegistrar实现类
    */
    @SpringBootApplication
    //@ComponentScan(basePackages="com.example.springbootday02enableother")
    //@Import(UserConfig.class)
    //@EnableUser
    //@Import(User.class)
    //@Import(UserConfig.class)
    //@Import(MyImportSelector.class)
    //@Import(MyImportBeanDefinitionRegistrar.class)
    public class SpringbootDay02EnableApplication {


    public static void main(String[] args) {
    ConfigurableApplicationContext run = SpringApplication.run(SpringbootDay02EnableApplication.class, args);
    // Object user = run.getBean(User.class);
    // System.out.println(user);
    // Object user1 = run.getBean("user");
    // System.out.println(user1);
    Jedis bean = run.getBean(Jedis.class);
    System.out.println(bean);
    bean.set("test","itcast");
    System.out.println(bean.get("test"));

    }

    @Bean
    public Jedis jedis(){
    return new Jedis("localhost",6379);
    }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

package com.example.redisspringbootautoconfigure.config;

import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.Jedis;

@Configuration
@EnableConfigurationProperties(RedisProperties.class)
@ConditionalOnClass(Jedis.class)
public class RedisAutoConfiguration {

@Bean
@ConditionalOnMissingBean(Jedis.class)
public Jedis jedis(RedisProperties redisProperties){
System.out.println("RedisAutoConfiguration....");
return new Jedis(redisProperties.getHost(),redisProperties.getPort());
}
}

2. Spring Boot 监控

2.1 Java 监听机制

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

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

  1. 事件:Event,继承 java.util.EventObject 类的对象
  2. 事件源:Source ,任意对象Object
  3. 监听器:Listener,实现 java.util.EventListener 接口 的对象

2.2 SpringBoot 监听机制

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

ApplicationContextInitializer、SpringApplicationRunListener、CommandLineRunner、ApplicationRunner

  1. 新建springboot工程

  2. MyApplicationContextInitializer

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    package com.itheima.springbootlistener.listener;

    import org.springframework.context.ApplicationContextInitializer;
    import org.springframework.context.ConfigurableApplicationContext;
    import org.springframework.stereotype.Component;

    @Component
    public class MyApplicationContextInitializer implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
    System.out.println("ApplicationContextInitializer....initialize");
    }
    }

  3. MySpringApplicationRunListener

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    package com.itheima.springbootlistener.listener;

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.SpringApplicationRunListener;
    import org.springframework.context.ConfigurableApplicationContext;
    import org.springframework.core.env.ConfigurableEnvironment;
    import org.springframework.stereotype.Component;

    public class MySpringApplicationRunListener implements SpringApplicationRunListener {

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

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

    @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) {
    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...项目启动失败");
    }
    }

  4. MyCommandLineRunner

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    package com.itheima.springbootlistener.listener;

    import org.springframework.boot.CommandLineRunner;
    import org.springframework.stereotype.Component;

    import java.util.Arrays;

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

  5. MyApplicationRunner

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    package com.itheima.springbootlistener.listener;

    import org.springframework.boot.ApplicationArguments;
    import org.springframework.boot.ApplicationRunner;
    import org.springframework.stereotype.Component;

    import java.util.Arrays;

    /**
    * 当项目启动后执行run方法。
    */
    @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()));
    }
    }

    META-INF/spring.factories

    1
    2
    3
    org.springframework.context.ApplicationContextInitializer=com.itheima.springbootlistener.listener.MyApplicationContextInitializer

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

2.3. SpringBoot 启动流程分析

img

2.4 SpringBoot 监控概述

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

2.4.1 SpringBoot 监控使用
  1. 使用步骤

    1. 导入依赖坐标

      1
      2
      3
      4
      5
      <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-actuator</artifactId>
      </dependency>

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      info.name=zhangsan
      info.age=23


      # 开启健康检查的完整信息
      management.endpoint.health.show-details=always


      # 将所有的监控endpoint暴露出来
      management.endpoints.web.exposure.include=*
    2. 访问http://localhost:8080/acruator

  2. SpringBoot 监控使用

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

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

    使用步骤:

     1.    admin-server:
                 1.    创建 admin-server 模块
                      2.    导入依赖坐标 admin-starter-server
                           3.    在引导类上启用监控功能@EnableAdminServer
     2.    admin-client:
                 1.    创建 admin-client 模块
                 2.    导入依赖坐标 admin-starter-client
                 3.    配置相关信息:server地址等
                 4.     启动server和client服务,访问server
    

4. SpringBoot 项目部署

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

1.     jar包(官方推荐)   java -jar  xx.jar  &

2.     ​        war包