目录

一.什么是框架,怎么理解框架?

1.让代码的结构更加清晰:

2.可以让程序员减少编写的代码,减少很多重复的代码:

二.什么是Spring Boot框架 ?

三.微服务,分布式和集群的区别是什么 ?

四.Spring Boot 开发环境。

1.什么时候用Snapshot版本?

2.稳定版使用Snapshot版本行不行?

五.配置JDK版本和创建Maven项目。

1.maven的setting.xml文件设置:

2.那么什么是maven呢?

六.配置Maven镜像。

1.全局配置。

2.单项目配置。

七.pom.xml中parent标签和dependency标签的区别?

八.parent标签中已经定义了依赖,为什么还要通过dependency引入重复的依赖?

1、首先得明白  dependencies 与 dependencyManagement的区别:

九.GroupId和ArtifactId两个字段是做什么的?

十.spring-boot-maven-plugin插件(简化部署)。

十一.什么是spring-boot-starter?

十二.@SpringBootApplication 注解的作用?

十三.@SpringBootConfiguration注解的作用?

十四.@EnableAutoConfiguration注解的作用?

十五.@ComponentScan注解。

十六.@EnableAutoConfiguration注解和@ComponentScan注解的区别?

十七.Spring @controller,@service,@repository,@component区别。

十八.@Bean 和 @Component的区别?

十九.对于@Autowired注解的自动注入对象问题。

二十.不懂的问题。

二十一.使用Spring Initializer 快速创建Spring boot项目。

1.创建项目的时候,我们需要保持联网状态。

2.创建的项目会自动在pom文件中引入相应的jar包。

3.resource文件夹目录结构:

二十二.Spring Boot的配置文件。

1.Spring Boot使用一个全局的配置文件(有两种写法,配置文件名称是固定的):

2.配置文件的作用:

二十三.YAML的语法格式。

二十四.YAML支持的三种数据结构。 

1.对象:键值对的集合(Map)。分为行内写法和非行内写法:

    (1)非行内写法:

    (2)行内写法:

2.数组:一组按次序排列的值(List,Set)。分为行内写法和非行内写法:

    (1)非行内写法:

    (2)行内写法:

3.字面量:单一的,不可再分的值(数字,字符串,Boolean)。

    (1)双引号“”:“会转义”字符串里面的特殊字符。

    (2)单引号‘’:“不会转义”特殊字符。

二十五.YAML配置文件值的获取。 

二十六.配置文件乱码问题。

二十七.@ConfigurationProperties和@Value注解的区别是什么?

二十八.@PropertySource的作用?

二十九.@ImportSource的作用?

三十.用配置类的方式向容器中注入组件。

三十一.对于用配置文件进行属性注入的情况说明。

三十二.配置文件占位符。

三十三.Spring Boot 的 Profile文件。

1.我们可以在resource下定义两个文件,application-dev.properties和application-prod.properties。

2.我们还可以使用命令行的方式,如下图(注意前面时两个-):

三十四.配置文件加载顺序。

三十五.什么是Spring Boot自动配置原理?

三十六.Spring Boot的自动配置原理是怎样的?

1.@Import注解:

2.EnableAutoConfigurationImportSelector类:

 3.selectImports()方法:

三十七.META-INF/spring.factories 文件。

三十八.用HttpEncodingAutoConfiguration来演示自动配置。

三十九.关于Spring Boot自动配置的结论。

四十.市面上的日志框架有哪些?

四十一.什么是日志门面和日志实现?

四十二.日志门面和日志实现的关系是怎样的呢?

四十三.Spring Boot使用的是哪个日志框架?

四十四.日志框架SLF4j的使用。

四十五.两张图。

1.实现绑定过程:

2.桥接旧的日志框架:

四十六.SLF4j日志级别。

四十七.SLF4j的一些功能。


一.什么是框架,怎么理解框架?

框架就是在实际开发中,可以让程序员减少编写的代码,减少很多重复的代码,让代码的结构更加清晰,耦合度更低,后期维护更方便。

1.让代码的结构更加清晰:

在javaSE中你可以使用JDBC来连接并操作数据库,在不使用框架的情况下,SQL语句都是写在JAVA代码中的。而在使用框架的情况下(例如MyBatis),SQL语句可以写在配置文件中。将SQL写在配置文件中(例如XML文件),使JAVA代码和SQL分离出来,当然更清晰。

2.可以让程序员减少编写的代码,减少很多重复的代码:

在编写servlet(Server Applet,全称Java Servlet)来处理HTTP请求时,请求地址的映射都是写在web.xml这个配置文件中的,比较繁琐,如下图:

                                                                                               

java SpringBoot DTO属性增加自定义去除空格注解 springboot去除没用的包_java

然而,当使用springMVC框架时,只需要在对应的类名上方添加@RequestMapping注解,就能够使请求地址和处理请求的CLASS一一对应起来。这样就极大的减少了需要编写的代码和重复代码。

二.什么是Spring Boot框架 ?

SpringBoot是由Pivotal团队在2013年开始研发、2014年4月发布第一个版本的全新开源的轻量级框架。它基于Spring4.0设计,不仅继承了Spring框架原有的优秀特性,而且还通过简化配置来进一步简化了Spring应用的整个搭建和开发过程。另外SpringBoot通过集成大量的框架使得依赖包的版本冲突,以及引用的不稳定性等问题得到了很好的解决。

简单来说,Spring Boot框架是Spring框架下的子框架,是Spring技术栈的一个大整合。它的出现是为了简化Spring项目搭建时的配置等。

它是J2EE开发的一站式解决方案。

三.微服务,分布式和集群的区别是什么 ?

微服务是一种架构风格,就是很小的服务,小到一个服务只对应一个单一的功能,只做一件事。这个服务可以单独部署运行,服务之间可以通过rpc来相互交互,每个微服务都是由独立的小团队开发,测试,部署,上线,负责它的整个生命周期。例如:淘宝的用户注册功能,用户注册功能就是一个单一的功能,这些功能就能够单独部署运行。

