【Spring Boot】(二)Spring Boot 进阶

本文介绍如何使用IDEA快速构建SpringBoot项目,包括创建项目、配置文件解析及自动配置原理。涵盖IDEA项目搭建步骤、配置文件详解、自动配置机制分析等内容。

使用IDEA快速构建项目

在上一篇博客中,使用了Spring官网来快速构建了一个Spring Boot,事实上,用IDEA也可以做到,步骤如下:
之前,我们在官网上直接快速构建了一个springboot项目,IDEA也可以做到,我们来看下具体步骤:

  1. 创建一个新项目,如图所示:
    在这里插入图片描述

  2. 在左边的框中选择Spring initalizr ,可以看到默认就是去官网的快速构建工具那里实现,如图所示:
    在这里插入图片描述

  3. 和之前一样填写项目信息,如图所示:
    在这里插入图片描述

  4. 选择初始化的组件,这里选择了Web组件中的Spring Web Starter,如图所示:
    在这里插入图片描述

  5. 填写项目路径,如图所示:
    在这里插入图片描述

  6. 等待项目构建成功,如图所示:
    在这里插入图片描述

控制器测试

  1. 我们在SpringBootApplication的同路径下建一个包 controller,在该包中建立一个类HelloSpringBoot,(注意:controller包一定要放在启动类的外面,启动类包下的里面,不然会提示404错误!以启动类的包路径作为顶层包路径,例如启动类包为com.example.demo,那么Controller包路径就为com.example.demo.controller)如图所示:
    在这里插入图片描述
  2. 在该类中编写代码,代码如下:
@RestController
//补充说明:@RestController 的意思就是 Controller 里面的方法都以 json 格式输出,不用再写什么 jackjson 配置的了!
public class HelloSpringBoot {

