当前位置:   article > 正文

SpringBoot:SpringApplication,热插拔,日志配置_@springbootapplication(scanbasepackages

@springbootapplication(scanbasepackages

1,SpringApplication与Spring容器

1.1,类配置与XML配置

传统Spring框架大多采用XML文件作为配置文件,但SpringBoot推荐使用Java配置类(带@Configurtion注解)作为配置文件,其实这两种方式在本质上并没有太大区别。建议与SpringBoot推荐的风格保持一致,使用@Configuration修饰带main()方法的主类,则该主类也是SpringBoot应用的主配置源。

除了加载主配置源中所有配置,SpringBoot还会自动扫描主配置源所在的包及其子包下所有带@Component注解(@Configuration、@Controller、@Service、@Repository都是@Component的变体)的配置类或Bean组件。

如果希望SpringBoot能加载其他配置类或者扫描其他包下配置类或Bean组件,则可使用:

  • @Import:该注解显式指定SpringBoot要加载的配置类。
  • @ComponentScan:该注解指定SpringBoot扫描指定包及其子包下所有的配置类或Bean组件。

如果项目不可避免地要用到XML配置文件,则可用@ImportResource注解来导入XML配置文件。

加载多个配置源

SpringBoot加载配置文件的三种不同方式:

  • 通过@ComponentScan的basePackages指定额外要扫描的包及其子包。
  • 使用@ImportResource注解指定加载XML配置文件。
  • 使用@Import注解指定加载其他Java配置类。
  1. package main;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.context.annotation.*;
  5. //额外扫描Controller和Pojo及其子包下所有配置类和Bean组件
  6. @SpringBootApplication(scanBasePackages = {"main.Pojo","main.Controller"})
  7. //加载类路径下的beans.xml文件作为配置文件
  8. @ImportResource("classpath:beans.xml")
  9. //加载包下的MyConfig文件作为配置类
  10. @Import(MyConfig.class)
  11. public class APP {
  12. public static void main(String[] args) {
  13. //创建Spring容器,运行SpringBoot应用
  14. SpringApplication.run(APP.class, args);
  15. }
  16. }

其中@SpringBootApplication注解指定了scanBasePackages属性,该注解源码:

  1. @AliasFor(
  2. annotation = ComponentScan.class,
  3. attribute = "basePackageClasses"
  4. )
  5. Class<?>[] scanBasePackageClasses() default {};

@SpringBootApplication的scanBasePackages其实就是@ComponentScan的basePackages属性,通过该属性可显式指定SpringBoot扫描指定包及其子包下所有的配置类和Bean组件。

  • 如果不为@SpringApplication指定scanBasePackages属性,则SringBoot会默认会加载主配置类(@SpringBootApplication修饰的类)所在包及其子包下的所有配置类和Bean组件,这相当于scanBasePackages属性的默认值就是主配置类所在的包。
  • 如果显式指定了scanBasePackages属性,那么就相当于覆盖了该属性的默认值,因此此处指定的属性值"main",这就是告诉SpringBoot要同时加载两个包及其子包下的配置类和Bean组件,其中"main"包是该属性原有的默认值。
  1. package main;
  2. import org.springframework.stereotype.Component;
  3. @Component
  4. public class Pig {
  5. public String bark(){
  6. return "我是一头猪";
  7. }
  8. }
  1. package main.Pojo;
  2. import org.springframework.stereotype.Component;
  3. @Component
  4. public class Dog {
  5. public String bark(){
  6. return "我是一条狗";
  7. }
  8. }

Dog类使用了@Component注解修饰,它将会被扫描、配置成Spring容器中的Bean。

  1. package main;
  2. import org.springframework.context.annotation.*;
  3. import java.text.DateFormat;
  4. @Configuration
  5. public class MyConfig {
  6. @Bean
  7. public DateFormat dateFormat(){
  8. return DateFormat.getDateInstance();
  9. }
  10. }
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5. <bean id="pig" class="main.Pig"/>
  6. </beans>
  1. package main.Controller;
  2. import main.Pig;
  3. import main.Pojo.Dog;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.web.bind.annotation.*;
  6. import java.text.DateFormat;
  7. import java.util.Date;
  8. @RestController
  9. public class helloController {
  10. @Autowired
  11. private Dog dog;
  12. @Autowired
  13. private Pig pig;
  14. @Autowired
  15. private DateFormat dateFormat;
  16. @GetMapping("/")
  17. public String test(){
  18. return pig.bark()+"-----"+dog.bark()+"-----"+dateFormat.format(new Date());
  19. }
  20. }

1.2,启动日志和失败分析器

日志级别

如果使用SpringApplication的静态run()方法来运行SpringBoot应用,则默认显示INFO级别的日志消息,包括一些与启动相关的详情。相反如果想关闭启动信息的日志,则可以设置:

spring.main.log-startup-info=false

如果应用启动失败,SpringBoot的失败分析器(Failure Analyzer)会提供详细的错误信息及修复建议。

如果没有合适的失败分析器来处理启动过程中出现的错误,但依然希望SpringBoot显示完整的错误报告,则可通过开启debug属性,或者将ConditionEvaluationReportLoggingListener的日志级别设置为DEBUG来实现。

  • 通过JAR包来运行SpringBoot应用,则可通过“--debug”选项来开启debug属性。
java -jar mySpringBoot-0.0.1-SNAPSHOT.jar --debug
  • 在application.properties文件中添加如下配置,将org.springframework.boot.autoconfigure.logging包下所有类的日志级别设为DEBUG,而ConditionEvaluationReportLoggingListener位于该包下。
logging.level.org.springframework.boot.autoconfigure.logging=true

失败分析器

虽然SpringBoot内置了大量失败分析器,但SpringBoot依然允许开发者注册资金的失败分析器,该失败分析器既可补充现有失败分析器的功能,也可替换现有的失败分析器。

自定义失败分析器应继承AbstractFailureAnalyzer<T>,该基类中的泛型T代表该分析器处理的异常。

继承AbstractFailureAnalyzer<T>抽象基类就要实现它的analyzer()抽象方法,该方法返回FailureAnalysis代表了对该异常的分析结果;如果不想让该失败分析器分析该异常,而是希望异常留给下一个分析器进行分析,则可让该方法返回null。

  1. package main;
  2. import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;
  3. import org.springframework.boot.diagnostics.FailureAnalysis;
  4. import java.net.BindException;
  5. public class FailureAnalyzer extends AbstractFailureAnalyzer<BindException> {
  6. protected FailureAnalysis analyze(Throwable rootFailure, BindException cause) {
  7. cause.printStackTrace();
  8. return new FailureAnalysis("程序启动出错:" + cause.getMessage(),"请先停止占用8080端口", cause);
  9. }
  10. }

​​​上面分析器的analyze()方法返回了一个FailureAnalysis对象,表明该失败分析器会对BindException进行分析。FailureAnalysis的本质就是包装三个信息:

  • description:失败的描述信息。第一个构造参数。
  • action:对该失败的修复建议。第二个构造参数。
  • cause:导致失败的异常。第三个构造参数。

自定义失败分析器需要在META-INF/spring.factories文件中注册,首先在项目的reources目录下创建META-INF文件夹,然后在META-INF文件夹内创建spring.factories文件,该文件的内容:

  1. org.springframework.boot.diagnostics.FailureAnalysisReporter=\
  2. main.MyAnalyzer

1.3,延迟初始化

Spring:概述_燕双嘤-CSDN博客1,Spring简介Spring是一个从实际开发中抽取出来的框架,因此它完成了大量开发中的通用步骤,留给开发者的仅仅是与特定应用相关的部分,从而大大提高了企业应用的开发效率。Spring为企业应用的开发提供了一个轻量级的解决方案。该方案包括:基于依赖注入的核心机、基于AOP的声明式事务管理、与多种持久层技术的整合,以及优秀的Web MVC框架等。Spring致力于JavaEE应用各层的解决方案,而不是仅仅专注于某一层的方案。可以说:Spring是企业应用开发的“一站式选择”,Spring贯穿表现层https://shao12138.blog.csdn.net/article/details/112904318#t7SpringBoot使用ApplicationContext作为Spring容器,因此SpringBoot默认会对容器中所有的singleton Bean执行预初始化。

在某些特殊需求下,SpringBoot也允许将取消ApplicationContext的预初始化行为改为延迟初始化,要将Spring容器设为延迟初始化:

  • 调用SpringApplicationBuilder对象的lazyInitialization(true)方法。
  • 调用SpringApplication对象的setLazyInitialization(true)方法。
  • 在application.properties文件中配置如下代码:
spring.main.lazy-initialization=true

启用延迟初始化之后,Spring容器将不会预初始化Bean,而是等到程序需要调用Bean的方法时才执行初始化,因此可降低SpringBoot应用的启动时间。

启动延迟初始化的缺点:

  • 在Web应用中,很多与Web相关的Bean要等到HTTP请求第一次到来时才会初始化,因此会降低第一次处理HTTP请求的响应效率。
  • Bean错误被延迟发现。由于延迟初始化的缘故,有些Bean的配置可能存在错误,但应用启动时并不会报错,只有等到应用要用这个配置错误的Bean时,程序才会报错,这样就延迟了发现错误的时机。
  • 运行过程中的内存紧张。由于应用启动时并未初始化程序所需的全部Bean,随着应用程序的运行,当应用中所有Bean初始化万抽,可能就会造成运行时内存紧张。为了避免出现这个问题,可以在延迟初始化之前对JVM的堆内存进行微调。

一般来说,如果不是有非常特殊的原因,则不建议启用SpringBoot的延迟初始化。

1.4,设置SpringApplication与层次容器

最简单的情况下,调用SpringApplication的run()静态方法即可运行SpringBoot应用,通过这种方式创建的SpringApplication自动采用默认配置。

如果要对SpringApplication进行自定义设置,调用setLazyInitialization(true)启动延迟初始化,调用setBanner()设置自定义Banner等,那么就需要先定义SpringApplication对象,然后调用该对象的run()实例方法。

  1. package main;
  2. import org.springframework.boot.Banner;
  3. import org.springframework.boot.SpringApplication;
  4. import org.springframework.boot.autoconfigure.SpringBootApplication;
  5. import org.springframework.core.env.Environment;
  6. import java.io.PrintStream;
  7. @SpringBootApplication
  8. public class APP {
  9. public static void main(String[] args) {
  10. SpringApplication application = new SpringApplication(APP.class);
  11. application.setLazyInitialization(true);
  12. Banner banner = new Banner() {
  13. public void printBanner(Environment environment, Class<?> sourceClass, PrintStream out) {
  14. String BANNER =
  15. "*********************************************\n" +
  16. " _ooOoo_\n" +
  17. " o8888888o\n" +
  18. " 88\" . \"88\n" +
  19. " (| -_- |)\n" +
  20. " O\\ = /O\n" +
  21. " ____/`---'\\____\n" +
  22. " .' \\\\| |// `.\n" +
  23. " / \\\\||| : |||// \\\n" +
  24. " / _||||| -:- |||||- \\\n" +
  25. " | | \\\\\\ - /// | |\n" +
  26. " | \\_| ''\\---/'' | |\n" +
  27. " \\ .-\\__ `-` ___/-. /\n" +
  28. " ___`. .' /--.--\\ `. . __\n" +
  29. " .\"\" '< `.___\\_<|>_/___.' >'\"\".\n" +
  30. " | | : `- \\`.;`\\ _ /`;.`/ - ` : | |\n" +
  31. " \\ \\ `-. \\_ __\\ /__ _/ .-` / /\n" +
  32. "======`-.____`-.___\\_____/___.-`____.-'======\n" +
  33. " `=---='\n" +
  34. "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
  35. " 佛祖保佑 永无BUG\n" ;
  36. out.println(BANNER);
  37. out.println();
  38. }
  39. };
  40. application.setBanner(banner);
  41. application.run();
  42. }
  43. }

SpringApplication的构造参数代表Spring容器的配置源,通常就是一个带@Configuration注解修饰的类的引用,SpringBoot将会加载该构造参数对应的配置类,并加载该类所在的包及其子包下所有的配置类和Bean组件。

除了直接调用构造器来创建SpringApplication对象,SpringBoot还提供了SpringApplicationBuilder工具类,通过该工具类能以流式API创建SpringApplication,并启动SpringBoot应用。

此外,SpringApplicationBuilder还提供了如下方法来加载配置文件:

  • sources(Class<?>...sources):为应用添加配置类。
  • child(Class<?>...sources):为当前容器添加子容器配置类。
  • parent(Class<?>...sources):为当前容器添加父容器配置类。

使用SpringApplicationBuilder可以构建ApplicationContext的层次结构(让Spring容器具有父子关系)。

  1. @SpringBootApplication
  2. public class APP {
  3. public static void main(String[] args) {
  4. new SpringApplicationBuilder()
  5. //父容器的配置类
  6. .sources(Parrent.class)
  7. //APP类对应的配置作为子容器
  8. .child(APP.class)
  9. .run(args);
  10. }
  11. }

上面程序加载了两个配置类,将通过Parent配置类创建的ApplicationContext作为父容器,而将通过App配置类创建的ApplicationContext作为子容器,这样就保证了两个Spring容器之间具有清晰的层次结构。

让多个Spring容器具有层次结构具有很多好处。比如,由于子容器是由父容器负责加载的,因此子容器中的Bean可访问父容器中的Bean,但父容器中的Bean不能访问子容器的Bean。

1.5,事件监听器与容器初始化器

Spring:Spring容器(BeanFactory和ApplicationContext)_燕双嘤-CSDN博客Spring的IoC容器是一个提供IoC支持的轻量级容器,IoC容器为管理对象之间的依赖关系提供了基础功能。Spring为我们提供了两种容器:BeanFactory和ApplicationContext。在基于Spring的JavaEE应用中,所有的组件都被当成Bean处理,包括数据源、Hibernate的SessionFactory。应用中所有组件都处于Spring的管理下,都被Spring以Bean的方式管理,Spring负责创建Bean实例,并管理其生命周期。Spring里的Bean是非常广义的.https://shao12138.blog.csdn.net/article/details/113032492#t2

除了Spring框架原有的容器事件,SpringApplication还会额外触发一些新的事件,而且有些事件是在ApplicationContext被创建之前被触发的。

为了监听SpringApplication触发的事件,SpringApplication提供了如下方式来注册事件监听:

  • 调用SpringApplication的addListeners()方法或SpringApplicationBuilder的listeners()方法添加事件监听器。
  • 使用META-INF/spring.factories文件来配置事件监听器。
org.springframework.context.ApplicationListener=main.MyListener

当SpringBoot应用启动时,SpringApplication会依次触发如下事件:

  • 在应用刚刚开始时、还未进行任何处理之时,触发ApplicationStartingEvent事件,除非监视器和初始化器注册失败。
  • 当ApplicationContext要使用Environment已经确定,但ApplicationContext还未被创建加载任何Bean之时,触发ApplicationEnvironmentPrepareEvent事件。
  • 当ApplicationContext准备完成且初始化器(ApplicationContextInitializer)已被调用,但未加载任何Bean定义之前,触发ApplicationContextInitializedEvent事件。
  • 在所有Bean定义被加载之后、Spring容器刷新之前,触发ApplicationPreparedEvent事件。
  • 在Spring容器刷新之后,ApplicationRunner、CommandLineRunner的接口方法被调用之前,触发ApplicationStartedEvent事件。
  • 当应用程序的LivenessState状态变成CORRECT,表明应用程序进入live状态时,触发AvailabilityChangeEvent事件。
  • 当所有ApplicationRunner、CommandLineRunner的接口方法被调用完成后,触发ApplicationReadyEvent事件。
  • 当应用程序的ReadinessState状态变成ACCEPTING_TRAFFIC,表明应用程序准备接受服务请求时,触发AvailabilityChangeEvent事件。
  • 如果启动遇到异常,则触发ApplicationFailedEvent事件。

上面列出的都是绑定到SpringApplication的SpringApplicationEvent事件。此外,还会在ApplicationPreparedEvent事件与ApplicationStartedEvent事件之间触发如下两个容器事件:

  • Web服务器初始化完成后触发WebServerInitializeEvent事件;如果使用Servlet Web服务器,则触发ServletWebServerInitializedEvent事件;如果使用反应式Web服务,则触发ReactiveWebServerInitializedEvent事件。
  • 在刷新ApplicationContext时触发ContextRefreshedEvent事件。

由于事件监听器采用同一个线程来执行,因此不应该在事件监听器中执行某些耗时操作;如果确实需要完成某些耗时操作,则建议使用ApplicationRunner或CommandLineRunner接口。

由于上面这些事件都是通过Spring框架的事件机制来发布的,这种机制会保证子容器中触发的事件也会自动触发父容器中的监听器。因此,如果应用程序采用了层次结构的容器(通过SpringApplicationBuilder启动SpringBoot应用时,可使用层次结构的容器),那么事件监听器就可能接收到同一类型事件的多个实例——它们来自不同的容器。

为了让事件监听器能区分事件到底来自那个容器,可以用事件监听器依赖注入的容器与事件来自的容器进行比较;为了将容器依赖注入事件监听器,可通过以下两种方式:

  • 接口注入:让事件监听器实现ApplicationContextAware接口,Spring容器将会被注入监听器。
  • 普通注入:如果事件监听器是容器的Bean,则可直接使用@Autowired注解来完成依赖注入。

除了监听器,SpringBoot还提供了ApplicationContextInitializer对Spring容器执行初始化。ApplicationContextInitializer接口的实现被称为“初始化器”,该接口的实现类必然实现其中的initialize(C ctx)方法,通过该方法的参数也可对Spring容器进行设置。

  • 调用SpringApplication的addInitializers()方法或SpringApplicationBuilder的initializers()方法添加初始化器。
  • 使用META-INF/spring.factories文件来配置初始化器。在该文件中添加如下代码即可注册初始化器。
  1. org.springframework.context.ApplicationContextInitializer=\
  2. main.MyInitializer

1.6,配置环境后处理器

如果想在Environment对象创建之后、Spring容器刷新之前对Environment对象(配置环境)进行定制。

SpringBoot提供了配置环境后处理器——实现EnvironmentPostProcfessor接口的类被称为“配置环境后处理器”。EnvironmentPostProcessor实现类必然实现其中的postProcessEnvironment(environment, application)方法,通过该方法的参数可对创建Spring容器的Environment进行额外的定制,比如将自定义的配置文件的属性加载到配置环境中。

2,热插拔

如果想在项目开发过程中实时看到代码的修改效果,则需要通过 Spring Boot 的热插拔(hot swapping)功能来实现,Spring Boot专门为热插拔等功能提供了开发者工具。

2.1,静态模板的重加载

Spring Boot支持的模板技术(如ThymeleafFreeMarker 和Groovy 等)都可通过配置来禁用缓存,禁用缓存可在不重启Web服务器的情况下重加载模板页面。

  1. #Thymeleaf模板下关闭缓存
  2. spring.thymeleaf.cache=false
  3. #FreeMarker模板下关闭缓存
  4. spring.freemarker.cache=false
  5. #Groovy模板下关闭缓存
  6. spring.groovy.template.cache=false
  7. #Mustache模板下关闭缓存
  8. spring.mustache.servlet.cache=false

Spring Boot通过监测类加载路径下文件的改变来实现模板的重加载,只有当Spring Boot监测到类加载路径下的模板页面发生了改变时,才会触发重加载。开发者修改并保存了模板页面(这些模板页面通常位于src\main\resources\template目录下)的代码后,如果项目没有重新构建,则Spring Boot并不能实时加载模板的改变。 如果仅仅是更改了静态资源(比如图片CSS样式等),由于它们都不在项目的类加载路径下,因此都不会触发Spring Boot重加载静态资源。

PS:如果使用IDE工具的debug模式运行应用,则IDE工具可以自动重加载静态模板和静态资源的改变,并能在不重启Web服务器的情况下热加载Java类文件的改变,这种机制被称为热插拔(hot swapping)

2.2,spring-boot-devtools

Spring Boot推荐在开发阶段使用spring-boot-devtools工具,只要在pom.xml文件中添加如下依赖即可增加该工具。

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-devtools</artifactId>
  4. <optional>true</optional>
  5. </dependency>

为了避免将 devtools 工具依赖传递到项目的其他模块,建议在 Maven 项目中将 spring-boot-devtools 依赖的<optional.../>元素设为 true。

devtools工具提供了大量开发时功能:

  • 应用快速重启。
  • 浏览器实时重加载(LiveReload)。
  • 各种开发时配置属性(如前面介绍的关闭模板缓存等),只要为项目添加了devtools工具,它就会自动完成2.1内容。

此外,devtools工具还会自动将Web日志组(包括Spring MVC和Spring WebFlux)设为DEBUG级别,这样就会详细显示各个请求处理请求 的Handler,以及为请求生成的响应等信息。如果想显示每个请求的所有详情(包括潜在的敏感信息),则可添加如下配置:

  1. spring.mvc.log-request-details=true
  2. #或
  3. spring.codec.log-request-details=true

如果想关闭devtools工具所添加的所有开发时配置属性(如关闭模 板缓存`设置Web日志组为DEBUG级别等),则可在application.properties文件中添加如下配置:

spring.devtools.add-properties=false

不要在产品场的Spring Boot应用中启用devtools工具,否则会带来安全隐患。但如果要远程使用devtools功能,这时就需要强制将devtools工具打 包进去。对于Maven构建工具,则需要将excludeDevtools属性设为false。例如如下配置片段:

  1. <build>
  2. <plugins>
  3. <plugin>
  4. <groupId>org.springframework.boot</groupId>
  5. <artifactId>spring-boot-maven-plugin</artifactId>
  6. <configuration>
  7. <excludeDevtools>false</excludeDevtools>
  8. </configuration>
  9. </plugin>
  10. </plugins>
  11. </build>

2.3,自动重启

devtools 工具会监测类加载路径下的文件(尤其是*.class 文件), 只要这些文件发生了改变,devtools工具就会自动重启Spring Boot应用。该功能在开发时比较实用,它能快速地呈现代码修改后的效果。

静态资源(如CSS样式单和JS脚本等)和视图模板资源发生了改变,不需要重启应用就可呈现改变后的效果,因此它们不会触发应用重启。

与触发静态模板的重加载类似,使用不同的工具,触发devtools工具自动重启的方式也不同:

  • 对于Eclipse,只要保存修改后的文件就会触发其自动重启。
  • 对于IntelliJ IDEA,保存文件后,必须运行“Build”→“Build Project”(或按“Ctrl+F9”快捷键)才会触发其自动重启。当然,也可选择为IntelliJ IDEA开启自动构建功能。不建议开启IntelliJ IDEA的自动构建功能,否则你会发现:只要对Java源代码做了一点修改,Spring Boot 应用就会自动重启,这样会导致IntelliJ IDEA“卡”得很。
  • 若使用 Maven 构建工具,则在保存文件后运行“mvn compile”命 令触发其自动重启。

devtools工具的自动重启是通过“双类加载器”来实现的,其中base类加载器负责加载那些无须改变的类(如从第三方JAR包加载的类),restart类加载器负责加载那些需要变化的类(在项目中开发的类)。当 devtools工具被触发自动重启时,base类加载器保持不变,继续复用; 而restart类加载器则需要重新创建,并加载所有可能改变的类,原有的restart类加载器被直接抛弃。正因为devtools工具在自动重启时复用了base类加载器及其所加载 的全部类(很明显,第三方JAR包涉及的类更多),所以devtools工具 的自动重启速度比直接启动(也被称为冷启动)要快得多。

如果觉得devtools工具的自动重启速度还不够快或者遇到了类加载问题,还可考虑使用第三方reload技术(如JRebel工具),这些技术可以在reload时重写已加载的类,因此效率更高。

2.4,实时重加载

devtools 工具内嵌了一个实时重加载(LiveReload)服务器,它可在资源改变时触发浏览器刷新。但前提是为该浏览器安装了 LiveReload 插件,基本上各主流的浏览器都有对应的 LiveReload插件。

为浏览器安装LiveReload插件之后,使用该浏览器访问Spring Boot 应用的页面时,通过单击按钮激活LiveReload插件。接下来,只要Spring Boot项目(带devtools工具)中的静态资源 (如CSS样式,JS脚本等)发生了改变,且触发了项目构建,浏览器 就会自动刷新(无须手动刷新),实时呈现静态资源的改变效果。

如果想关闭devtools工具的LiveReload服务器,则可在application.properties文件中添加如下属性:

spring.devtools.livereload.enabled=false

PS:每次最多只能启动一个LiveReload服务器。因此,如果通过IDE运行了多个带devtools工具的应用,那么只有第一个应用能够获得LiveReload功能。

3,日志配置

3.1,Spring Boot日志设计

通过Spring Boot提供的日志抽象层可以非常方便地管理应用的日志输出。只要在项目中导入 spring-boot-starter.jar 依赖,它就会传递导入 spring-boot-starter-logging.jar。

spring-boot-starter-logging.jar依赖如下三个JAR 包:

  • logback-classic.jar:它传递依赖于logback-core.jar和slf4j-api.jar。
  • log4j-to-slf4j.jar:它传递依赖于log4j-api.jar和slf4j-api.jar。 
  • jul-to-slf4j.jar:它传递依赖于slf4j-api.jar。

常见的日志框架就包括SLF4J、Log4j、Log4j2、Logback、common-logging(JCL)、 java.util.logging(JUL)、JBoss Logging等。这些日志框架又可分为:

  • 门面类(抽象层):SLF4J、JCL、JBoss Logging。
  • 日志实现:Log4j、Log4j2、Logback、JUL。

Spring Boot默认使用SLF4J+Logback的日志组合,其中SLF4J作为日志门面(应用程序输出日志时也应该面向该API),Logback作为日志实现,开发者通常不需要直接操作日志实现的API。因此,Spring Boot 默认会添加 SLF4J 依赖(slf4j-api.jar)和 Logback 依赖(logback-core.jar 和slf4j-api.jar)。

由于Spring Boot框架需要整合大量第三方框架,而这些框架的底层可能会使用JCL、Log4j、JUL等日志,因此Spring Boot还要提供对应的日志路由,将其他日志框架所生成的日志信息统一路由给SLF4J来处理。所以,从上面的依赖关系中还看到了如下依赖:

  • log4j-to-slf4j.jar:负责将Log4j日志路由到SLF4J。
  • jul-to-slf4j.jar:负责将JUL日志路由到SLF4J。

虽然Spring Boot默认采用Logback作为底层日志实现,但通过配置完全可以将底层日志实现改为使用其他框架。Spring Boot允许将Logback依赖排除出去,添加其他日志实现(比如Log4j)的依赖,这样即可将底层日志实现改为使用其他框架。

当把Spring Boot应用部署到Web服务器或应用服务器上时,JUL生成的日志将不会被路由到Spring Boot应用的日志中,这是为了避免将服务器或部署在服务器上的其他应用程序的日志 也路由到Spring Boot应用的日志中,否则会造成日志的混乱。

3.2,日志级别

  1. @RestController
  2. public class HelloController {
  3. Logger logger = LoggerFactory.getLogger(this.getClass());
  4. @GetMapping
  5. public void hello() {
  6. logger.trace("-------TRACE级别的日志-------");
  7. logger.debug("-------DEBUG级别的日志-------");
  8. logger.info("-------INFO级别的日志-------");
  9. logger.warn("-------WARN级别的日志-------");
  10. logger.error("-------ERROR级别的日志-------");;
  11. }
  12. }

从上面的输出可以看到,Spring Boot默认只输出INFO、WARN和ERROR级别的日志,这说明Spring Boot应用默认设置的日志级别为INFO。Spring Boot应用默认的日志级别是INFO,因此在控制台中只能看到INFO级别的日志;

综合各种日志框架来看,它们总共支持如下几种日志级别:

  1. ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF
  2. -ALL:输出所有日志。
  3. -TRACE:详细记录了Spring Boot的运行过程。
  4. -DEBUG:Spring Boot的核心日志(包括嵌入式容器、Hibernate和Spring Boot)。
  5. -INFO:输出基本日志。
  6. -WARN:输出警告类日志。
  7. -ERROR:输出异常日志。
  8. -FATAL:Log4j新增的一种日志级别,代表“致命错误”,级别高于ERROR
  9. -OFF:关闭所有日志。

由于Spring Boot并不支持FATAL级别,因此FATAL级别会被自动转换为ERROR级别。 日志系统有一个“潜规则”:只有当日志输出方法的级别高于或等于日志的设置级别时,该日志才会实际输出 。由此可见,将日志的级别设得越高(比如设为 ERROR),应用程序输出的日志就越精简,应用的运行性能就越好,所有日志都要输出到 I/O 节点(文件或数据库),这些都是有性能开销的;将日志的级别设得越低(比如设为 DEBUG),应用程序输出的日志就越详细,应用运行过程的记录就保存得越完整,但性能也越低。因此,当项目处于开发、测试、试运行阶段时,通常会将日志级别设得低一 些,从而记录相对完整的运行过程,以便后期调试、优化应用;当项目 处于实际运行阶段时,通常会将日志级别设得高一些,从而保证良好的性能。

3.3,日志内容

  1. 2022-10-31 16:04:30.797 INFO 1196 --- [nio-8080-exec-3] c.e.s.Controller.HelloController : -------INFO级别的日志-------
  2. 2022-10-31 16:04:30.797 WARN 1196 --- [nio-8080-exec-3] c.e.s.Controller.HelloController : -------WARN级别的日志-------
  3. 2022-10-31 16:04:30.798 ERROR 1196 --- [nio-8080-exec-3] c.e.s.Controller.HelloController : -------ERROR级别的日志-------

Spring Boot输出的每条日志都包括如下信息:

  • 日期和时间:时间精确到毫秒。
  • 日志级别:ERROR、WARN、INFO、DEBUG或TRACE。
  • 进程ID。
  • 三个减号(---):分隔符。
  • 线程名:用方括号括起来的是线程名(在控制台输出时可能会被截断)。
  • 日志名:通常就是输出日志的类的完整类名(为了便于阅读, 包名经常被简写,比如o.s.w其实代表了org.springframework.web)。
  • 日志信息。

要改变日志的设置级别,有以下几种方式:

  • 全局:通过debug=true或trace=true等属性(可通过配置文件、命令行参数、系统变量、OS环境变量等方式)改变整个Spring Boot核心的日志级别。
  1. #application.properties
  2. trace=true
  • 局部:通过 logging.level.<logger-name>=<level>属性(可通过配置文件、命令行参数、系统变量等方式)设置程序组件本身的日志级别。其中<logger-name>代表日志名,通常就是包名或全限定类名,而level则可以是trace、debug、info、warn和error等级别。
  1. #application.properties
  2. logging.level.root = WARN
  3. logging.level.org.springframework.web = DEBUG
  4. logging.level.com.example.springboot.Controller.HelloController = TRACE
  5. #redis
  6. logging.level.io.lettuce.core = debug

3.4,输出日志到文件

Spring Boot 默认只将日志输出到控制台,不输出到文件。如果要将日志输出到文件,则可为Spring Boot设置如下两个属性之一:

  • logging.file:设置日志文件。
  • logging.path:设置日志文件的目录。使用默认的spring.log作为文件名。

当日志文件达到10MB时,会自动重新使用新的日志文件。若要改变这个设置,对于Logback日志实现(Spring Boot默认采用该日志实现),则可直接使用application.properties(或application.yml)设置:

对于其他日志实现,则需要通过对应的日志设置文件来设置。比如采用Log4j日志实现,则需要使用log4j.xml文件进行设置。

3.5,改用Log4j2日志

Log4j本身已经很优秀,而Log4j2则完全是Log4j的重新设计,因此放弃Logback,改为使用Log4j2也是不错的技术选择。若要让Spring Boot底层使用Log4j2也很简单:正如前面所介绍的,只需要去除Logback依赖库,并添加Log4j2依赖库即可。

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter</artifactId>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.springframework.boot</groupId>
  8. <artifactId>spring-boot-starter-web</artifactId>
  9. <exclusions>
  10. <exclusion>
  11. <groupId>org.springframework.boot</groupId>
  12. <artifactId>spring-boot-starter-logging</artifactId>
  13. </exclusion>
  14. </exclusions>
  15. </dependency>
  16. <dependency>
  17. <groupId>org.springframework.boot</groupId>
  18. <artifactId>spring-boot-starter-log4j2</artifactId>
  19. </dependency>
  20. </dependencies>

通过上面的配置,将项目的底层日志框架改成了Log4j2,但得益于Spring Boot日志机制的抽象机制,上层程序使用日志没有任何改变,日 志效果也没有任何改变。如果不是有经验的开发者,则可能都不知道 底层日志框架已从Logback改成了Log4j2

如果要对 Log4j2 做自定义的详细配置,则既可通过 log4j2.yml(或 log4j2.yaml)进行配置,也可通过 log4j2.json(或 log4j2.jsn)进行配置。log4j2.yml 或 log4j2.json 配置文件应遵守 Log4j2本身的语法。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/86675
推荐阅读
相关标签
  

闽ICP备14008679号