分布式是一种部署方式,顾名思义就是服务分散部署在不同的机器上的,一个服务可能负责几个功能,是一种面向SOA架构的,服务之间也是通过rpc来交互或者是webservice来交互的。简单来说,就是一个业务分拆成多个子业务,部署在不同的服务器上。

集群就是同一个业务(功能),部署在多个服务器上。例如:当注册人数较多,并发较大时,一个服务器不能满足需求注册需求,那么可以把注册功能copy到多个服务器上进行部署,就是就能应对并发较大的问题。

微服务相比分布式服务来说,它的粒度更小,服务之间耦合度更低,由于每个微服务都由独立的小团队负责,因此它敏捷性更高,分布式服务最后都会向微服务架构演化,这是一种趋势。

四.Spring Boot 开发环境。

本次Spring Boot 的学习,是在以下环境下进行的:

由于Spring Boot 框架的jdk要求是1.7及以上,并且最好用maven3.x。所以,

-jdk:java version "1.8.0_112"

-maven:Apache Maven3.3.9

-IDEA:IntelliJ IDEA Ultimate 2017.2.7 x64

-Spring Boot:spring-boot-1.5.9.RELEASE.jar

这里可以简单说一下jar包的Snapshot和Release版本的区别:Snapshot版本代表不稳定、尚处于开发中的版本,快照版本。Release版本则代表稳定的版本,发行版本。

1.什么时候用Snapshot版本?

       依赖库中的jar正处于开发的阶段,会被经常被更新,这种情况下,如果使用Release,会频繁增加版本号,导致版本号的滥用。在上传jar时,选择Snapshot和Release上传时,在版本号的构建上有所不同,上传同样的版本号jar包时,Snapshot在版本号的后面会自动追加一串新的数字,就是所谓的日期标签,这样在不断更新jar包时,可以不用每次都要将版本号提高一个版本,可以有效的维护版本号。

2.稳定版使用Snapshot版本行不行?

不行,因为会造成不稳定。比如说,今天你依赖某个Snapshot版本的第三方库成功构建了自己的应用,明天再构建时可能就会失败,因为今晚第三方可能已经更新了它的Snapshot库。你再次构建时,Maven会去远程repository下载Snapshot的最新版本,你构建时用的库就是新的jar文件了,这时正确性就很难保证了。稳定版应该依赖Release版本的jar包,这样更新时需要更新版本号,版本号没变时,依赖的jar包也不会变。

五.配置JDK版本和创建Maven项目。

1.maven的setting.xml文件设置:

 在setting.xml文件中的<profiles>标签中添加如下配置,这样配置的目的是告诉maven在进行打包的时候,使用jdk1.8进行编译。

<profile>
		  <id>jdk-1.8</id>
	 
		  <activation>
			<activeByDefault>true</activeByDefault>
			<jdk>1.8</jdk>
		  </activation>
	 
		  <properties>
			<maven.compiler.source>1.8</maven.compiler.source>
			<maven.compiler.target>1.8</maven.compiler.target>
			<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
		  </properties>
		</profile>

另外需要在IDEA中配置IDEA将要使用的maven版本,对应的setting.xml和本地仓库。

java SpringBoot DTO属性增加自定义去除空格注解 springboot去除没用的包_spring boot_02

localRepository用于配置本地仓库,本地仓库其实起到了一个缓存的作用,它的默认地址是 C:\Users\用户名.m2。当从maven中获取jar包的时候,maven首先会在本地仓库中查找,如果本地仓库有则返回;如果没有则从远程仓库中获取包,并在本地库中保存。

2.那么什么是maven呢?

我目前的理解,maven的核心就是pom.xml,使用maven是为了更好的帮项目管理包依赖(管理jar包的工具)。

六.配置Maven镜像。

当在pom.xml中引入依赖时,idea会把项目依赖的jar包导入到本地仓库。这时,会发现jar包下载的速度非常的慢,这是因为Maven默认配置的依赖仓库主要部署在国外,在国内当然下载慢了。对于这个问题,可以通过配置开源镜像站解决这个问题的,例如阿里云镜像等。

1.全局配置。

添加阿里云的镜像到maven的setting.xml配置中,这样就不需要每次在pom中,添加镜像仓库的配置,在mirrors节点下面添加子节点:

<mirror>  
      <id>alimaven</id>  
      <name>aliyun maven</name>  
      <url>https://maven.aliyun.com/repository/public/</url>  
      <mirrorOf>central</mirrorOf> <!--表示匹配原仓库的请求都转到镜像仓库-->         
</mirror>

<mirror>
      <id>repo2</id>
      <name>Human Readable Name for this Mirror.</name>
      <url>http://repo2.maven.org/maven2/</url>
      <mirrorOf>central</mirrorOf>
</mirror>

<mirror>
      <id>ui</id>
      <name>Human Readable Name for this Mirror.</name>
      <url>http://uk.maven.org/maven2/</url>
      <mirrorOf>central</mirrorOf>
</mirror>

2.单项目配置。

单项目配置时,需要修改pom.xml文件。pom.xml文件中,没有mirror元素。在pom.xml文件中,通过覆盖默认的中央仓库的配置,实现中央仓库地址的变更。

<repositories>
        <repository>
            <id>central</id>
            <name>aliyun maven</name>
            <url>https://maven.aliyun.com/repository/public/</url>
            <layout>default</layout>
            <!-- 是否开启发布版构件下载 -->
            <releases>
                <enabled>true</enabled>
            </releases>
            <!-- 是否开启快照版构件下载 -->
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

注:Maven默认中央仓库的id 为 central。id是唯一的。因此使用< id>central< /id>覆盖了默认的中央仓库。 

七.pom.xml中parent标签和dependency标签的区别?

对于这个问题,看到了一个例子:

如果有三个项目A、B、C,

B通过<parent>引用的项目A,C项目中通过<dependency>依赖的A,

那么B可以使用A项目中<dependency>中依赖类的方法,但是不能调用A项目中自己定义的类和方法,

C既可以使用A项目自己提供的方法,也可以使用A项目<dependency>引入类的方法。

