在这里插入图片描述

👨🏻‍🎓博主介绍:大家好,我是芝士味的椒盐,一名在校大学生,热爱分享知识,很高兴在这里认识大家🌟
🌈擅长领域:Java、大数据、运维、电子
🙏🏻如果本文章各位小伙伴们有帮助的话,🍭关注+👍🏻点赞+🗣评论+📦收藏,相应的有空了我也会回访,互助!!!
🤝另本人水平有限,旨在创作简单易懂的文章,在文章描述时如有错,恳请各位大佬指正,在此感谢!!!


SpringBoot自动装配

  • 主类使用了@SpringBootApplication,其内部的@EnableAutoConfiguration就会作用,开启自动装配

    # Initializers
    org.springframework.context.ApplicationContextInitializer=\
    org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
    org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
    
    # Application Listeners
    org.springframework.context.ApplicationListener=\
    org.springframework.boot.autoconfigure.BackgroundPreinitializer
    
    # Auto Configuration Import Listeners
    org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
    org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener
    
    # Auto Configuration Import Filters
    org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
    org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
    org.springframework.boot.autoconfigure.condition.OnClassCondition,\
    org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition
    																							......
    
  • 按需加载,只有导入了相关的依赖之后才会生效

  • 包扫描

    • 默认是扫描引导类(主类)的包所在的包及其子包下的Bean。

    • 各种配置拥有默认值

      • 默认配置最终都是映射到某个类上,如:MultipartProperties
      • 配置文件的值最终会绑定每个类上,这个类会在容器中创建对象
    • 也可以更改包扫描位置使用如下

      @SpringBootApplication(scanBasePackages = "icu.lookyousmileface.springboot_gettingstarted.controller")
      
    • 还可以不使用@SpringApplication注解,使用@ComponentScan注解,不可以和@SpringApplication注解一起用

      @SpringBootConfiguration
      @EnableAutoConfiguration
      @ComponentScan("icu.lookyousmileface.springboot_gettingstarted")
      
      • 会冲突

        @ComponentScan(
            excludeFilters = {@Filter(
            type = FilterType.CUSTOM,
            classes = {TypeExcludeFilter.class}
        ),
        

SpringBoot容器功能

  • @Configuration

    • Full模式与Lite模式

      • 配置 类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断
      • 配置类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式
      @Configuration(proxyBeanMethods = true)
      public class MyConfig {
      
          @Bean
          public Human human(){
              return new Human("松江",18,'男');
          }
      
          public Pet pet(){
              return new Pet("小黑","白色");
          }
      }
      
      public static void main(String[] args) {
              ConfigurableApplicationContext run = SpringApplication.run(SpringbootGettingstartedApplication.class);
              //查看场景启动器带来的组件
              String[] beanDefinitionNames = run.getBeanDefinitionNames();
              Arrays.stream(beanDefinitionNames).forEach(S->System.out.println(S));
              //从容器获得对象
              Human human1 = run.getBean("human",Human.class);
              Human human2 = run.getBean("human",Human.class);
              System.out.println(human1==human2);
              //icu.lookyousmileface.springboot_gettingstarted.config.MyConfig$$EnhancerBySpringCGLIB$$21ae3889@15515c51 表示被代理
              MyConfig myConfig = run.getBean(MyConfig.class);
              System.out.println(myConfig);
              //config的proxyBeanMethods = true为单实列,否则每次调用都会产生一个新的对象
              Human human = myConfig.human();
              Human human3 = myConfig.human();
              System.out.println(human3==human);
      }
      
      • config类配置代替了大量的xml配置
  • @Bean(表示对象组件)、@Component(表示组件)、@Controller(表示控制器组件)、@Service(表示业务层组件)、@Repository(标注表示数据库组件)

  • @ComponentScan(包扫描)、@Import(导入组件)

    • @Import:使用@Import导入组件,其名字为全类名如:Human,@Bean注册的注册的类为首字母小写形势human

      */
      //使用@Import导入组件,其名字为全类名如:Human,@Bean注册的注册的类为首字母小写形势human
      @Import({Human.class,Pet.class})
      @Configuration(proxyBeanMethods = true)
      public class MyConfig {
      
          @Bean
          public Human human(){
              return new Human("松江",18,'男');
          }
      
          public Pet pet(){
              return new Pet("小黑","白色");
          }
      }
      
  • @Conditional

    • 条件装配:满足Conditional指定的条件,则进行组件注入,其下由多个子类如下:

      在这里插入图片描述

    • 代码实验:

      @Configuration
      public class MyConfig {
      
          @ConditionalOnMissingBean(name = "peto1")
          @Bean
          public Human human01(){
              return new Human("宋江",46,'男');
          }
      
      //    @Bean
          public Pet Peto1(){
              return new Pet("小黄","yellow");
          }
      }
      
      • @ConditionalOnMissingBean(name = “peto1”)也就是说,如果没有"pet01"Bean这个名称的容器就创建human01,否则就将不创建Human类的对象, 可以作用在方法和类上。
  • @ImportResource(引入原生的配置文件), 例如:要倒入Spring原生bean配置文件如下

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    
        <bean id="hu01" class="icu.lookyousmileface.springboot_gettinggide.bean.Human">
            <property name="name" value="武松"></property>
            <property name="age" value="19"></property>
            <property name="sex" value="男"></property>
        </bean>
    
        <bean id="pe01" class="icu.lookyousmileface.springboot_gettinggide.bean.Pet">
            <property name="name" value="cat"></property>
            <property name="color" value="red"></property>
        </bean>
    </beans>
    
    • 就可以在配置类上加上该注解如下,bean此时在resources目录下:

      @Configuration
      @ImportResource("classpath:bean.xml")
      public class MyConfig {
      
      //    @ConditionalOnMissingBean(name = "peto1")
          @Bean
          public Human human01(){
              return new Human("宋江",46,'男');
          }
      
          @Bean
          public Pet Peto1(){
              return new Pet("小黄","yellow");
          }
      }
      
  • 配置绑定(@ConfigurationProperties+@Component标注在要绑定属性的类上)

    • application.yml(选用的是yml,选用properties遇到中文会出现乱码)

      myhuman:
        name: 宋江
        age: 89
        sex:
    • Human.java

      @Component
      prefix表示和配置文件的前缀相同的属性开始匹配,也就是上述application.yml中的myhuman
      @ConfigurationProperties(prefix = "myhuman")
      public class Human {
          private String name;
          private int age;
          private String sex;
      }
      
      • ⚠️注意配置绑定之前需要导入配置出绑定处理器,解决没有提示的问题

        <!--配置文件处理器,properties参数绑定对象-->
          <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-configuration-processor</artifactId>
          <optional>true</optional>
        </dependency>
        
      • ⚠️为了减少不必要插件编译进jar包或war包,可进行排除

        <build>
                <plugins>
                    <plugin>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-maven-plugin</artifactId>
                        <!--编译时排除不必要的类-->
                        <configuration>
                            <excludes>
                                <exclude>
                                    <groupId>org.projectlombok</groupId>
                                    <artifactId>lombok</artifactId>
                                </exclude>
                                <exclude>
                                    <groupId>org.springframework.boot</groupId>
                                    <artifactId>spring-boot-configuration-processor</artifactId>
                                </exclude>
                            </excludes>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        
  • 配置绑定(@EnableConfigurationProperties+@ConfigurationProperties)

    • application.yml

    • Human.java

      @AllArgsConstructor
      @NoArgsConstructor
      @Data
      @Accessors(chain = true)
      @EqualsAndHashCode
      //@Component
      @ConfigurationProperties(prefix = "myhuman")
      public class Human {
          private String name;
          private int age;
          private String sex;
      }
      
    • MyConfig.java

      @Configuration
      //@ImportResource("classpath:bean.xml")
      @EnableConfigurationProperties(Human.class)
      public class MyConfig {
      
      //    @ConditionalOnMissingBean(name = "peto1")
      //    @Bean
      //    public Human human01(){
      //        return new Human("宋江",46,"男");
      //    }
      
          @Bean
          public Pet Peto1(){
              return new Pet("小黄","yellow");
          }
      }
      
      • @EnableConfigurationProperties(Human.class):表示支持某个类参数绑定,也就是开启配置绑定功能,将Human这个组件注册到容器。注意不要存在其他注册该容器的情况否则报错。
  • 自动配置原理

    • @SpringBootConfiguration:@Configuration是一个配置类

    • @ComponentScan:包扫描

    • @EnableAutoConfiguration:自动装配核心

      @AutoConfigurationPackage
      @Import({AutoConfigurationImportSelector.class})
      
      1. @AutoConfigurationPackage

        @Import(AutoConfigurationPackages.Registrar.class)  //给容器中导入一个组件
        public @interface AutoConfigurationPackage {}
        
        //利用Registrar给容器中导入一系列组件
        //将指定的一个包下的所有组件导入进来?MainApplication 所在包下。
        
      2. @Import(AutoConfigurationImportSelector.class)

        1、利用getAutoConfigurationEntry(annotationMetadata);给容器中批量导入一些组件
        2、调用List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes)获取到所有需要导入到容器中的配置类
        3、利用工厂加载 Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader);得到所有的组件
        4、从META-INF/spring.factories位置来加载一个文件。
            默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件
            spring-boot-autoconfigure-2.3.4.RELEASE.jar包里面也有META-INF/spring.factories
        

        在这里插入图片描述
        在这里插入图片描述

    • 按需开启自动配置项

      虽然127个场景的所有自动配置启动的时候默认全部加载。xxxxAutoConfiguration
      按照条件装配规则(@Conditional),最终会按需配置。
      
    • 修改自动配置

      				@Bean
              @ConditionalOnBean(MultipartResolver.class)  //容器中有这个类型组件
              @ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) //容器中没有这个名字 multipartResolver 的组件
              public MultipartResolver multipartResolver(MultipartResolver resolver) {
                  //给@Bean标注的方法传入了对象参数,这个参数的值就会从容器中找。
                  //SpringMVC multipartResolver。防止有些用户配置的文件上传解析器不符合规范
                  // Detect if the user has created a MultipartResolver but named it incorrectly
                  return resolver;
              }
      给容器中加入了文件上传解析器;
      
      • SpringBoot默认会在底层配好所有的组件。但是如果用户自己配置了以用户的优先

        		@Bean
            @ConditionalOnMissingBean
            public CharacterEncodingFilter characterEncodingFilter() {
            }
        
    • 总结:

      SpringBoot先加载所有的自动配置类  xxxxxAutoConfiguration
      • 每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。xxxxProperties里面拿。xxxProperties和配置文件进行了绑定
      • 生效的配置类就会给容器中装配很多组件
      • 只要容器中有这些组件,相当于这些功能就有了
      • 定制化配置
      • 用户直接自己@Bean替换底层的组件
      • 用户去看这个组件是获取的配置文件什么值就去修改。
      xxxxxAutoConfiguration ---> 组件  ---> xxxxProperties里面拿值  ----> application.properties
      
    • 最佳实践

      • 引入场景依赖
      	• https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-starter
      • 查看自动配置了哪些(选做)
      	• 自己分析,引入场景对应的自动配置一般都生效了
      	• 配置文件中debug=true开启自动配置报告。Negative(不生效)\Positive(生效)
      • 是否需要修改
      	• 参照文档修改配置项
      		• https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html#common-application-properties
      		• 自己分析。xxxxProperties绑定了配置文件的哪些。
      	• 自定义加入或者替换组件
      		• @Bean@Component。。。
      	• 自定义器  XXXXXCustomizer;
      	• ......
      
  • 开发小技巧

    • lombok:通过注解的方式创建get/set/toString等方法,提高编写bean的效率,也可以使用Slfj日志输出。

    • devtools:跟JRebel差不多的热部署工具,只要倒入其依赖即可使用,快捷键Control+F9

      <!--springboot的热部署工具-->
      <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-devtools</artifactId>
                  <version>2.0.4.RELEASE</version>
      </dependency>
      
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