1. Spring Boot 高级

2. 自动配置

2.1. Condition

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

启动类返回IOC容器 获取bean对象

  1. //启动springboot的应用 返回spring的IOC容器
  2. ConfigurableApplicationContext context = SpringApplication.run(SpringbootProfilesApplication.class, args);
  3. //获取bean
  4. Object redisTemplate = context.getBean("redisTemplate");
  5. System.out.println(redisTemplate);

创建一个类实现 Condition接口 实现matches方法 返回一个布尔值 true为允许创建bean false为不允许

  1. import org.springframework.context.annotation.Condition;
  2. import org.springframework.context.annotation.ConditionContext;
  3. import org.springframework.core.type.AnnotatedTypeMetadata;
  4. public class ClassCondition implements Condition {
  5. @Override
  6. public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
  7. try {
  8. //获取指定的class 是否加载 没有则不允许创建新的bean
  9. Class<?> cls = Class.forName("redis.clients.jedis.Jedis");
  10. } catch (ClassNotFoundException e) {
  11. return false;
  12. }
  13. return true;
  14. }
  15. }

使用注解@Conditional

  1. @Configuration
  2. public class UserConfig {
  3. @Bean
  4. //如果为true则创建该bean
  5. @Conditional(ClassCondition.class)
  6. public User user(){
  7. return new User();
  8. }
  9. }

2.2. 自定义Conditional注解

创建注解

  1. package com.itheima.springbootprofiles.condtion;
  2. import org.springframework.context.annotation.Conditional;
  3. import java.lang.annotation.*;
  4. @Target({ElementType.TYPE, ElementType.METHOD})
  5. @Retention(RetentionPolicy.RUNTIME)
  6. @Documented
  7. @Conditional(ClassCondition.class)
  8. public @interface ConditionOnClass {
  9. String[] value();
  10. }

创建一个类实现 Condition接口 实现matches方法 返回一个布尔值 true为允许创建bean false为不允许

  1. package com.itheima.springbootprofiles.condtion;
  2. import org.springframework.context.annotation.Condition;
  3. import org.springframework.context.annotation.ConditionContext;
  4. import org.springframework.core.type.AnnotatedTypeMetadata;
  5. import java.util.Map;
  6. public class ClassCondition implements Condition {
  7. /**
  8. *
  9. * @param context 上下文对象 用于获取环境 ioc容器 classloader对象
  10. * @param metadata 注解元对象 可以用于获取注解定义的属性值
  11. * @return
  12. */
  13. @Override
  14. public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
  15. Map<String, Object> map = metadata.getAnnotationAttributes(ConditionOnClass.class.getName()); //获取注解中的元数据
  16. String[] value = (String[]) map.get("value"); //获取value中值
  17. try {
  18. //获取指定的class 是否加载 没有则不允许创建新的bean
  19. for (String classNmae : value) {
  20. Class<?> cls = Class.forName(classNmae);
  21. }
  22. } catch (ClassNotFoundException e) {
  23. return false;
  24. }
  25. return true;
  26. }
  27. }

使用注解

  1. @Configuration
  2. public class UserConfig {
  3. @Bean
  4. // @Conditional(ClassCondition.class)
  5. @ConditionOnClass("com.alibaba.fastjson.Json")
  6. public User user(){
  7. return new User();
  8. }
  9. }

2.3. 常用条件注解

  • @ConditionalOnProperty 判断配置文件中是否有对应属性和值才初始化Bean
  • @ConditionalOnClass 判断环境中是否有对应的字节码文件才初始化Bean
  • @ConditionalOnMissingBean 判断环境中没有对应的Bean时才初始化Bean
  • @ConditionalOnBean 判断容器中有指定组件时才注册该被标注的组件
  1. @Bean
  2. //当application配置文件中有此键值对时才创建此bean
  3. @ConditionalOnProperty(name = "name",havingValue = "zhangsan")
  4. public User user2(){
  5. return new User();
  6. }
  1. @ConditionalOnBean(name = "tomcat")
  2. @Bean // 给容器注册添加组件 用bean声明 返回的值,就是组件在容器中的实例
  3. public User user01() {
  4. User zhangsan = new User("zhangsan",18);
  5. zhangsan.setPet(tomcatpet());
  6. return zhangsan;
  7. }

2.4. 切换内置web服务器