简单来说, <parent>相当于引入了一个空项目,只用来引入依赖(并不含代码),而<dependency>则是引入了项目,不仅可以使用项目中的东西,来可以使用项目的依赖。

如果要引入一个jar包,需要在pom文件中加上<dependency></dependency>就可以依赖相应的jar包,这样就可以使用其本身的类和方法还有依赖jar的类和方法。

另外,还有一个解释:

例如,有两个web项目W1、W2,一个java项目J1,依赖同一个jar包:common.jar。如果分别在各自pom文件中引入common.jar的依赖,那么当common.jar的版本发生变化时,三个项目的pom文件都要改common.jar的version,项目中依赖越多修改越多。此时就可以使用parent标签, 可以创建一个parent项目,打包类型为pom,parent项目中没有任何代码,只是管理多个项目之间公共的依赖。在parent项目的pom文件中定义对common.jar的依赖,W1W2J1三个子项目中只需要定义<parent></parent>,parent标签中写上parent项目的pom坐标就可以引用到common.jar了。

这种说法就是parent项目仅仅作为一个“依赖中间客”的任务,其本身没有任何java代码,只是存粹的依赖其他项目,这样多个项目依赖parent项目时,只需要改变parent项目中的依赖jar就能改变所有依赖parent项目需要的jar。通过parent标签引入依赖的这种方式可以解耦合(减少项目和其所依赖项目之间的耦合度<关联度>)。

八.parent标签中已经定义了依赖,为什么还要通过dependency引入重复的依赖?

这个问法可能有人不理解,那么来看一张图:

java SpringBoot DTO属性增加自定义去除空格注解 springboot去除没用的包_java_03

这个maven项目继承了spring-boot-starter-parent依赖,而spring-boot-starter-parent又继承了spring-boot-dependencies依赖,spring-boot-dependencies中dependency了spring-boot-starter-web jar。

java SpringBoot DTO属性增加自定义去除空格注解 springboot去除没用的包_maven_04

而在第一张图可以看到,再一次的依赖了spring-boot-starter-web(开发web程序最最基础的包,其中包含tomcat,这导致用Spring Boot开发项目时,不用额外配置tomcat服务器) jar,只不过这次没有写版本号而已。那么为什么要重复引用呢?

spring-boot-dependencies 可以说是真正管理SpringBoot应用里面所有依赖版本的地方,SpringBoot的版本控制中心;

仔细看可以看到,dependencies外还有dependencyManagement标签。

java SpringBoot DTO属性增加自定义去除空格注解 springboot去除没用的包_jar_05

1、首先得明白  dependencies 与 dependencyManagement的区别:

dependencies即使在子项目中不写该依赖项,那么子项目仍然会从父项目中继承该依赖项,如果父类有很多依赖,这样没用的也继承来,会造成臃肿。

dependencyManagement里只是声明依赖,并不实现引入,因此子项目需要显式的声明需要用的依赖。如果不在子项目中声明依赖,是不会从父项目中继承下来的;只有在子项目中写了该依赖项,并且没有指定具体版本,才会从父项目中继承该项,并且version和scope都读取自父类pom;另外如果子项目中指定了版本号,那么会使用子项目中指定的jar版本。

这也是为什么在依赖一些jar的时候可以不指定版本,因为在依赖parent时,parent中已经声明了依赖jar的版本,只需要重新声明依赖即可。

九.GroupId和ArtifactId两个字段是做什么的?

首先通过idea创建一个maven项目,这里就略过,但是在创建maven项目时,需要填写GroupId和ArtifactId两个字段。

那么这两个字段是什么含义,有什么用呢?

GroupIdArtifactId被统称为“坐标”是为了保证项目唯一性而提出的,如果你要把你项目弄到maven本地仓库去,你想要找到你的项目就必须根据这两个id去查找。

  GroupId一般分为多个段,这里我只说两段,第一段为域,第二段为公司名称。域又分为org、com、cn等等许多,其中org为非营利组织,com为商业组织。举个apache公司的tomcat项目例子:这个项目的GroupId是org.apache,它的域是org(因为tomcat是非营利项目),公司名称是apache,ArtifactId是tomcat。
  
  比如我创建一个项目,我一般会将GroupId设置为cn.joe,cn表示域为中国,joe是我个人姓名缩写,ArtifactId设置为projectOne,表示你这个项目的名称是projectOne。

需要在pom.xml文件中添加配置:

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.9.RELEASE</version>
    </parent>

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

并且要编写主程序类:

/**
 * @SpringBootApplication 来标注一个主程序类,说明这是一个Spring Boot应用
 */
@SpringBootApplication
public class HelloWordMainApplication {
    public static void main(String[] args) {

        //启动Spring Boot应用
        SpringApplication.run(HelloWordMainApplication.class,args);
    }
}

在启动项目的时候,只需要运行main()方法就可以了。

这里的代码就不贴了,很简单,但是需要注意的是,@RequestMapping这个注解的value值,也就是映射路径的前缀一定要使用“/”。

十.spring-boot-maven-plugin插件(简化部署)。

可以用spring-boot-maven-plugin 插件来将应用(项目)打成一个可执行的jar包。这样在发布项目的时候,不需要额外把jar/war包放到服务器上,然后启动服务器。只需要用java -jar

<!-- 这个插件,可以将应用(项目)打成一个可执行的jar包-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

没有用插件打包时运行java -jar命令时提示额米有主清单属性。

java SpringBoot DTO属性增加自定义去除空格注解 springboot去除没用的包_maven_06

 并且,没有插件打包时,在目录下只会生成一个jar文件。

java SpringBoot DTO属性增加自定义去除空格注解 springboot去除没用的包_java_07

 用插件打包时运行java -jar命令时会启动项目:

java SpringBoot DTO属性增加自定义去除空格注解 springboot去除没用的包_jar_08

并且有插件打包时,在目录下会生成2个文件(当然运行时还是.jar文件):

java SpringBoot DTO属性增加自定义去除空格注解 springboot去除没用的包_jar_09

十一.什么是spring-boot-starter?

spring-boot将所有功能场景都抽取出来,做成一个个starter启动器。

