SpringBoot自动加载原理

通过查看SpringBoot启动类来查看SpringBoot自动加载的原理:

@SpringBootApplication注解

点击这个注解

里面有这样3个注解

@SpringBootConfiguration(重要)

@EnableAutoConfiguration(重要)

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

 

@ComponentScan

其中@ComponentScan是组件扫描器注解,他会自动扫描并加载符合条件的组件或Bean,并将这个Bean加载到IoC容器中,这个注解对应Spring中xml配置文件中的元素,有了它就会有相应的Bean,和spring的xml文件中添加Bean一样

 

@SpringBootConfigration

而@SpringBootConfigration这个注解则表明这个类是一个SpringBoot配置类,点击这个注解,发现其下有一个 @Configration  说明这是一个Spring配置类,配置类就对应Spring中的xml配置文件,在配置类中可以进行相应的配置,和在spring的xml文件中进行相应的配置一样  @Configration下有一个@Component注解,表明配置类就是一个Spring中的组件,这里也说明启动类也只是Spring中的一个组件罢了,用来启动应用

 

@EnableAutoConfigration

从这个注解的名字我们就知道他与自动配置有关

他会告诉SpringBoot开启自动配置功能,这样自动配置才会生效

其下有两个重要注解

@AutoConfigrationPackage

@Import(AutoConfigrationImportSelector.class)

@AutoConfigrationPackage,点进去,有一个@Import(AutoConfigrationPackage.Registrar.class),@Import是Spring的底层注解,给IoC容器导入一个组件,Registrar.class的作用是将主启动类的所在包及其所有子包里面的所有组件扫描到Spring容器中,这也是我们的包为什么要和启动类同级的原因。这个注解就将我们自己写的所有组件扫描到了Spring容器中。

@Import(AutoConfigurationImportSelector.class),给容器导入组件,这里的组件就是那些我们原本需要配置的组件了。AutoConfigurationImportSelector类中有一个getCondidateConfigrations(),这个方法用于获取所有候选的配置

SpringBoot自动加载原理_第1张图片

这个方法又调用了SpringFactoriesLoader的静态方法loadFactoryNames,loadFactoryNames方法的一个参数是getSpringFactoriesLoaderFactoryClass()方法,这个方法是

SpringBoot自动加载原理_第2张图片

可以看到它返回的是EnableAutoConfiguration.class,也就是说这个方法返回的是标注了这个注解的所有包,而启动类就被这个注解标注,在loadSpringFactories方法中启动类又被返回。所以说他做这一圈操作,就是为了将启动类所需的所有资源导入。

现在回到loadFactoryNames方法,loadFactoryNames方法调用了SpringFactoriesLoader类中的静态方法loadSpringFactories,loadSpringFactories方法又调用了spring.factoires文件

SpringBoot自动加载原理_第3张图片

    这个文件中有很多自动配置的文件,他们的命名形式为xxxxAutoConfigration,我们熟悉的WebMvcAutoConfiguration,HttpEncodingAutoConfiguration等等都在其中。

 

SpringBoot自动加载原理_第4张图片

每一个xxxxAntoConfgiration里有一些

1.@ConditionOnxxxx(),和一些组件(用@Bean修饰的类或方法),组件上也有@ConditionOnxxxx(),@ConditionOnxxxx的意思是当所有条件满足时,他标注的类或者组件才会生效

2.@EnableConfigurationProperties(xxxxProperties.class),意思是与xxxxProperties类绑定,当组件生效时从这个类中获取对应的属性, xxxxProperties类中有我们所有可以配置的属性,@ConfigurationProperties(prefix = "xxxx",) public class xxxxProperties {可以配置的属性},当我们在我们的配置文件中加上对应的prefix时,我们就可以配置这个properties类中的属性了。

这就是为什么我们在我们的yml文件中配置相应的属性就可以生效的原因

 

以HttpEncodingAutoConfiguration为例:

//表明这是一个配置类,和以前的配置类一样,可以向容器中添加组件
@Configuration(proxyBeanMethods = false)
//与ServerProperties类绑定,从这个类中获取对应的属性
@EnableConfigurationProperties(ServerProperties.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass(CharacterEncodingFilter.class)
@ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {

   private final Encoding properties;

   public HttpEncodingAutoConfiguration(ServerProperties properties) {
      this.properties = properties.getServlet().getEncoding();
   }

   @Bean
   @ConditionalOnMissingBean
   public CharacterEncodingFilter characterEncodingFilter() {
      ...
   }

   ...
      }}}

它对应的properties为ServerProperties.java,当HttpEncodingAutoConfiguration中的组件生效时,组件会从ServerProperties类中获取相应的属性

@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {...}
这个类和我们的配置文件绑定,其中有一些属性,prefix就是我们配置时需要使用的前缀,使用这个前缀我们就可以在我们的配置文件中进行相应的配置了,例如:server.port=8080

 所以自动配置的大概过程就是

SpringBoot自动加载原理_第5张图片

当@ConditionOnxxxx()条件不成立的时候,该自动配置类就不会生效。在通过spring.factories获取配置类位置之后就不会加载这个自动配置类,如果条件成立,就加载这个自动配置类到Ioc容器中,这样自动配置类就生效了,我们就不需要再配置了。一旦这个自动配置类生效,就会向容器中添加各种组件,这些组件的属性是从对应的properties类中获取的(通过@EnableConfigurationProperties(xxxxProperties.class)绑定)。

 

如果自动配置类中没有我们需要的属性怎么办?

自定义一个类,用@ConfigurationProperties(prefix="")和@Component来修饰它

例如:

@Component

@ConfigurationProperties(prefix="hhh")

public class   hhhconfig(){

     private String hhhName;

     private int age;

     对应的set,get方法

}

在我们的yml文件中添加
 

hhh

      hhhname:testhhh

      age:3333
@SpringBootTest
class SpringbootdemoApplicationTests {
    @Autowired
    TestConfig hhhconfig;
    @Test
    void contextLoads() {
        System.out.println(hhhconfig.getHhhName());
        System.out.println(hhhconfig.getAge());
    }

}

会输出我们配置的结果,所以想要配置自动配置类中不存在的属性,就自己写一个properties类就可以了。

 

感觉写博客确实对理解知识很有帮助,当你能讲一个知识点讲出来的时候说明你已经理解得很透彻了,花1个小时写博客确实比自己看1个小时知识点理解的更快。

从今天起要多写博客。

顺便吐槽下,CSDN这个编辑器是真的烂。
 

你可能感兴趣的:(spring,boot,java)