SpringBoot的web环境默认为tomcat作为内置服务器,Springboot提供了4种内置服务器让我们选择

  • 排除tomcat 引入jetty依赖
    1. <dependency>
    2. <groupId>org.springframework.boot</groupId>
    3. <artifactId>spring-boot-starter-web</artifactId>
    4. <!-- 排除tomcat-->
    5. <exclusions>
    6. <exclusion>
    7. <groupId>org.springframework.boot</groupId>
    8. <artifactId>spring-boot-starter-tomcat</artifactId>
    9. </exclusion>
    10. </exclusions>
    11. </dependency>
    12. <!-- 引入jetty的依赖-->
    13. <dependency>
    14. <groupId>org.springframework.boot</groupId>
    15. <artifactId>spring-boot-starter-jetty</artifactId>
    16. </dependency>

2.5. @Enable* 注解

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

2.5.1. 第三方包导入

在项目或者POM中添加坐标

Springboot并不会加载到我们自己手动导入的第三方包

  1. 使用@ComponentScan(“引用路径”) 重新定义扫描目录 SpringBoot默认为启动类的根路径下Bean
  2. 使用@Import(字节码) 导入第三方jar包
  3. 自定义注解 实现@Import 并继承其之前的注解 简化我们书写

2.5.2. @Import注解

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

  1. 导入Bean

  2. 导入配置类

  3. 导入ImportSelector实现类 一般用于加载配置文件中的类 ```java public class MyImportSelector implements ImportSelector { //实现selectImports方法 需要一个元数据 @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) {

    1. return new String[]{"com.itheima.domain.user"};

    } }

//使用@Import导入实现类 @Import(MyImportSelector.class)

  1. 4.
  2. 导入 ImportBeanDefinitionRegistrar 实现类
  3. ```java
  4. public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
  5. @Override
  6. public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
  7. //Bean对象
  8. AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition();
  9. //创建bean的名称 以及需要一个bean对象
  10. registry.registerBeanDefinition("user",beanDefinition);
  11. }
  12. }
  13. //使用@Import导入实现类
  14. @Import(MyImportBeanDefinitionRegistrar.class)

2.5.3. @EnableAutoConfiguration

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

2.6. 自定义自动配置

配置redis 配置类

  1. package com.itheima.redisspringbootautoconfigure.redis.config;
  2. import org.springframework.boot.context.properties.ConfigurationProperties;
  3. @ConfigurationProperties(prefix = "redis")
  4. public class RedisProperties {
  5. private String host="localhost";
  6. private int port =6379;
  7. public String getHost() {
  8. return host;
  9. }
  10. public void setHost(String host) {
  11. this.host = host;
  12. }
  13. public int getPort() {
  14. return port;
  15. }
  16. public void setPort(int port) {
  17. this.port = port;
  18. }
  19. }

自动配置类

  1. package com.itheima.redisspringbootautoconfigure.redis.config;
  2. import org.springframework.boot.context.properties.EnableConfigurationProperties;
  3. import org.springframework.context.annotation.Bean;
  4. import org.springframework.context.annotation.Configuration;
  5. import redis.clients.jedis.Jedis;
  6. @Configuration
  7. @EnableConfigurationProperties(RedisProperties.class)
  8. @ConditionalOnClass(Jedis.class)
  9. public class RedisAutoConfiguration {
  10. @Bean
  11. @ConditionalOnMissingBean(name = "jedis")
  12. public Jedis jedis(RedisProperties redisProperties) {
  13. return new Jedis(redisProperties.getHost(), redisProperties.getPort());
  14. }
  15. }

在resource 下创建META-INF目录 创建spring.factories文件

  1. org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  2. com.itheima.redisspringbootautoconfigure.redis.config.RedisAutoConfiguration
  • 使用 在项目pom中引入自定义自动配置的项目坐标

启动时自动配置