当想使用一些场景时,只需要启动对应的场景启动器,那么对应场景所需要的所有jar包就会全部导入到的项目中。

spring-boot--starter可以称之为场景启动器(场景可以理解为功能),它是一些jar依赖的集合。

十二.@SpringBootApplication 注解的作用?

用@SpringBootApplication标注的类,说明这个类是Spring Boot项目的主配置类。Spring Boot可以运行这个类的main()方法来启动Spring Boot项目。

@SpringBootApplication是一个组合注解,通过翻看@SpringBootApplication的源码发现,它是由下列的注解组合而成:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {

虽然标注了多个注解,但实际上除了最上面的4个元注解,重要的只有下面的三个Annotation:

  • @SpringBootConfiguration(@SpringBootConfiguration点进去查看发现里面还是应用了@Configuration)
  • @EnableAutoConfiguration
  • @ComponentScan

所以,@SpringBootConfiguration其中的一个含义就是,将注解所在包下(主配置类下的包)的组件扫描进入spring容器,并自动配置一些配置类。 

十三.@SpringBootConfiguration注解的作用?

@Configuration用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。

配置类也是一个组件@Component。

十四.@EnableAutoConfiguration注解的作用?

@EnableAutoConfiguration注解是开启自动配置功能的。

通过看源代码知道,@EnableAutoConfiguration可以看到它是由 @AutoConfigurationPackage,@Import(EnableAutoConfigurationImportSelector.class)这两个注解来组成的。

@AutoConfigurationPackage(自动配置包注解)是由@Import({Registrar.class})来实现的,@Import是spring的底层注解,是用来给容器中导入组件,导入哪些组件是由Registrar.class来定义的。而在@EnableAutoConfiguration中的@Import返回的组件是@EnableAutoConfiguration注解所在包下的类文件。

@Import(EnableAutoConfigurationImportSelector.class)的作用就是自动配置一些配置类,免去了手动编写配置类注入功能组件等工作。例如把配置类中视图解析器注入进容器中。

十五.@ComponentScan注解。

@ComponentScan用于类或接口上,主要是指定扫描路径,spring会把指定路径下带有指定注解的类自动装配到bean容器里。会被自动装配的注解包括@Controller、@Service、@Component、@Repository等等。其作用等同于<context:component-scan base-package="com.maple.learn" />配置。

@ComponentScan使用常用属性如下:

basePackages、value:指定扫描路径,如果为空则以@ComponentScan注解的类所在的包为基本的扫描路径。

basePackageClasses:指定具体扫描的类。

includeFilters:指定满足Filter条件的类。

excludeFilters:指定排除Filter条件的类。

includeFilters和excludeFilters 的FilterType可选:ANNOTATION=注解类型 默认、ASSIGNABLE_TYPE(指定固定类)、ASPECTJ(ASPECTJ类型)、REGEX(正则表达式)、CUSTOM(自定义类型),自定义的Filter需要实现TypeFilter接口。

ComponentScan的常见的配置如下:

@ComponentScan(value="com.maple.learn",
        excludeFilters = {@ComponentScan.Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class)},
        includeFilters = {@ComponentScan.Filter(type=FilterType.ANNOTATION,classes={Controller.class})}
        )

public class SampleClass{
        ……

十六.@EnableAutoConfiguration注解和@ComponentScan注解的区别?

1.@EnableAutoConfiguration:扫包范围默认当前类。

2.@ComponentScan(" ") 扫包范围默认当前类所在包下面的所有类。

3.@ComponentScan(" ")扫包范围大于@EnableAutoConfiguration,@ComponentScan(" ")依赖于@EnableAutoConfiguration启动程序。@EnableAutoConfiguration自己可以启动程序,@ComponentScan(" ")自己却不能启动程序。

4.Spring IoC容器可以自动装配(autowire)。

十七.Spring @controller,@service,@repository,@component区别。

1、@controller 控制器(注入服务)

用于标注控制层,相当于struts中的action层。

2、@service 服务(注入dao)

用于标注服务层,主要用来进行业务的逻辑处理。

3、@repository(实现dao访问)

用于标注数据访问层,也可以说用于标注数据访问组件,即DAO组件。

4、@component (把普通pojo实例化到spring容器中,相当于配置文件中的 <bean id="" class=""/>)。

泛指各种组件,就是说当类不属于各种归类的时候(不属于@Controller、@Services等的时候),就可以使用@Component来标注这个类。

共同点:被@controller 、@service、@repository 、@component 注解的类,都会把这些类纳入进spring容器中进行管理。

十八.@Bean 和 @Component的区别

1、@Component注解表明一个类会作为组件类,并告知Spring要为这个类创建bean。

2、@Bean注解告诉Spring这个方法将会返回一个对象,这个对象要注册为Spring应用上下文中的bean。通常方法体中包含了最终产生bean实例的逻辑。

两者的目的是一样的,都是注册bean到Spring容器中。

区别:

@Component(@Controller、@Service、@Repository)通常是通过类路径扫描来自动侦测以及自动装配到Spring容器中。

而@Bean注解通常是在标有该注解的方法中定义产生这个bean的逻辑。

@Component 作用于类,@Bean作用于方法。

十九.对于@Autowired注解的自动注入对象问题。

写了一个小的Demo,得出来一个结论:

两个Controller 注入的Service是同一个,在一个Controller中改变了Service的属性后,在另一个Controller中访问Service时,得到的是改变后的属性值。

二十.不懂的问题。

@ComponentScan用于类或接口上,主要是指定扫描路径,spring会把指定路径下带有指定注解的类自动装配到bean容器里。那什么还要使用@EnableAutoConfiguration中的注解呢?

@EnableAutoConfiguration中有两个注解,其中@Import(AutoConfigurationImportSelector.class)是自动装载的关键,但我不知道另一个@AutoConfigurationPackage是干什么用的。我在网上搜索看了很多文章都说@AutoConfigurationPackage的作用是在SpringBoot应用启动时默认会将启动类所在的package作为自动配置的package,但这件事不是@ComponentScan干的吗?难道@AutoConfigurationPackage中这两个注解干的是同一件事?

二十一.使用Spring Initializer 快速创建Spring boot项目。

创建的过程就略过了,我们说下面几点。

1.创建项目的时候,我们需要保持联网状态。

2.创建的项目会自动在pom文件中引入相应的jar包。

3.resource文件夹目录结构:

static:保存所有的静态文件,例如:js,css,images;

