springboot自动配置原理

381 阅读3分钟

springboot自动配置原理

自动配置:

pom.xml

  • spring-boot-dependencies  核心依赖在父工程中
    
  • 我们在写或者引入一些springboot依赖时,不需要指定版本,就因为有这些版本仓库

starter

  • 就是springboot的启动场景
  • 比如spring-boot-starter-web,他就会帮我们自动导入web环境所有的依赖
  • springboot会将所有的场景都变成一个个的启动器
  • 我们要使用什么功能,引入相应的启动器就可以了

主程序

  • @SpringBootApplication 标注是一个springboot的应用 
    
  • @SpringBootConfiguration   springboot的配置
        @Configuration   spring的配置类
           @Component   说明这也是一个spring的组件
    @EnableAutoConfiguration   开启自动配置
        @AutoConfigurationPackage  自动配置包
           @Import(AutoConfigurationPackages.Registrar.class)  导入选择器
        @Import(AutoConfigurationImportSelector.class)   导入选择器
           List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); 获取所有的配置
    
  • //获取所有的配置
    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
       List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
             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;
    }
    
    protected Class<?> getSpringFactoriesLoaderFactoryClass() {
    		return EnableAutoConfiguration.class;
    	}
    
  • META-INF/spring.factories  自动配置的核心文件
    

1.png 这个文件里放的全是自动配置类的名称,主程序启动时就通过注解将这些自动类配置类全部加载,有了这些配置类,就省去我们写配置文件

  • 为什么加载了很多自动配置类  一些生效了,一些没生效,以springmvc的自动配置类来示例:
    下面这个是springmvc的自动配置类
    @Configuration 表示这是一个配置类
    @ConditionalOnClass  这个判断条件成立才会加载这个配置类,也就是说Servlet,DispatcherServlet存在才生效,我们建项目时导入mvc包那么这个配置类才生效
    @ConditionalOnWebApplicatio  当前是个web程序时才生效
    其他的配置类类似 都是在配置类上通过注解判断是否生效
    
    @Configuration(proxyBeanMethods = false)
    @ConditionalOnWebApplication(type = Type.SERVLET)
    @ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })       
    @ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
    @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
    @AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
          ValidationAutoConfiguration.class })
    public class WebMvcAutoConfiguration {
    
       public static final String DEFAULT_PREFIX = "";
    
       public static final String DEFAULT_SUFFIX = "";
    
       private static final String[] SERVLET_LOCATIONS = { "/" };
    
       @Bean
       @ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
       @ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled", matchIfMissing = false)
       public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
          return new OrderedHiddenHttpMethodFilter();
       }
    
  • springboot中redis的配置文件如下
    
    spring.redis.host=127.0.0.1
    spring.redis.port=6379
    

我们可以通过@ConfigurationProperties 将它们注入到一个类中去,也可以用@value单个绑定,配置文件方式写更便捷,类过于麻烦,那这个配置文件中能写那些东西呢?

这是redis的自动配置类

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RedisOperations.class)          
@EnableConfigurationProperties(RedisProperties.class)   自动配置属性,以RedisProperties类为准
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {

   @Bean
   @ConditionalOnMissingBean(name = "redisTemplate")
   public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
         throws UnknownHostException {
      RedisTemplate<Object, Object> template = new RedisTemplate<>();
      template.setConnectionFactory(redisConnectionFactory);
      return template;
   }
这是RedisProperties类
可以看到@ConfigurationProperties,说明将配置文件的值注入进来,也可以看到前缀spring.redis 和redis的配置文件的一摸一样,如配置主机配置文件就可以写spring.redis.host="localhost",下面这个类host属性有个默认的值localhost,所以我们不在配置文件中配置redis的连接地址,你也能连上以本地的redis,所以你在配置文件里配置了springboot就用你的,你没配置就用配置类默认的,同理我们再配置其他属性时,都可以参考响应的配置类编写配置文件

@ConfigurationProperties(prefix = "spring.redis")
public class RedisProperties {

   /**
    * Database index used by the connection factory.
    */
   private int database = 0;

   /**
    * Connection URL. Overrides host, port, and password. User is ignored. Example:
    * redis://user:password@example.com:6379
    */
   private String url;

   /**
    * Redis server host.
    */
   private String host = "localhost";

总结:springboot自动配置可以理解为,springboot的主程序在运行时,通过@EnableAutoConfiguration开启自动配置,首先会去扫描META-INF/spring.factories下所有的自动配置类,有了这些配置类就省去我们写配置文件,通过@ConditionalXXX判断这些配置类是否应该生效,只要导入了对应的starter,自动配置就会生效,通过相对应配置类上的@EnableConfigurationProperties,加载相关配置属性,若配置文件中有的就用配置文件的,没有的就用默认提供的,这就是springboot的自动配置原理。