    @RequestMapping("/hello")
    public String index(){
        return "Hello,SpringBoot!";
   	 }
}
  • 启动主程序,打开浏览器访问 http://localhost:8080/hello ,就可以看到效果,如图所示:
    在这里插入图片描述

  • 总结:在之后的学习中,直接使用IDEA创建项目即可,方便快捷!

    Spring Boot的配置文件

    配置文件

    SpringBoot使用一个全局的配置文件,配置文件名称是固定的

    • application.properties
      语法结构 : key=value
    • application.yml
      语法结构 :key:空格value

    配置文件的作用 :修改SpringBoot自动配置的默认值,因为SpringBoot在底层都给我们自动配置好了;

    要学习配置文件,就需要先了解YAML,关于YAML的博客地址在此:
    https://blog.youkuaiyun.com/qq_41151659/article/category/9212710

    注入配置文件

    1. 如果要使用properties配置文件可能导入时存在乱码现象,需要在IDEA中进行调整,为了省事,我们这里直接使用yml文件,将默认的application.properties后缀修改为yml,如图所示:
      在这里插入图片描述
    2. 在pom.xml中导入配置文件处理器的依赖,不然会报错,代码如下:
    <!--导入配置文件处理器,配置文件进行绑定就会有提示-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
    </dependency>
    
  • 在刚刚新建的application.yml文件中编写配置文件,代码如下:
  • person:
      name: abc
      age: 3
      happy: false
      birth: 2000/01/01
      maps: {k1: v1,k2: v2}
      lists: [code,music,movie]
      dog:
        name: 旺财
        age: 1
    
    1. 在Spring Boot的主程序的同级目录下建一个pojo包,只有这样,主程序才会对这些类失效,在该包中我们建两个实体类:Person类、Dog类,记得写上 toString()方法,方便调试输出结果,代码如下:
      在这里插入图片描述

    Person类代码如下:

    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.stereotype.Component;
    
    import java.util.Date;
    import java.util.List;
    import java.util.Map;
    
    @Component
    @ConfigurationProperties(prefix = "person")
    public class Person {
    
    private String name;
    private Integer age;
    private Boolean happy;
    private Date birth;
    private Map<String,Object> maps;
    private List<Object> lists;
    private Dog dog;
    
    public Person() {
    }
    
    public Person(String name, Integer age, Boolean happy, Date birth, Map<String, Object> maps, List<Object> lists, Dog dog) {
        this.name = name;
        this.age = age;
        this.happy = happy;
        this.birth = birth;
        this.maps = maps;
        this.lists = lists;
        this.dog = dog;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public Integer getAge() {
        return age;
    }
    
    public void setAge(Integer age) {
        this.age = age;
    }
    
    public Boolean getHappy() {
        return happy;
    }
    
    public void setHappy(Boolean happy) {
        this.happy = happy;
    }
    
    public Date getBirth() {
        return birth;
    }
    
    public void setBirth(Date birth) {
        this.birth = birth;
    }
    
    public Map<String, Object> getMaps() {
        return maps;
    }
    
    public void setMaps(Map<String, Object> maps) {
        this.maps = maps;
    }
    
    public List<Object> getLists() {
        return lists;
    }
    
    public void setLists(List<Object> lists) {
        this.lists = lists;
    }
    
    public Dog getDog() {
        return dog;
    }
    
    public void setDog(Dog dog) {
        this.dog = dog;
    }
    
    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", happy=" + happy +
                ", birth=" + birth +
                ", maps=" + maps +
                ", lists=" + lists +
                ", dog=" + dog +
                '}';
    }
    }
    
    

    Dog类代码如下:

    public class Dog {
    
    private String name;
    private Integer age;
    
    public Dog() {
    }
    
    public Dog(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public Integer getAge() {
        return age;
    }
    
    public void setAge(Integer age) {
        this.age = age;
    }
    
    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    }
    
    
    

    确认无误后,到测试单元中编写测试类,看是否注入成功,代码如下:

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class SpringbootDemo03ApplicationTests {
    
        @Autowired
        Person person = new Person();
    
        @Test
        public void contextLoads() {
            System.out.println(person);
        }
    
    }
    
    1. 运行,结果如下:
      在这里插入图片描述

    其他实现方式

    上面提到的方式是最简单的方式,开发中相当常用。
    事实上,还存在有其他的实现方式。
    配置文件除了yml,还有我们之前常用的properties。没有最先提到的原因是:properties配置文件在写中文的时候,会有乱码 ,需要去IDEA中设置编码格式为UTF-8; 如图所示:
    在这里插入图片描述
    在settings–>FileEncodings 中配置;

    在这里插入图片描述

    还有,我们的类和配置文件直接关联着 , 我们使用的是@configurationProperties的方式,还有一种方式是使用@value,代码如下:

    //怎么把配置配资文件的值绑定到我们的对象中;
    //将配置文件中配置的每一个属性的值,映射到这个组件中;
    //prefix : 在配置文件中的一个对象;
    
    //@Validated //可以支持JSR303数据校验
    
    @Component //被容器托管
    @PropertySource(value = "classpath:person.properties") //加载指定的配置文件 classpath:项目类路径
    //@ConfigurationProperties(prefix = "person") :默认加载全局的配置文件
    public class Person {
    
        //@Value("${person.name}")
        //数据验证 : 前端;数据合法,才传递到后台
        //@Email(message="必须是邮箱")
        //properties单一的取值 :
        @Value("${person.name}") //从配置文件中取值
        private String lastName;
        @Value("#{11*2}")  //#{SPEL} Spring表达式
        private Integer age;
        @Value("true")  // 字面量
        private Boolean happy;
    
        private Date birth;
        private Map<String,Object> maps;
        private List<Object> hobbys;
    
        private Dog dog;
    
        public Person() {
        }
    
        public String getLastName() {
            return lastName;
        }
    
        public void setLastName(String lastName) {
            this.lastName = lastName;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        public Boolean getHappy() {
            return happy;
        }
    
        public void setHappy(Boolean happy) {
            this.happy = happy;
        }
    
        public Date getBirth() {
            return birth;
        }
    
        public void setBirth(Date birth) {
            this.birth = birth;
        }
    
        public Map<String, Object> getMaps() {
            return maps;
        }
    
        public void setMaps(Map<String, Object> maps) {
            this.maps = maps;
        }
    
        public List<Object> getHobbys() {
            return hobbys;
        }
    
        public void setHobbys(List<Object> hobbys) {
            this.hobbys = hobbys;
        }
    
        public Dog getDog() {
            return dog;
        }
    
        public void setDog(Dog dog) {
            this.dog = dog;
        }
    
        @Override
        public String toString() {
            return "Person{" +
                    "name='" + lastName + '\'' +
                    ", age=" + age +
                    ", happy=" + happy +
                    ", birth=" + birth +
                    ", maps=" + maps +
                    ", hobbys=" + hobbys +
                    ", dog=" + dog +
                    '}';
        }
    }
    
    

    结果如图所示:
    在这里插入图片描述
    事实上,这个使用起来并不友好!因为需要为每个属性单独注解赋值,比较麻烦;我们可以看个功能对比图:
    在这里插入图片描述

    • cp只需要写一次即可 , value则需要每个字段都添加
    • 松散绑定:这个什么意思呢? 比如我的yml中写的last-name,这个和lastName是一样的, - 后面跟着的字母默认是大写的。这就是松散绑定
    • JSR303数据校验 , 这个就是我们可以在字段是增加一层过滤器验证 , 可以保证数据的合法性
    • 复杂类型封装,yml中可以封装对象 , 使用@value就不支持

    总结

    • 配置yml和配置properties都可以获取到值 , 强烈推荐 yml
    • 如果我们在某个业务中,只需要获取配置文件中的某个值,可以使用一下 @value
    • 如果说,我们专门编写了一个JavaBean来和配置文件进行映射,就直接使用@configurationProperties,不要犹豫!

    JSR303数据校验

    spring-boot中可以用@validated来校验数据,如果数据异常则会统一抛出异常,方便异常中心统一处理。在这里,来写个注解让我们的name只能支持Email格式,代码如下:

    @Component //注册bean
    @ConfigurationProperties(prefix = "person")
    @Validated  //数据校验
    public class Person {
    
        //@Value("${person.name}")
        @Email //name必须是邮箱格式
        private String name;
    }
    

    运行结果如图所示:
    在这里插入图片描述
    总结:使用数据校验,可以保证数据的正确性;

    加载指定配置文件

    @PropertySource:加载指定的配置文件;使用@configurationProperties默认从全局配置文件中获取值

    1. 在 resources目录下新建一个person.properties文件
    name=kuangshen
    
    1. 在实体类中指定加载person.properties文件,代码如下:
    @PropertySource(value = "classpath:person.properties")
    @Component //注册bean
    public class Person {
    
        @Value("${name}")
        private String name;
    
        ......  
    }
    
  • 运行程序,结果如下:
    在这里插入图片描述
  • 配置文件占位符

    设定随机数的语法如下:

    ${random.value}、${random.int}、${random.long}、${random.int(10)}
    

    占位符引用其他属性的值,如果不存在可以设置默认值,编写yml配置文件,代码如下:

    person:
        name: qinjiang${random.uuid}
        age: ${random.int}
        happy: false
        birth: 2000/01/01
        maps: {k1: v1,k2: v2}
        lists:
          - code
          - girl
          - music
        dog:
          name: ${person.hello:hello}_旺财
          age: 1
    

    多环境切换

    profile是Spring对不同环境提供不同配置功能的支持,可以通过激活不同的环境版本,实现快速切换环境;
    切换多种环境,拥有两种方式:
    方式一:多配置文件
    我们在主配置文件编写的时候,文件名必须application-{profile}.properties/yml , 用来指定多个环境版本;

    例如:application-test.properties,代表测试环境配置;application-dev.properties,代表开发环境配置

    但是Springboot并不会直接启动这些配置文件,它默认使用application.properties主配置文件;

    我们需要通过一个配置来选择需要激活的环境,配置如下:

    #比如在配置文件中指定使用dev环境,我们可以通过设置不同的端口号进行测试;
    #我们启动SpringBoot,就可以看到已经切换到dev下的配置了;
    spring.profiles.active=dev
    

    方式二:yml的多文档块
    和properties配置文件中类似,但是使用yml去实现不需要创建多个配置文件,更加方便了,配置如下:

    server:
      port: 8081
    #选择要激活那个环境块
    spring:
      profiles:
        active: prod
    
    ---
    server:
      port: 8083
    #配置环境的名称
    spring:
      profiles: dev
    
    
    ---
    
    server:
      port: 8084
    spring:
      profiles: prod  #配置环境的名称
    
    

    注意:如果yml和properties同时都配置了端口,并且没有激活其他环境 , 默认会使用properties配置文件!

    配置文件加载位置

    根据官方文档,springboot启动会扫描以下位置的application.properties或者application.yml文件作为Spring Boot的默认配置文件,说明如下:

    • 优先级1:项目路径下的config文件夹配置文件
    • 优先级2:项目路径下配置文件
    • 优先级3:资源路径下的config文件夹配置文件
    • 优先级4:资源路径下配置文件

    优先级由高到低,高优先级的配置会覆盖低优先级的配置;

    SpringBoot会从这四个位置全部加载主配置文件;互补配置;

    我们在最低级的配置文件中设置一个项目访问路径的配置来测试互补问题;

    #配置项目的访问路径
    server.servlet.context-path=/kuang
    

    【拓展:指定位置加载配置文件】

    事实上,我们还可以通过spring.config.location来改变默认的配置文件位置

    项目打包好以后,我们可以使用命令行参数的形式,启动项目的时候来指定配置文件的新位置;

    这种情况,一般是后期运维做的多,相同配置,外部指定的配置文件优先级最高

    java -jar spring-boot-config.jar --spring.config.location=F:/application.properties
    

    总结:外部加载配置文件的方式十分多,我们选择最常用的即可,在开发的资源文件中进行配置!

    Spring Boot的自动配置原理

    分析自动配置原理

    1. SpringBoot启动的时候加载主配置类,开启了自动配置功能 @EnableAutoConfiguration
    2. @EnableAutoConfiguration 作用:
      1. 利用EnableAutoConfigurationImportSelector给容器中导入一些组件,导入了哪些组件呢?
      2. 可以查看这个类selectImports()方法的内容,他返回了一个 autoConfigurationEntry , 来自 this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata); 这个方法。我们继续跟踪;
      3. 这个方法中有一个值 : List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes); 叫做获取候选的配置 , 我们点击去继续跟踪;
      4. 找到一段关键代码,代码如下:
      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() ,我们继续进去看 , 它又调用了 loadSpringFactories 方法;继续跟踪。发现它去获得了一个资源文件:“META-INF/spring.factories”

    1. 继续阅读源码,代码如下:
    Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
    

    它将读取到的资源封装在url中,然后遍历url , 将这些url文件封装在Properties文件中;最后返回封装好的结果;他的那个ClassLoader参数,我们追踪回去,看到他就是 EnableAutoConfiguration

    在这里插入图片描述

    1. 说明了这个逻辑就是 从properties中获取到EnableAutoConfiguration.class类(类名)对应的值,然后把他们添加在容器中
    2. 总结一句话就是:将类路径下 META-INF/spring.factories 里面配置的所有EnableAutoConfiguration的值加入到了容器中;我们从源码中拿过来,代码如下:
    # Auto Configure
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    org.springframework.boot.autoconfigure.admin.SpringApplicationAdmi	nJmxAutoConfiguration,\
    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.CloudServiceConnectorsAutoConfiguration,\
    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.CassandraReactiveDataAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\
    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.jdbc.JdbcRepositoriesAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\
    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.RedisReactiveAutoConfiguration,\
    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.elasticsearch.rest.RestClientAutoConfiguration,\
    org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
    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.http.HttpMessageConvertersAutoConfiguration,\
    org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,\
    org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,\
    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.groovy.template.GroovyTemplateAutoConfiguration,\
    org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\
    org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
    org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\
    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.mongo.embedded.EmbeddedMongoAutoConfiguration,\
    org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
    org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\
    org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
    org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
    org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\
    org.springframework.boot.autoconfigure.reactor.core.ReactorCoreAutoConfiguration,\
    org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
    org.springframework.boot.autoconfigure.security.servlet.SecurityRequestMatcherProviderAutoConfiguration,\
    org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\
    org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\
    org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\
    org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\
    org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
    org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
    org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\
    org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,\
    org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration,\
    org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration,\
    org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
    org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration,\
    org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration,\
    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.client.RestTemplateAutoConfiguration,\
    org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\
    org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\
    org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\
    org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\
    org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\
    org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration,\
    org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\
    org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
    org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
    org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\
    org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
    org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\
    org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
    org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\
    org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\
    org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\
    org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,\
    org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration
    

    每一个这样的 xxxAutoConfiguration类都是容器中的一个组件,最后都加入到容器中;用他们来做自动配置;

  • 每一个自动配置类可以进行自动配置功能;
  • 我们以 HttpEncodingAutoConfiguration(Http编码自动配置)为例解释自动配置原理,代码如下;
  • @Configuration //表示这是一个配置类,以前编写的配置文件一样,也可以给容器中添加组件
    //启动指定类的ConfigurationProperties功能;
    //进入这个HttpProperties查看,将配置文件中对应的值和HttpProperties绑定起来;
    //并把HttpProperties加入到ioc容器中
    @EnableConfigurationProperties({HttpProperties.class}) 
    
    //Spring底层@Conditional注解
    //根据不同的条件判断,如果满足指定的条件,整个配置类里面的配置就会生效;
    //这里的意思就是判断当前应用是否是web应用,如果是,当前配置类生效
    @ConditionalOnWebApplication(
        type = Type.SERVLET
    )
    
    //判断当前项目有没有这个类CharacterEncodingFilter;SpringMVC中进行乱码解决的过滤器;
    @ConditionalOnClass({CharacterEncodingFilter.class})
    
    //判断配置文件中是否存在某个配置:spring.http.encoding.enabled;
    //如果不存在,判断也是成立的
    //即使我们配置文件中不配置pring.http.encoding.enabled=true,也是默认生效的;
    @ConditionalOnProperty(
        prefix = "spring.http.encoding",
        value = {"enabled"},
        matchIfMissing = true
    )
    
    public class HttpEncodingAutoConfiguration {
    
        //他已经和SpringBoot的配置文件映射了
        private final Encoding properties;
    
        //只有一个有参构造器的情况下,参数的值就会从容器中拿
        public HttpEncodingAutoConfiguration(HttpProperties properties) {
            this.properties = properties.getEncoding();
        }
    
        //给容器中添加一个组件,这个组件的某些值需要从properties中获取
        @Bean
        @ConditionalOnMissingBean //判断容器没有这个组件?
        public CharacterEncodingFilter characterEncodingFilter() {
            CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
            filter.setEncoding(this.properties.getCharset().name());
            filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.REQUEST));
            filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.RESPONSE));
            return filter;
        }
        ......
    }    
    
    

    总结 : 根据当前不同的条件判断,决定这个配置类是否生效!
    一但这个配置类生效;这个配置类就会给容器中添加各种组件;这些组件的属性是从对应的properties类中获取的,这些类里面的每一个属性又是和配置文件绑定的;

    1. 所有在配置文件中能配置的属性都是在xxxxProperties类中封装者‘;配置文件能配置什么就可以参照某个功能对应的这个属性类,代码如下:

    @ConfigurationProperties(
    prefix = "spring.http"
    ) //从配置文件中获取指定的值和bean的属性进行绑定
    public class HttpProperties {
    private boolean logRequestDetails;
    private final HttpProperties.Encoding encoding = new HttpProperties.Encoding();
    
    public HttpProperties() {
    }
    
    public boolean isLogRequestDetails() {
        return this.logRequestDetails;
    }
    
    public void setLogRequestDetails(boolean logRequestDetails) {
        this.logRequestDetails = logRequestDetails;
    }
    
    public HttpProperties.Encoding getEncoding() {
        return this.encoding;
    }
    
    public static class Encoding {
        public static final Charset DEFAULT_CHARSET;
        private Charset charset;
        private Boolean force;
        private Boolean forceRequest;
        private Boolean forceResponse;
        private Map<Locale, Charset> mapping;
        
        ......
    }
    }
    
  • 去配置文件里尝试调出前缀,可以发现已经实现了自动装配,如图所示:
    在这里插入图片描述
    精髓

    1. SpringBoot启动会加载大量的自动配置类

    2. 我们看我们需要的功能有没有在SpringBoot默认写好的自动配置类当中;

    3. 我们再来看这个自动配置类中到底配置了哪些组件;(只要我们要用的组件存在在其中,我们就不需要再手动配置了)

    4. 给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们只需要在配置文件中指定这些属性的值即可;

    xxxxAutoConfigurartion自动配置类;给容器中添加组件

    xxxxProperties封装配置文件中相关属性

  • @Conditional

    了解完自动装配的原理后,我们来关注一个细节问题 ,自动配置类必须在一定的条件下才能生效;

    @Conditional派生注解(Spring注解版原生的@Conditional作用)

    作用:必须是@Conditional指定的条件成立,才给容器中添加组件,配置配里面的所有内容才生效,如图所示;
    在这里插入图片描述
    那么多的自动配置类,必须在一定的条件下才能生效;也就是说,我们加载了这么多的配置类,但不是所有的都生效了

    我们怎么知道哪些自动配置类生效;我们可以通过启用 debug=true属性;来让控制台打印自动配置报告,这样我们就可以很方便的知道哪些自动配置类生效;代码如下:

    #开启springboot的调试类
    debug=true
    

    在日志中,相关的属性如下:

    • Positive matches:(自动配置类启用的:正匹配)

    • Negative matches:(没有启动,没有匹配成功的自动配置类:负匹配)

    • Unconditional classes: (没有条件的类)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值