    templates:保存所有的模板页面(Spring Boot 的默认jar包使用的是嵌入式的tomcat,默认不支持jsp页面)。可以使用模板引擎(freemarker,thymeleaf)。

application.properties:Spring Boot应用的配置文件(可以用来更改一些Spring Boot的默认配置)。

二十二.Spring Boot的配置文件。

1.Spring Boot使用一个全局的配置文件(有两种写法,配置文件名称是固定的):

    application.properties

    application.yml

2.配置文件的作用:

Spring Boot在底层都给我们配置好了一些默认值。我们可以通过全局配置文件来修改其默认值。

Yaml(Yet Another Markup Language :也是一种标记语言)是一个可读性高,用来表达数据序列化的格式。是以数据为中心,比xml更适合做配置(省去了繁重的标签配置)。

    xml配置如下:

<server>
    <port>8081</port>
</server>

二十三.YAML的语法格式。

1.使用缩进来表示层级关系。

2.缩进时不允许使用tab键,只允许使用空格。

3.缩进时空格数目不重要,只要相同层级的元素左侧对其即可。

4.属性和值是大小写敏感的。但是-x 和 X是一样的,例如:last-name和lastName是相同的,都可以注入到实体类中的lastName属性中。

5.用K: V的形式表示一对键值对(注意,:和 V之间一定要有空格)。如下:

server:
    port: 8080

二十四.YAML支持的三种数据结构。 

1.对象:键值对的集合(Map)。分为行内写法和非行内写法:

    (1)非行内写法:

server:
    port: 8080


user:
    name: joe
    age: 24

    (2)行内写法:

user: {name: joe,age: 24}

2.数组:一组按次序排列的值(List,Set)。分为行内写法和非行内写法:

- 和 值之间也要使用空格)。

    (1)非行内写法:

pets:
 - cat
 - dog
 - pig

    (2)行内写法:

pets: [cat,dog,pig]

3.字面量:单一的,不可再分的值(数字,字符串,Boolean)。

username: joe

字符串默认不加单引号或者双引号:

    (1)双引号“”:“会转义”字符串里面的特殊字符。

                  name: “zhangsan \n lisi”:输出;zhangsan 换行 lisi

    (2)单引号‘’:“不会转义”特殊字符。

                        name: “zhangsan \n lisi”:输出;zhangsan \n lisi

总的来说,不管是哪种写法,都是利用空格来表示层级关系,并且“-” 和 “:” 之后一定要有空格,然后才能写value值。

二十五.YAML配置文件值的获取。 

如果我们在yaml文件中定义了一个对象user,那么我们就可以创建一个实体类user,一一对应上yaml文件中的user属性。然后使用@ConfigurationProperties这个注解标注在user类上,

这样运行程序后,配置文件中的user属性值会赋值给user实体类中的属性。

@ConfigurationProperties注解的作用就是告诉Spring Boot将本类中的所有属性和配置文件中的相关配置(相关属性)进行绑定。

注意:

@ConfigurationProperties 这个注解有一个参数是prefix(前缀),它用来指定该实体类是用配置文件中的哪个对象进行映射。本例子中就是@ConfigurationProperties(prefix = “user”)。

此外:

要想使用@ConfigurationProperties这个注解,我们首先要在pom文件中引入如下依赖,这样我们才能使用ConfigurationProperties这个注解(引入之后,有对应的属性提示,通常引入):

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

@ConfigurationProperties注解要想能自动映射,还需要其标注的类是容器中的组件,所以该注解通常要个@Component注解一起使用。

二十六.配置文件乱码问题。

乱码是因为同一个字符的“输入”和“输出”的码表不一样。

例如:张三 -----------------》0000  ----------------》李四;

                   输入(码表)            输出(码表)

所以,我们只需要配置下properties文件的编码和idea控制台输出编码一致即可。

二十七.@ConfigurationProperties和@Value注解的区别是什么?

@Value注解类似于bean标签里面的value属性。@Value:给属性赋值。
                 1、基本数值
                 2、可以写SpEL; #{}
                 3、可以写${};

@ConfigurationProperties 默认从全局配置文件中获取值。

<bean class = "xxxx">
    <propertyname = "yyy" value = "?"></property>
</bean>

1.@ConfigurationProperties(prefix = "xxxx")可以读取多个属性,例如对象。而@value读取单个属性只能读取单一属性(每个属性上都要加@Value注解),支持对象中的属性,SpEl(Spring的表达式),Boolean,日期,List<String>等。注意事项:maps和dog不能使用@value注解,@Value不支持复杂类型。

@Component
public class Person1 {
    @Value("${person.last-name}")
    String LastName;

   @Value("#{12*2}")
    Integer age;

    @Value("true")
    boolean boss;

    @Value("${person.birth}")
    Date birth;

    Map<String, String> maps;
    @Value("${person.list}")
    List<String> list;

    Dog dog;

2.表格对比:

 

@ConfigurationProperties

@value

功能

批量注入配置文件的属性

一个个指定

松散绑定(松散语法)

支持

不支持

SPEL

不支持

支持

JSR303数据校验

支持(邮箱验证)

不支持

复杂类型封装

支持

不支持

 

    松散绑定(松散语法)指的是,例如:@value只能 @Value("${person.last-name}")来的到last-name属性的值,而不能通过@Value("${person.lastName}")来的到last-name属性的值。