3. 监听机制

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

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

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

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

  • ApplicationContextInitializer 项目图标加载后监听 ```java package com.itheima.springbootinit.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”); } }

  1. <br />并且配置resource下的 META-INF 的spring.factories配置

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

  1. -
  2. SpringApplicationRunListener 生命周期监听
  3. ```java
  4. package com.itheima.springbootinit.listener;
  5. import org.springframework.boot.ConfigurableBootstrapContext;
  6. import org.springframework.boot.SpringApplication;
  7. import org.springframework.boot.SpringApplicationRunListener;
  8. import org.springframework.context.ConfigurableApplicationContext;
  9. import org.springframework.core.env.ConfigurableEnvironment;
  10. import org.springframework.stereotype.Component;
  11. public class MySpringApplicationRunListener implements SpringApplicationRunListener {
  12. public MySpringApplicationRunListener(SpringApplication application, String[] args) {
  13. }
  14. @Override
  15. public void starting(ConfigurableBootstrapContext bootstrapContext) {
  16. System.out.println("starting...项目启动中");
  17. }
  18. @Override
  19. public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
  20. System.out.println("environmentPrepared...环境对象开始准备");
  21. }
  22. @Override
  23. public void contextPrepared(ConfigurableApplicationContext context) {
  24. System.out.println("contextPrepared...上下文对象开始准备");
  25. }
  26. @Override
  27. public void contextLoaded(ConfigurableApplicationContext context) {
  28. System.out.println("contextLoaded...上下文对象开始加载");
  29. }
  30. @Override
  31. public void started(ConfigurableApplicationContext context) {
  32. System.out.println("started...上下文对象加载完成");
  33. }
  34. @Override
  35. public void running(ConfigurableApplicationContext context) {
  36. System.out.println("running...项目启动完成,开始运行");
  37. }
  38. @Override
  39. public void failed(ConfigurableApplicationContext context, Throwable exception) {
  40. System.out.println("failed...项目启动失败");
  41. }
  42. }


并且配置resource下的 META-INF 的spring.factories配置

  1. org.springframework.boot.SpringApplicationRunListener=com.itheima.springbootinit.listener.MySpringApplicationRunListener
  • CommandLineRunner ```java package com.itheima.springbootinit.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.toString(args)); //java运行传递的参数 } }

  1. -
  2. ApplicationRunner
  3. ```java
  4. package com.itheima.springbootinit.listener;
  5. import org.springframework.boot.ApplicationArguments;
  6. import org.springframework.boot.ApplicationRunner;
  7. import org.springframework.stereotype.Component;
  8. import java.util.Arrays;
  9. @Component
  10. public class MyApplicationRunner implements ApplicationRunner {
  11. @Override
  12. public void run(ApplicationArguments args) throws Exception {
  13. System.out.println("ApplicationRunner...run");
  14. System.out.println(Arrays.toString(args.getSourceArgs())); //java运行传递的参数
  15. }
  16. }

3.1. 启动流程

13. Spring Boot 高级 - 图1

4. 监控

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

13. Spring Boot 高级 - 图2

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

访问localhost:8080/acruator

  • 开启(health)健康检查完整信息
  1. management.endpoint.health.show-details=always
  • 将所有的监控endpoint暴露出来
  1. management.endpoints.web.exposure.include=*

5. Spring Boot Admin

Spring Boot Admin是一个开源社区项目 用于管理和监控SpringBoot应用程序

分服务端和客户端 客户端用于查看监控 服务端用于监控Spring

服务端

13. Spring Boot 高级 - 图3

  1. <dependency>
  2. <groupId>de.codecentric</groupId>
  3. <artifactId>spring-boot-admin-starter-server</artifactId>
  4. <version>2.5.0</version>
  5. </dependency>

启动类中加上 注解 @EnableAdminServer 用于监控springboot

客户端

创建另外一个项目

13. Spring Boot 高级 - 图4

  1. <dependency>
  2. <groupId>de.codecentric</groupId>
  3. <artifactId>spring-boot-admin-starter-client</artifactId>
  4. <version>2.5.0</version>
  5. </dependency>

在application配置admin.server地址

  1. spring.boot.admin.client.url=http://localhost:8080 #对应的是server的ip和端口
  2. management.endpoint.health.show-details=always
  3. management.endpoints.web.exposure.include=*

13. Spring Boot 高级 - 图5

6. 部署

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

  1. jar包(官方推荐)
    直接在maven中打包即可

  2. war包
    在pom文件中packageing定义为war包
    启动类继承 SpringBootServletInitializer 类 重写configure方法

    1. @Override
    2. protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
    3. return builder.sources(SpringbootProfilesApplication.class); //将启动类字节码文件传递过去
    4. }


放置war包到tomcat的webapps的目录下启动tomcat即可