心心相印 → 印贼作父 → 父相伤害 → 害想咋滴
一篇文章让你0基础精通SpringBoot,害想咋滴?(白嫖有罪,记得点赞)
SpringBoot由于学习的内容比较多,我会分成多个章节来写。
不详细记得叫人打我
不详细一定要叫人打我
不详细千万记得叫人打我
Spring Framework
Spring Framework是轻量级的框架。无需开发重量级的 EnterpriseJavaBean(EJB),通过依赖注入和面向切面编程,用简单的Java 对象实现了 EJB 的功能。
缺点:
Spring boot
SpringBoot简化了J2EE应用开发,约定大于配置,去繁从简,just run就能创建一个独立的,产品级别的应用。其设计目的也是用来简化新 Spring 应用的初始搭建以及开发过程。
Spring Boot 不是Spring 的替代者,Spring 框架是通过 IOC 机制来管理 Bean 的。Spring Boot 依赖 Spring 框架来管理对象的依赖。Spring Boot 并不是Spring 的精简版本,而是为使用 Spring 做好各种产品级准备
Spring Boot 不是Spring 的替代者,而是Spring框架进行了再封装。
spring boot 其实不是什么新的框架,如果说 maven 是jar包管理工具,那么spring boot 系列技术站整合工具,spring boot 中不仅整合了Spring家族的其他技术服务,还允许接入其他技术框架。
spring boot 也是Spring家族中的一员,不同的是Spring boot更像一个多插孔,多规格的插板,底层不仅使用了Spring其他应用的技术站,还可以接入其他框架或工具。插板在手,天下你有。
优点:
缺点:
想要用SpringBoot进行企业级产品的应用进行深度定制,对掌握Spring框架要求相对较高。
问:什么是微服务?(熟悉的同学可以直接跳过)
简单举例:看军事新闻的同学应该都知道,一艘航空母舰作战能力虽然很强,但是弱点太明显,就是防御能力太差,单艘的航空母舰很少单独行动,通常航空母舰战斗群才是主要军事力量,你可以把单艘航母理解为的单体应用(防御差,机动性不好),把航母战斗群(调度复杂,维护费用高)理解为微服务。
大部分的开发者经历和开发过单体应用,无论是传统的 Servlet + JSP,还是 SSM,还是现在的 SpringBoot,它们都是单体应用,那么长期陪伴我们的单体应用有什么弊端?我们是面临了什么问题,导致我们要抛弃单体应用转向微服务架构?个人总结主要问题如下:
部署成本高(无论是修改1行代码,还是10行代码,都要全量替换,重新打包,部署,运行)
改动影响大,风险高(不论代码改动多小,成本都相同,风险也相同)
因为成本高,风险高,所以导致部署频率低(无法快速交付客户需求)
当然还有例如无法满足快速扩容,弹性伸缩,无法适应云环境特性等问题,但我们不一一详谈了,以上的问题,都是微服务架构要解决的问题
推荐文章:三种架构的区别
单体架构实际上就是将前端页面,所有模块功能的代码都放在一个应用里面,进行应用部署。开发、测试,以及应用的部署都非常简单。如果服务器负载比较大,可以将单体应用复制放到多个服务器上,从而实现均衡负载。缺点是只修改到代码,就需要整个代码重新打包,部署,维护起来比较麻烦。
微服务实际上是一种架构风格,一个应用应该是一族小型的服务器:微服务则集成了各种功能服务于一体,且提倡服务与服务之间相互独立,可独立升级,可替换,不影响其他服务的一个服务群体。其中服务与服务之间的互相调用可以通过HTTP的方式进行互通。
微服务架构的特点:
微服务由于是服务集群组成的一个大型分布式服务网,确实提高了应用的开发效率和安全性,降低了开发成本,但是也给维护和测试人员带来的一定的难度:
那如何比较和的解决微服务产生的问题呢?Spring公司已为我们提供了一整套的解决方案:
详细参阅:https://www.cnblogs.com/xiao2shiqi/p/11298663.html
必须掌握以下内容:
环境约束
(SpringBoot2 )
案例演示
案例需求:
浏览器发送hello请求,服务器接收请求并处理,响应Hello World字符串
1、创建普通Maven工程(不使用骨架)
3、导入Spring Boot版本依赖
作为一个springboot项目必须要加上以下依赖,这是Spring Boot的父级依赖,这样当前的项目就是个Spring Boot项目了。
spring-boot-starter-parent 是一个特殊的starter,它用来提供相关的Maven默认依赖。使用它之后,常用的包依赖可以省去version标签。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
spring-boot-starter-parent里面提供了一个spring-boot-dependencies
依赖,在此依赖中定义了常用的所有的依赖的版本号,因此不需要定义version,就可以添加兼容的版本依赖。
4、编写一个主程序类:启动Spring Boot应用
Run方法中需要传入两个参数,其中一个参数是类,传入的该类必输是被@SpringBootApplication
标注的类
6、启动Spring Boot主程序
为什么可以执行,因为SpringBoot中集成了Tomcat服务器
8、简化部署
将Spring-boot的maven插件导入到pom文件里面。
该插件的作用是可以将应用打包成一个可执行的jar包:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
然后使用Maven工具中package命令
进行打包:
将jar复制到指定目录,并运行jar包:
再次进行测试访问,发现也能访问成功:
1、Spring boot父项目
以为的应用,父项目一般是用来管理jar包的。
按住Ctrl 键 + 鼠标左键,进入spring-boot-starter-parent
,发现该父项目依赖于一个叫
spring-boot-dependencies
的父项目,如图:
当我们再点击进入查看的时候,发现我们常用的jar包版本依赖都存储在里面:
注:
原来SpringBoot就在这里帮助我们来管理版本,所以说这个就是spring boot的版本仲裁中心
。后期如果你想要使用某个jar的其他版本可以在这里进行管理。当然,如果是没有在仲裁中心的依赖自然需要声明版本号。
在版本仲裁中心下面,又依赖了多个类型启动器,如图:
至于启动器下面会做介绍。
2、spring-boot-starter-web依赖
在pom文件中除了spring-boot-starter-parent的依赖,还有一个spring-boot-starter-web
的依赖:
该依赖也是没有写版本号,其中在spring-boot-starter-web中可以拆分为:
spring-boot-starter :
spring-boot 场景启动器:帮我们导入了web模块正常运行所依赖的组件,
这些依赖的版本号都是由父项目的仲裁中心进行统一管理。
可以点击spring-boot-starter-web
进去查看web模块依赖的组件:
在Spring-boot中,也有更多类似的启动器,每一个starter都是一系列依赖描述的组合,spring boot将所有的功能场景都抽取出来,做成了一个个的starter(启动器)
,例如:
只需要在项目里面引入这些starter相关场景的所有依赖都会导入进来。要用什么功能,就导入什么场景启动器即可。所以后面会听到“启动器”这个词比“依赖”这个词还要多。
下面常用的应用程序starters是Spring Boot在 org.springframework.boot 组下提供的:
spring-boot-starter
核心Spring Boot starter,包括自动配置支持,日志和YAML
spring-boot-starter-actuator
生产准备的特性,用于帮你监控和管理应用
spring-boot-starter-amqp
对"高级消息队列协议"的支持,通过 spring-rabbit 实现
spring-boot-starter-aop
对面向切面编程的支持,包括 spring-aop 和AspectJ
spring-boot-starter-mail
对 javax.mail 的支持
spring-boot-starter-mobile
对 spring-mobile 的支持
spring-boot-starter-redis
对REDIS键值数据存储的支持,包括 spring-redis
spring-boot-starter-security
对 spring-security 的支持
spring-boot-starter-test
对常用测试依赖的支持,包括JUnit, Hamcrest和Mockito,还有 spring-test 模块
spring-boot-starter-thymeleaf
对Thymeleaf模板引擎的支持,包括和Spring的集成
spring-boot-starter-web
对全栈web开发的支持,包括Tomcat和 spring-webmvc
spring-boot-starter-websocket
对WebSocket开发的支持
spring-boot-starter-remote-shell
添加远程 ssh shell支持
spring-boot-starter-jetty
导入Jetty HTTP引擎(作为Tomcat的替代)
spring-boot-starter-log4j
对Log4J日志系统的支持
spring-boot-starter-logging
导入Spring Boot的默认日志系统(Logback)
spring-boot-starter-tomcat
导入Spring Boot的默认HTTP引擎(Tomcat)
3、主程序类(主入口类)
@SpringBootApplication :Spring Boot应用标注在某个类上说明这个类是SpringBoot的主配置类,也是SpringBoot程序的入口。SpringBoot就应该运行这个类的main方法来启动SpringBoot应用。
点击@SpringBootApplication
注解进行查看,发现该注解是一个组合注解,该注解里面有很多注解组成:
注解1:
@SpringBootConfiguration:标志在某个类上,表示这是一个Spring boot的配置类。点击查看该注解,发现该注解又是由几个注解组合而成:
其中@SpringBootConfiguration注解和@Configuration注解都是代表该类是一个配置类,
只是@Configuration注解是Spring提供
而@SpringBootConfiguration是spring boot来提供的。
注解2:
@EnableAutoConfiguration:开启自动配置功能。
告诉Spring boot开启自动配置功能。
该注解都代替了Spring中的自动扫描包等配置,是由Spring boot 帮我们自动配置的。
点击鼠标进去查看该组合注解:
@AutoConfigurationPackage注解下的子注解@Import({AutoConfigurationImportSelector.class})
的作用是扫描主程序类所在包以及其子包里面的的@Controller、@Controller、@Service等容器注解,然后将该类的bean注入到Spring容器中。同时,AutoConfigurationImportSelector类中的selectImports(AnnotationMetadata annotationMetadata)
方法就是获取组件,然后组件以全类名的方式返回,这些组件就会被添加到容器中,会给容器中导入很多的自动配置类,这些自动配置类的作用,就是给容器中导入这个场景所需要的所有组件,并配置好这些组件。比如我们需要用到MongoDB的功能,那么MongoDB的自动配置类和相应的组件一 一配置好,并添加到容器,然后就可以直接调用bean对象。
有了自动配置类,就免去了我们手动编写配置以及注入功能组件等工作。这就是Spring boot几乎零配置的原理。
实际上,Spring boot在启动的时候,@EnableAutoConfiguration注解会从类路径下的MATA-INF/spring.factories中获取EnableAutoConfiguration指定的值。将这些值作为自动配置类导入到容器中,此时自动配置类就生效了,此时就自动帮我们进行自动配置功能,就不需要写那么多的配置文件和代码了。
我们可以在里面选择一个自动配置点,然后按Ctrl + 鼠标左键 点击进去进行查看,发现里面的类都使用配置类的方法进行了自动配置,替代了Sprng传统的xml配置。
总结:1、@EnableAutoConfiguration
注解是实现SpringBoot自动加载配置的注解,也是三大注解的核心注解。
面试题:Spring Boot 的自动配置是如何实现的?
Spring Boot 项目的启动注解是:@SpringBootApplication,其实它就是由下面三个注解组成的:
@Configuration
@ComponentScan
@EnableAutoConfiguration
其中 @EnableAutoConfiguration 是实现自动配置的入口,该注解又通过 @Import 注解导入了AutoConfigurationImportSelector,在该类中加载 META-INF/spring.factories 的配置信息。然后筛选出以 EnableAutoConfiguration 为 key 的数据,加载到 IOC 容器中,实现自动配置功能!
按照以上的方法,创建一个Spirng boot项目需要:
(1)创建一个Spring boot项目都需要先创建一个maven项目
(2)导入spring boot 对应场景启动器(stater)依赖
(3)编写一个主程序,再编写业务逻辑
由于按照上述的方法来创建一个Spring boot项目比较麻烦,而我们的 IDEA 工具提供了创建向导来快速的创建一个Spring boot项目。
注:使用Spring Initializer向导创建需要联网
打开idea工具,新建一个项目,选择Spring 初始化器:
选择场景启动器,需要什么功能服务,就选择什么启动器:
点击next以后,直接点击finsh,完了以后等待联网加载即可(它会从SpringBoot的官网爱生成项目,放到工作区中)。
踩坑:加载完成以后,提示需要手动去安装这个插件,发现这是一个支持脚本高亮,并且格式化的脚本个是插件:
于是在In the Settings/Preferences dialog Ctrl+Alt+S 下载:
安装完成重启即可
然后我们打开使用向导创建项目的pom文件
,发现已经智能的帮我们导入了启动器依赖和创建了主程序:
主程序:
生成的项目结构:
编写业务逻辑程序:
@ResponseBody直接将数据写到浏览器
改进:
使用Spring4.2提供的注解进行改进
启动主程序进行测试:
SpinrgBoot内置Tomcat服务器,所以不需要配置Tomcat
结果:
SpringBoot使用一个全局的配置文件,配置文件名是固定的:
全局配置文件可以对一些SpringBoot默认配置进行修改,比如:端口号等
配置文件放在src/main/resources
目录或类路径/config
下
例如,分别使用两种配置文件来修改SpinrgBoot访问端口:
1、基本语法
k:(空格)v
表示一对键值对(空格必须有)
以空格缩进表示层级关系;
只要是左对齐的一列数据,都认为是一个层级的
更详细语法推荐:yml语法
3、获取yml配置文件的值
1、新建Dog和Person实体类:
3、使用注解告诉SpringBoot与配置文件中的值进行绑定
@ConfigurationProperties
将配置文件中每一个属性的值映射到bean组件中
再使用prefix = "person"
告诉springboot对配置文件中的哪个属性进行映射(这里的person对应yml那边的person)
此外,还有一个条件,@ConfigurationProperties
注解能生效的前提是,被注解的类必须是容器中的组件,才能将bean和配置文件的值进行绑定。所以此时需要使用@Component
将该bean加入到容器中。
加入配置文件处理器:
此时发现启动报错了,是因为配置文件中的map,不能使用中文当做key值:
所以修改后的配置文件为:
然后再次启动就可以正常输出了。
当然也可以写成这种:
或者这种:
如果我们将配置中的value修改成中文,如图:
那么对于yml配置文件来说是没问题的,但是对于properties文件来说就有问题。
获取配置文件值注入总结:
1、pom文件中增加 配置文件处理器(spring-boot-configuration-processor)
2、类名上加入@ConfigurationProperties(prefix = "person")
注解来指定和配置文件中的值绑定
3、使用@Component
将类注入到容器中
1、下面我们先将yml配置文件给注释了:
2、然后在properties配置文件中配置Person值:
3、直接启动服务进行测试:
此时发现中文输出乱码:
将properties的字符集编码修改成UTF-8,再次运行即可。
然后重新启动即可。
还存在第三种赋值的方式,就是使用spring底层注解@value
,如图所示:
然后启动,结果:
同样可以配合properties文件实现赋值。
无论是yml还是properties配置文件,都可以使用@Value
和@ConfiguartionProperties
注解来取,那么二者的区别是什么呢?
松散绑定即:
如果实体类属性是 lastName ,那么使用@ConfiguartionProperties
注解时,可以是last-name或lastName,但是使用@value
必须为lastName 才能取到值
@PropertySource:加载指定的配置文件。@ConfigurationProperties注解是默认从全局配置文件`application.properties 中获取值,如果该配置文件内容比较多,想提取部分配置出来,怎么办?
2、指定配置文件位置
启动测试
(为了方便测试,可将application.properties文件中的配置注释了,进行测试)。
注:@PropertySource注解只能加载.properties文件,不能加载.yml文件
@ImportResource:导入Spring的配置文件,让配置文件中的内容生效。因为是springg配置文件,所以该注解只用于properties配置文件。
springBoot里面没有spring的配置文件,如果想要让springBoot认识spring的配置文件。需要用到@ImportResource
该注解。
测试,启动该方法,会发现结果为false,容器中不存在该组件。
此时需要在主程序入口告诉SpringBoot配置文件位置,如图:
此时再启动该方法进行测试即可:
结果:
springBoot更推荐给容器中添加组件的方式是使用@Bean注解
:
springBoot推荐使用全注解的方式来完成往容器中注入组件
测试:
测试结果:true
如果方法名称改了,这里就变成了false。
1、在配置文件中(yml、properties),可以使用SpringBoot提供的随机数组
2、属性配置占位符
例如:
1、修改全局配置文件:
2、使用@ConfigurationProperties注解:
3、测试结果:
Person{
id=110-1152748429,
name='张三9c4e2c3a121af6bed6146b815157c5ee',
is_Boos=true,
barthday=SunMar2700: 00: 00CST1994,
map={
k1=89,
k2=99
},
list=[a,
b,
c],
dog=Dog{
name='张三60ed7cf086d7bab7155bea197b0e1fb8_旺财_true',
age=13
}
}
同时,可以使用这种方式给不存在的属性赋值:
输出结果是:99_666
Profile是Spring对不同环境(多环境)提供不同配置功能的支持,比如在开发、测试、生产环境配置文件会有不同,此时就可以通过Profile来激活、指定参数等方式快速切换环境。
多Profile文件作为环境配置
我们在编写全局配置文件的时候,文件名是application-{profile}.properties
。
例如:
假如:
主配置文件(application.properties或application.yml)
中配置的服务端口号是8081
开发环境(application-dev.properties)
中配置的服务端口号是8080
SIT环境(application-sit.properties)
中配置的服务端口号是8089
UAT环境(application-sit.properties)
中配置的服务端口号是8090
那么此时默认是去找主配置文件中的配置,也就是8081端口。
此时我们可以通过在主配置文件中通过激活的方式来切换环境,如图:
然后启动服务进行测试:
确实切换成了8080。
其中,对于主配置文件是application.yml
的时候,还可以使用多文档块来进行激活。
例如:
测试时候发现,由于项目中此时也存在application-dev.properties
子配置文件,所以此时启动发现优先激活的配置是application-dev.properties
里面的。如果想要激活yml中的dev配置,需要重新修改一个名称,或者删除配置文件application-dev.properties
即可。
总结:
无论使用properties的激活方式还是yml的激活方式,只跟主配置文件后缀有关,跟子配置文件无关
在以上两种配置方式的前提下,此外还有一种命令函激活的方式:
格式:
--spring.profiles.active=[环境名]
当然,还有一个蛇皮操作,就是在将该项目打成jar以后,想要执行该jar包。在使用
java -jar
执行jar包的时候,可以也可以跟上--spring.profiles.active=[环境名]
来指定环境配置。如图所示:
除此以外还有一种修改JVM虚拟机参数的方式,方法跟上面雷同:
格式:
-Dspring.profiles.active=uat
总结:
由于是在环境启动的时候才激活配置的,所以其他的激活配置方式在这种方式面前都无效。哪怕是接下来所讲的其他配置,优先执行命令函或JVM参数配置。
springboot启动会默认去扫描application.properties
或application.yml
,所以文件名是固定的。当然,具体springboot会去哪个位置找配置文件,也是有固定的:
优先级:
–file:./config/ > –file:./ > –classpath:/config/ > –classpath:/
以上配置文件位置是按照优先级由高到低的顺序
,所有位置的配置文件都会被加载,高优先级的配置会覆盖低优先级的配置;
当然我们也可以通过配置spring.config.location
来改变默认配置文件位置。
项目打包好以后,我们可以使用命令行参数的形式,启动项目的时候来指定配置文件的新位置;指定配置文件和默认加载的这些配置文件共同起作用形式互补配置。
例如,我们G盘有一个配置文件,当我们把一个springboot打成jar后,启动jar的时候可以这样写:
spring boot不仅可以从工程的resource文件夹或者config文件夹下加载配置,还可以在以下位置加载配置:
优先级别从高到低;高优先级别的配置覆盖低优先级别的配置,如果配置不同的地方,所有的配置会形成互补配置。
其中上述中的标红部分是我们需要重点掌握内容,从上向下优先级越来越低,高优先级的配置会覆盖低优先级的配置,高优先级的配置和低优先级的配置都会生效,形成互补配置;
命令行参数
以修改启动端口号为例,我们启动jar的同时可以指定启动的端口号为9909
启动以后访问:
如果想在启动的时候修改多个配置,中间用空格间隔即可,比如我们在修改端口的同时还想添加一个路径,就执行下面的这个命令:
java -jar spingboot01-1.0-SNAPSHOT.jar --server.port=9909 --server.servlet.context-path=/boot
其中:–server.port=9909用来修改端口号
–server.servlet.context-path=/boot增加访问路径为/boot,此时我们想要执行结果如下:
记住加载原则:由 jar包外 向jar包内进行寻找,优先加载带 profile 的文件,再加载不带 profile 的文件;
举例:比如我们此时想修改多个加载参数,我们可以单拉出一个配置文件放在和 jar 包的同级目录下:
此时如果启动这个 jar 肯定端口号为8801,访问路径为 /boot。此时我们在 jar 所在的同级目录放置一个配置文件,端口号为8888,访问路径为/hai;
此时启动这个 jar(啥参数都不用加)
此时我们访问:http://localhost:8888/hai/hello
所以支持配置加载来源,可查看官方文档。
问题:配置文件到底能写什么?怎么写?自动配置原理;
配置文件能配置的属性参照官网
自动配置原理(SpringBoot 精华)
1)、SpringBoot启动的时候加载主配置类,开启了自动配置功能
@EnableAutoConfiguration
2)、@EnableAutoConfiguration 作用:
EnableAutoConfigurationImportSelector
给容器中导入一些组件?selectImports()
方法导入哪些组件。
SpringFactoriesLoader.loadFactoryNames()
扫描所有jar包类路径下 META-INF/spring.factories
把扫描到的这些文件的内容包装成properties对象
从properties中获取到EnableAutoConfiguration.class
类(类名)对应的值,然后把他们添加在容器中
将 类路径下 META-INF/spring.factories 里面配置的所有EnableAutoConfiguration
的值加入到了容器中;
每一个这样的
xxxAutoConfiguration
类都是容器中的一个组件,用他们来做自动配置。
下面以HttpEncodingAutoConfiguration
自动配置类为例来讲述原理
鼠标点击进入HttpEncodingAutoConfiguration类中查看
归根结底就是,根据不同的判断条件来判断该配置类是否能生效。
鼠标点击进入ServerProperties类中:前缀是server,属性是port、address
所有配置文件(application.properties或application.yml
)中能配置的属性,都是在XXXProperties类中封装着,配置文件能配置什么就可以参照某个功能对应的这个属性类。
如:port和address的配置。
自动配置精髓总结:
1)SpringBoot启动会加载大量的自动配置类
2)查看我们需要的功能里面有没有SpringBoot默认写的自动配置类;
3)我们再来看这个自动配置类中到底配置了哪些组件;
4)给容器中自动配置类添加组件的时候,会从properties类中获取某些属性,我们就可以在application.properties指定这些属性的值。
再比如常用SpringBoot的数据源自动配置类中,我们常用的properties配置有这些:
自动配置精髓总结:
1)SpringBoot启动会加载大量的自动配置类
2)查看我们需要的功能里面有没有SpringBoot默认写的自动配置类;
3)我们再来看这个自动配置类中到底配置了哪些组件;
4)给容器中自动配置类添加组件的时候,会从properties类中获取某些属性,我们就可以在application.properties指定这些属性的值。
细节:自动配置类中的@conditionnal
注解,之前说只有满足注解的条件,自动配置才生效。我们是可以重写注解中的方法来控制自动配置是否生效的。
我们如何知道SpringBoot在启动的时候哪些自动配置类生效呢?
方法:
(1)开发SpringBoot的debug模式
(2)重启SpringBoot服务,控制台查看自动配置报告:
对于一个应用程序来说日志记录是必不可少的一部分。线上问题追踪,基于日志的业务逻辑统计分析等都离不日志。java领域存在多种日志框架,目前常用的日志框架包括Log4j 1,Log4j 2,Commons Logging,Slf4j,Logback,Jul …
SLF4J定义了统一的日志抽象接口,而真正的日志实现实际上是在运行时决定的——它提供了各类日志框架的binding。
详细日志框架内容可以参考:Java常用日志框架介绍
日志门面(日志接口) | 日志实现 |
---|---|
log4j、log4j2、Logback、JUL |
实际使用过程中是选择一个日志门面和一个日志实现来进行组合使用。
日志门面:
由于日志门面中的JCL自2014年以后停止更新,所以不推荐使用。而JBosss-logging不适合不同程序员使用,排除。
日志实现:
slf4j、log4j 和 logback 都是出自同一人之手,如果选择了slf4j作为门面,那么就需要选择log4j 或logback 作为实现,由于logback 是log4j的改良本,所以一般搭配是slf4j和logback 。log4j2是Apache公司开发的日志实现,现在大部分公司逐渐在使用log42。
Spring框架默认是使用JCL。而SpringBoot选用的是slf4j和logback
在开发的时候,日志记录方法的使用,不应该来直接调用日志的实现类,而是调用日志抽象层里面的方法。
那么slf4j是如何在系统中使用的呢?
该图请参考文章来看,一定要看:https://www.cnblogs.com/bootdo/p/11251459.html
slf4j-simple、logback都是slf4j的具体实现,log4j并不直接实现slf4j,但是有专门的一层桥接slf4j-log4j12来实现slf4j。
例如组合:slf4j + log4j
(1)给系统里面导入slf4j-api.jar和slf4j-log4j12.jar连接器和log4j.jar
(2)导入log4j.properties的配置文件(不同日志实现日志文件不同)
(3)写TEST案例测试
(4)启动服务,查看控制台。
具体实现可参考文档:https://www.jianshu.com/p/805a754053cf
其他组合也是一样的用法。
日志框架经典问题:
假如一个项目中用到了spring(commons-logging)、Hibenate(jboss-logging) 、Mybatis…现在要将日志记录进行统一,统一采用slf4j + Logback,该如何做呢?
方法如图:
(1)由于Spring中有commons-logging日志实现,而Spring框架中的东西又依赖于该实现,如果将Sping中的commons-logging去除了,那么Spring此时肯定启动不起来,所以我们需要导入jcl-over-slf4j.jar
替换commons-logging.jar。
(2)同样的导入log4j-over-slf4j包替换log4j的jar包
(3)同样导入jul-to-slf4j.jar包替换java.util.logging的jar包
(4)导入slf4j-api.jar
(5)最后导入logback-classic.jar和logback-core.jar即可
同样的。如果想要将日志框架替换成slf4j + log4j,那么可以参考该图:
日志框架替换总结:
1、将系统中其他日志框架先排除出去
2、用中间包来替换原有的日志框架
3、导入slf4j其他的实现
1、新建一个SpringBoot项目,加入spring-boot-starter-web
2、显示出jar包的依赖关系图,快捷键是:Ctrl + Alt + Shirft + U
然后找到jar包依赖图中用到日志的jar包:
实际上spring-boot-starter-web依赖spring-boot-starter中已经引用了logback日志的依赖,我们无需在引用下面的依赖了,在使用SpringBoot2开发过程中,为了避免其他日志框架jar包冲突,如果没有要求的情况下,就使用logback。
如果想要统一整合logback日志框架,可以参考文章:
SpringBoot2.x整合logback日志框架
日志级别由低到高为 trace < debug < info < warn < error
日志框架可以控制输出不同级别的日志到控制台或者日志文件中。
logback可以这样使用,例如:
然后启动SpringBoot:
可以看到控制台输出没有trace
和debug
级别的日志,说明SpringBoot2中默认配置了日志级别是info
级别的,所以输出了info级别及其以上的日志。
由于SpringBoot默认是运用logback日志框架,且启动服务的时候自动加载配置,所以只需要修改application.properties或application.yml配置文件就可以覆盖自动加载的配置。
我们先测试将com.example
包下的所有日志级别修改成trace
,如图所示:
修改成ttrace
级别以后,则所有大于trace的日志界别都会打印输出,我们启动服务测试下,发现测试结果成功:
除此了日志级别以外,日志框架常用的设置还有:
1、全局常规设置(格式、路径、级别)
2、指定日志框架文件位置(用以覆盖使用)
3、切换日志框架
SpringBoot日志框架常用的配置还有:
l
日志参数 | 描述 |
---|---|
logging.level.包名 | 指定包下的东西按日志级别输出 |
logging.file.name | 生成日志文件的名称,默认名称是spring.log。当可以填写路径 |
logging.file.path | 指定日志文件生成路径 |
logging.pattern.console | 指定控制台输出日志内容的格式 |
logging.pattern.file | 指定日志内容输出到文件的格式 |
注1:logging.pattern.console
和 logging.pattern.file
不一样,一个是指定控制台输出日志的格式,一个是指定日志内容输出到文件的格式。
例如:
# 在控制台输出的日志的格式
logging.pattern.console=%d{yyyy‐MM‐dd} [%thread] %‐5level %logger{50} ‐ %msg%n
# 指定文件中日志输出的格式
logging.pattern.file=%d{yyyy‐MM‐dd} === [%thread] === %‐5level === %logger{50} ==== %msg%n
注2:如果在logging.file.name配置成路径的情况下。同时还配置了logging.file.path,那么启作用的是logging.file.name。
注3:日志输出格式:
logback默认日志文件格式:
%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %-5level %logger{50} - %msg%n
%d表示日期时间,
%thread表示线程名,
%‐5level:级别从左显示5个字符宽度
%logger{50} 表示logger名字最长50个字符,否则按照句点分割。
%msg:日志消息,
%n是换行符
logging.file.name 配置日志文件名称:
当然,也可以写成路径:
#指定日志文件的路径
logging.file.path=D:/logs/2020-01-07
如果感兴趣的同学具体要看SpringBoot的logback怎么配置的可以去这个位置查看:
自定义日志文件
给类路径下放上每个日志框架自己的配置文件就能覆盖SpringBoot的配置。
注:
logback.xml:
直接就被日志框架识别了,绕过SpringBoot直接起来作用;
logback-spring.xml:日志框架就不直接加载日志的配置项,由SpringBoot解析日志配置,可以使用SpringBoot的高级Profile功能
SpringBoot官方更推荐使用后者。
测试:
引入logback.xml配置文件:
logback.xml内容:
<?xml version="1.0" encoding="UTF-8"?>
<!--
scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒当scan为true时,此属性生效。默认的时间间隔为1分钟。
debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<configuration scan="false" scanPeriod="60 seconds" debug="false">
<!-- 定义日志的根目录 -->
<property name="LOG_HOME" value="/app/log" />
<!-- 定义日志文件名称 -->
<property name="appName" value="atguigu-springboot"></property>
<!-- ch.qos.logback.core.ConsoleAppender 表示控制台输出 -->
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<!--
日志输出格式:
%d表示日期时间,
%thread表示线程名,
%-5level:级别从左显示5个字符宽度
%logger{50} 表示logger名字最长50个字符,否则按照句点分割。
%msg:日志消息,
%n是换行符
-->
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} ----> [%thread] ---> %-5level %logger{50} - %msg%n</pattern>
</layout>
</appender>
<!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 -->
<appender name="appLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 指定日志文件的名称 -->
<file>${LOG_HOME}/${appName}.log</file>
<!--
当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名
TimeBasedRollingPolicy: 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动。
-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--
滚动时产生的文件的存放位置及文件名称 %d{yyyy-MM-dd}:按天进行日志滚动
%i:当文件大小超过maxFileSize时,按照i进行文件滚动
-->
<fileNamePattern>${LOG_HOME}/${appName}-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
<!--
可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。假设设置每天滚动,
且maxHistory是365,则只保存最近365天的文件,删除之前的旧文件。注意,删除旧文件是,
那些为了归档而创建的目录也会被删除。
-->
<MaxHistory>365</MaxHistory>
<!--
当日志文件超过maxFileSize指定的大小是,根据上面提到的%i进行日志文件滚动 注意此处配置SizeBasedTriggeringPolicy是无法实现按文件大小进行滚动的,必须配置timeBasedFileNamingAndTriggeringPolicy
-->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!-- 日志输出格式: -->
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%n</pattern>
</layout>
</appender>
<!--
logger主要用于存放日志对象,也可以定义日志类型、级别
name:表示匹配的logger类型前缀,也就是包的前半部分
level:要记录的日志级别,包括 TRACE < DEBUG < INFO < WARN < ERROR
additivity:作用在于children-logger是否使用 rootLogger配置的appender进行输出,
false:表示只用当前logger的appender-ref,true:
表示当前logger的appender-ref和rootLogger的appender-ref都有效
-->
<!-- hibernate logger -->
<logger name="com.atguigu" level="debug" />
<!-- Spring framework logger -->
<logger name="org.springframework" level="debug" additivity="false"></logger>
<!--
root与logger是父子关系,没有特别定义则默认为root,任何一个类只会和一个logger对应,
要么是定义的logger,要么是root,判断的关键在于找到这个logger,然后判断这个logger的appender和level。
-->
<root level="info">
<appender-ref ref="stdout" />
<appender-ref ref="appLogAppender" />
</root>
</configuration>
如果我们将配置文件名称修改成logback-spring.xml
,那么此时就可以使用SpringBoot的高级Profile功能:
再配置一下激活哪个环境:
然后重启启动服务测试:
如果我们把SpringBoot的日志框架切换成log4j
日志框架
log4j框架替换图:
(1)把spring-boot-starter-logging模块排除了
删除后pom文件也改变了:
(2)pom.xml中导入log4j2的启动器:
<!--log4j2日志框架启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
(3)log4j2配置文件
log4j2配置文件,只需在resources目录下创建log4j2.xml,按照如下配置。
名称必须是log4j2.xml,这样框架才能识别。
log4j2.xml文件内容:
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="warn">
<properties>
<Property name="app_name">five-year-root</Property>
<Property name="log_path">D:\logs\${app_name}</Property>
</properties>
<appenders>
<console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="[%d][%t][%p][%l] %m%n" />
</console>
<RollingFile name="RollingFileInfo" fileName="${log_path}/info/info.log"
filePattern="${log_path}/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log.gz">
<Filters>
<ThresholdFilter level="INFO" />
<ThresholdFilter
level="WARN"
onMatch="DENY"
onMismatch="NEUTRAL" />
</Filters>
<PatternLayout pattern="[%d][%t][%p][%c:%L] %m%n" />
<Policies>
<!-- 归档每天的文件 -->
<TimeBasedTriggeringPolicy interval="1" modulate="true" />
<!-- 限制单个文件大小 -->
<SizeBasedTriggeringPolicy size="2 MB" />
</Policies>
<!-- 限制每天文件个数 -->
<DefaultRolloverStrategy compressionLevel="0" max="10"/>
</RollingFile>
<RollingFile name="RollingFileWarn"
fileName="${log_path}/warn/warn.log"
filePattern="${log_path}/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log.gz">
<Filters>
<ThresholdFilter level="WARN" />
<ThresholdFilter
level="ERROR"
onMatch="DENY"
onMismatch="NEUTRAL" />
</Filters>
<PatternLayout pattern="[%d][%t][%p][%c:%L] %m%n" />
<Policies>
<!-- 归档每天的文件 -->
<TimeBasedTriggeringPolicy interval="1" modulate="true" />
<!-- 限制单个文件大小 -->
<SizeBasedTriggeringPolicy size="2 MB" />
</Policies>
<!-- 限制每天文件个数 -->
<DefaultRolloverStrategy compressionLevel="0" max="10"/>
</RollingFile>
<RollingFile name="RollingFileError" fileName="${log_path}/error/error.log"
filePattern="${log_path}/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log.gz">
<ThresholdFilter level="ERROR" />
<PatternLayout pattern="[%d][%t][%p][%c:%L] %m%n" />
<Policies>
<!-- 归档每天的文件 -->
<TimeBasedTriggeringPolicy interval="1" modulate="true" />
<!-- 限制单个文件大小 -->
<SizeBasedTriggeringPolicy size="10 MB" />
</Policies>
<!-- 限制每天文件个数 -->
<DefaultRolloverStrategy compressionLevel="0" max="10"/>
</RollingFile>
</appenders>
<loggers>
<root level="info">
<appender-ref ref="Console" />
<appender-ref ref="RollingFileInfo" />
<appender-ref ref="RollingFileWarn" />
<appender-ref ref="RollingFileError" />
</root>
</loggers>
</configuration>