    支持(邮箱验证)是配置文件注入值的数据校验,需要@Validated和@Email两个注解来实现。

经过自己测试,yml文件好像不支持SPEL,所以SPEL写在yml文件中,通过@Value也不能获取到。但是SPEL可以写在@Value注解参数里。

二十八.@PropertySource的作用?

加载指定的属性文件*.properties(*.yml是不支持的)。可以配合@Value 和@ConfigurationProperties 使用。

亲测:

1.如果和@ConfigurationProperties或者和@Value分别一起使用,那么注入属性的时候,查找属性的顺序为:application.properties   >   application.yml  >   @PropertySource配置的文件。

也就是说,一但查找到了,就不继续查找了,直接将查找到的属性值注入进去。

2.如果和@ConfigurationProperties,@Value一起使用,那么注入属性的时候,查找属性的顺序为:@ConfigurationProperties 先按 application.properties   >   application.yml  >   @PropertySource配置的文件 的顺序查找属性,没有找到,在让@Value按上面一样的顺序再次查找。

简单来说,就是互补配置,如果找到了就赋值,没有找到就继续查找。

3.@PropertySource注解中的值是数组形式的,可以配置多个文件。当多个文件时,我们可以认为是值覆盖,如果user2.properties中有相同的属性值,那么就会使用user2.properties中的属性值。

@PropertySource(value = {"classpath:user.properties","classpath:user2.properties"})

二十九.@ImportSource的作用?

用来导入spring的配置文件,使配置文件中的内容生效。Spring Boot里没有Spring的配置文件,我们自己编写的配置文件也不能自动识别。想要Spring的配置文件生效,需要在启动类上加上注解@ImportSource(locations = {"classpath:xxx.xml"})。

三十.用配置类的方式向容器中注入组件。

虽然我们可以通过@ImportSource注解的方式来向容器中注入Bean,例如bean.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">


    <bean id = "service1" class = "cn.joe.springbootquick.HelleService"></bean>

</beans>

但是SpringBoot不建议我们这么做,它推荐我们向容器中注入组件的方式是,全注解的方式。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyAppConfig {

    @Bean
    public HelleService helloService1(){
        return new HelleService();
    }
}

@Configuration指明当前类是一个配置类,就是用来代替Spring之前的配置文件的。

@Bean将其标注方法的返回值作为一个组件注入到容器中,该组件的id为该方法的方法名。 

三十一.对于用配置文件进行属性注入的情况说明。

说几个结论(亲测),只有@ConfigurationProperties,没有@PropertySource时:

1.在我们使用@ConfigurationProperties注解的时候,我们可以不引入spring-boot-configuration-processor,没有这个processor我们的@ConfigurationProperties一样会生效。processor的作用是,我们引入后,在属性文件中写属性值时,会有对应的提示信息(例如这个对象中有那些属性)。

2.用@ConfigurationProperties注解进行属性注入时,需要对象中(实体类)的属性值有对应的setXXX()方法,否则会注入不进去。 而@Value注解不用setXXX()方法。

3.@ConfigurationProperties 和 @Value注解,都默认去全局配置文件中加载属性(application.properties和application.yml)。

4.@ConfigurationProperties 和 @Value注解同时存在时,只有前者在两个全局配置文件中都没有找到对应的属性时,才会让后者去全局配置文件中查找属性。

5.当application.yml 和 application.properties 两个文件同时存在的时候,application.properties的优先级是高于application.yml的。Spring Boot会先去加载application.properties文件中的user.name属性,如果没有,才回去加载application.yml文件中的user.name属性。

也就是说两个文件都会起作用,只不过有同样的属性的时候,通过@ConfigurationProperties注解和@Value会首先加载application.properties文件中的属性。

Spring Boot更推荐使用application.yml代替application.properties,另外由于properties的配置文件含中文时读取会乱码,而在yml中不会。

三十二.配置文件占位符。

我们在配置application.properties中可以使用${},其中可以写配置文件的其他属性,还有random方法等。

application.yml是不支持这种写法的(亲测)。

user.age=${random.int}

user.uuid=${random.uuid}

user.password=${user.hello:hello}_${random.int}

其中${user.hello:hello}的含义是user.hello没有取到值,则${user.hello:hello}的值为hello。

三十三.Spring Boot 的 Profile文件。

我们在开发时,可能会在开发场景和生产环境之间来回切换(环境的配置信息会不同,例如:数据库连接信息、数据库连接池配置等)。这种切换我们可以通过定义多Profile文件的方式。文件格式为application-{profile}.properties/yml。

1.我们可以在resource下定义两个文件,application-dev.properties和application-prod.properties。

java SpringBoot DTO属性增加自定义去除空格注解 springboot去除没用的包_java_10

由于我们是自动加载主配置文件的,所以要想Profile文件生效我们需要在主配置文件中激活它:

spring.profiles.active=dev

上面的代码的含义就是我们也将使用application-dev.properties进行配置。

既然,又引用了额外的配置文件,那么会覆盖原来的配置文件吗?

不会(亲测)。主配置文件和引入的配置文件都会生效,但是如果有相同的配置(例如:属性名称),那么会以后引入的配置文件为准,我们也可以理解为后引入的配置文件在相同属性方面覆盖了原主配置文件(互补配置)。

而且spring.profiles.active这个属性是不可以重复配置的。

java SpringBoot DTO属性增加自定义去除空格注解 springboot去除没用的包_jar_11

2.我们还可以使用命令行的方式,如下图(注意前面时两个-):

java SpringBoot DTO属性增加自定义去除空格注解 springboot去除没用的包_maven_12

3.我们还可以使用虚拟机参数的方式,如下图(前缀是-D):

java SpringBoot DTO属性增加自定义去除空格注解 springboot去除没用的包_spring_13

4.我们还可以使用运行时指定的方式。

   即,我们将打好的jar包通过java -jar 命令运行时,在文件名后面在指定其要执行的配置。

java SpringBoot DTO属性增加自定义去除空格注解 springboot去除没用的包_java_14

    图片下面的红框说明,已经成功的将端口变为9092(dev这种模式的端口)。

5.在application.properties中,我们可以使用上述几种方式。但是这种创建文件的方式比较麻烦,我们可以使用yml的多文档快:

spring:
  profiles:
    active: prod

server:
 port: 9090
---

spring:
 profiles: prod

server:
 port: 9091

---

spring:
 profiles: dev

server:
 port: 9092

上面的代码就是yml的多文档块,我们可以通过“---” 来将一个文档划分为多个文档块,每个文档块就相当于一个文件,我们可以在每个文档块中定义一个profiles来代表这个文档块,当我们想使用其中一个时,我们只需要通过active:来指定执行哪个代码块的配置。 

三十四.配置文件加载顺序。

1. springboot启动会扫描一下位置的application.properties或者application.yml作为默认的配置文件。
           工程根目录:./config/ 
           工程根目录:./
           classpath:/config/
           classpath:/
        上述文件的优先级从上至下逐个递减,并且所有的文件都会被加载,高优先级的内容会覆盖底优先级的内容,形成互补配置

2.那如果上面的4个优先级同时有application.properties或者application.yml两个文件,那么优先级是怎样的(亲测)?

   优先级从上至下逐个递减不变,然后在此基础上application.properties的优先级大于application.yml。也就是说工程根目录:./config/ 下的application.yml的优先级大于工程根目录:./下的application.properties。

3.我们还可以通过如下命令来告诉springboot执行哪个配置文件,这种方式是在启动包的时候(这种方式在运维的时候非常好用):

spring.config.location=C:/Users/22940/Desktop/application.yml

    通过指定配置文件的方式,优先级高于上述4种(即使是application.yml文件(亲测))。

三十五.什么是Spring Boot自动配置原理?

Spring Boot的自动配置是什么意思呢?

举个例子,当我们想要修改web项目的启动端口,我们只需要在application.properties中写如下代码即可:

server.port=8081

那么为什么我们直接在application.properties写server.port=8081,就能够修改Spring Boot项目启动时的端口号呢?这其中的缘由就是Spring Boot的自动配置原理。

三十六.Spring Boot的自动配置原理是怎样的?

Spring Boot项目在启动的时候,加载主配置类,主配置类上有一个@SpringBootApplication注解,点击进去我们发现是由如下注解组成的:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {

其中,有一个@EnableAutoConfiguration注解,含义是开启自动配置功能。

在点击进去,我们发现@EnableAutoConfiguration是由如下注解组成的:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({EnableAutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {

不看上面的4个元注解,我们来学习一下下面的两个注解:

1.@Import注解:

给容器中导入一些组件,但是导入哪些组件要看其中的value值。所以@Import({EnableAutoConfigurationImportSelector.class})的作用就是,将EnableAutoConfigurationImportSelector类中“挑选的某些东西”作为组件导入到容器中。

2.EnableAutoConfigurationImportSelector类:

   EnableAutoConfigurationImportSelector的父类是AutoConfigurationImportSelector,

package org.springframework.boot.autoconfigure;

import org.springframework.core.type.AnnotationMetadata;

/** @deprecated */
@Deprecated
public class EnableAutoConfigurationImportSelector extends AutoConfigurationImportSelector {
    public EnableAutoConfigurationImportSelector() {
    }

    protected boolean isEnabled(AnnotationMetadata metadata) {
        return this.getClass().equals(EnableAutoConfigurationImportSelector.class) ? ((Boolean)this.getEnvironment().getProperty("spring.boot.enableautoconfiguration", Boolean.class, true)).booleanValue() : true;
    }
}

   点进去父类我们会看到selectImports()方法,

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
    private static final String[] NO_IMPORTS = new String[0];
    private static final Log logger = LogFactory.getLog(AutoConfigurationImportSelector.class);
    private ConfigurableListableBeanFactory beanFactory;
    private Environment environment;
    private ClassLoader beanClassLoader;
    private ResourceLoader resourceLoader;

    public AutoConfigurationImportSelector() {
    }

    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {

 3.selectImports()方法:

    selectImports()方法的返回值是String[ ]类型的,它的返回值将要作为组件注入到容器中。

    该方法中有如下的代码:

List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);

    getCandidateConfigurations()是得到候选配置,点进去如下:

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
        Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
        return configurations;
    }

     其中SpringFactoriesLoader.loadFactoryNames()的作用是扫描所有jar包类路径下的 "META-INF/spring.factories" 文件。这个我们可以通过点进去loadFactoryNames()方法 可以验证:

public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();

        try {
            Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
            ArrayList result = new ArrayList();

            while(urls.hasMoreElements()) {
                URL url = (URL)urls.nextElement();
                Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
                String factoryClassNames = properties.getProperty(factoryClassName);
                result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
            }

    扫描之后,将META-INF/spring.factories文件里面的内容包装正properties对象。

    该方法还可以看到properties.getProperty(factoryClassName)代码,这段代码的作用是将获取上面的到的properties对象的actoryClassName属性值。那么actoryClassName参数的值是什么呢?

    通过上面所有的代码,我们往回追溯的话,可以看到这个值就是 EnableAutoConfiguration.class:

protected Class<?> getSpringFactoriesLoaderFactoryClass() {
        return EnableAutoConfiguration.class;
    }

自动配置功能第一步,就是获取所有jar包类路径下的 "META-INF/spring.factories" 文件并将文件变成的properties对象,然后在获取对象中的EnableAutoConfiguration属性值作为组件注入到容器中,然后用容器中的这些组件进行自动配置。

    也就是说,所有jar包类路径下的spring.factories文件中EnableAutoConfiguration的属性值作为组件加入到了容器中。

三十七.META-INF/spring.factories 文件。

可以找一个spring.factories看一看:

java SpringBoot DTO属性增加自定义去除空格注解 springboot去除没用的包_spring_15

 具体的值:

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\
org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\
org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\
org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\
org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\
org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\
org.springframework.boot.autoconfigure.mobile.DeviceResolverAutoConfiguration,\
org.springframework.boot.autoconfigure.mobile.DeviceDelegatingViewResolverAutoConfiguration,\
org.springframework.boot.autoconfigure.mobile.SitePreferenceAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.reactor.ReactorAutoConfiguration,\
org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.SecurityFilterAutoConfiguration,\
org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration,\
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
org.springframework.boot.autoconfigure.social.SocialWebAutoConfiguration,\
org.springframework.boot.autoconfigure.social.FacebookAutoConfiguration,\
org.springframework.boot.autoconfigure.social.LinkedInAutoConfiguration,\
org.springframework.boot.autoconfigure.social.TwitterAutoConfiguration,\
org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\
org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\
org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration,\
org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration,\
org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.WebSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration

 每一个xxxAutoConfiguration这样的类都作为一个组件加入到容器中,用它们来做自动配置。

三十八.用HttpEncodingAutoConfiguration来演示自动配置。

 我们可以通过spring.factories直接点进去HttpEncodingAutoConfiguration这个类:

@Configuration
@EnableConfigurationProperties({HttpEncodingProperties.class})
@ConditionalOnWebApplication
@ConditionalOnClass({CharacterEncodingFilter.class})
@ConditionalOnProperty(
    prefix = "spring.http.encoding",
    value = {"enabled"},
    matchIfMissing = true
)
public class HttpEncodingAutoConfiguration {
    private final HttpEncodingProperties properties;

    public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
        this.properties = properties;
    }

    @Bean
    @ConditionalOnMissingBean({CharacterEncodingFilter.class})
    public CharacterEncodingFilter characterEncodingFilter() {
        CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
        filter.setEncoding(this.properties.getCharset().name());
        filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
        filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
        return filter;
    }

1.我们可以看到这个类有@Configuration注解,说明这是一个配置类,给容器中添加组件。

2.@EnableConfigurationProperties({HttpEncodingProperties.class})的作用是,启用HttpEncodingProperties.class类的配置属性功能,将HttpEncodingProperties对象映射到private final HttpEncodingProperties properties中。点进去这个类:

@ConfigurationProperties(
    prefix = "spring.http.encoding"
)
public class HttpEncodingProperties {
    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
    private Charset charset;
    private Boolean force;
    private Boolean forceRequest;
    private Boolean forceResponse;
    private Map<Locale, Charset> mapping;

这个类上面有@ConfigurationProperties(prefix = "spring.http.encoding" )注解,这个是关键,这也就是为什么在配置文件中写某些属性,例如spring.http.encoding=utf-8,就可以将编码变成utf-8,因为这个类从配置文件中获取映射值之后,便将对象注入到了容器中。

所有的配置文件中能配置的属性,都在xxxProperties类中封装着。配置文件能配置什么功能,可以参考某个功能对应的这个类属性。

至于上面的@ConditionalOnXXX注解,就是在满足条件后,才将组件注入到容器中,否则不注入,这里就不过多的讨论了。

三十九.关于Spring Boot自动配置的结论。

所谓的自动配置功能第一步,就是获取所有jar包类路径下的 "META-INF/spring.factories" 文件并将文件变成的properties对象,然后在获取对象中的EnableAutoConfiguration属性值作为组件注入到容器中,然后用容器中的这些组件进行自动配置。

也就是说,所有jar包类路径下的spring.factories文件中EnableAutoConfiguration的属性值(xxxProperties类)作为组件加入到了容器中。

自动配置功能第二步,就是通过配置文件来给xxxProperties类进行属性映射注入,属性注入之后便将对象注入到了容器中,然后在配置文件中配置的东西就生效了。

四十.市面上的日志框架有哪些?

市面上的日志框架主要有,JUL,JCL,Jboss-logging,logback,log4j,log4j2,slf4j....等。

四十一.什么是日志门面和日志实现?

日志门面又称为日志的抽象层,主要包括JCL(Jakarta Commons Logging),SLF4j(Simple Logging Facade for Java),jboss-loggin。

日志实现主要包括Log4j,JUL(java.util.logging),Log4j2,LogBack。

四十二.日志门面和日志实现的关系是怎样的呢?

我的理解是,日志门面和日志实现我们把它们可以看作是接口和实现类的关系。我们在使用日志的时候,只需要调用其日志门面即可。

四十三.Spring Boot使用的是哪个日志框架?

日志门面使用的是:SLF4j。

日志实现使用的是:Logback。

四十四.日志框架SLF4j的使用。

1.以后在开发的时候,日志记录方法的调用,不应该来直接调用日志的实现类,而是调用日志抽象层里的方法:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SLF4jTest {
    public static final Logger logger = LoggerFactory.getLogger(SLF4jTest.class);
    @Test
    public void startTest(){
        logger.info("info");
        logger.error("err");
        logger.warn("warn");
        logger.debug("debug");

        String name = "zhangsan";
        logger.info("name: {}", name );

        try {
            int i = 1/0;
        } catch (Exception e) {
            logger.error("calc error", e);
        }
    }
}

2.Maven配置: 

<!--slf4j 日志门面 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.30</version>
        </dependency>
        
        <!--logback -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

       <!--nop 不打印日志-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-nop</artifactId>
            <version>1.7.30</version>
        </dependency>

        <!--log4j -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.30</version>
        </dependency>

       <!--jul -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-jdk14</artifactId>
            <version>1.5.6</version>
        </dependency>

slf4j有且仅有一个日志实现框架的绑定(如果出现多个默认使用第一个依赖日志实现)。

四十五.两张图。

1.实现绑定过程:

java SpringBoot DTO属性增加自定义去除空格注解 springboot去除没用的包_jar_16

2.桥接旧的日志框架:

桥接解决的是项目中日志的遗留问题,当系统中存在之前的日志API,可以通过桥接转换到slf4j的实现:

1.先去除之前老的日志框架的依赖

2.添加SLF4J提供的桥接组件

3.为项目添加SLF4J的具体实现

 

java SpringBoot DTO属性增加自定义去除空格注解 springboot去除没用的包_spring boot_17

四十六.SLF4j日志级别。

日志级别由高到低依次为:error > warn > info > debug > trace。

可以调整日志的输出级别,日志就会输出当前级别及更高级别的日志。

SLF4j的默认级别root绑定的是info,所以默认输出的日志有info,warn,error。

四十七.SLF4j的一些功能。

1.可以自由切换使用哪个日志实现。

2.可以自定义日志输出的格式。

3.可以自定义日志输出的路径。