springboot原理源代码图解剖析

1 springboot官方文档网址

https://docs.spring.io/spring-boot/docs/1.5.8.RELEASE/reference/htmlsingle/

2 POM文件

2.1 版本依赖的管理(版本仲裁中心)

parent导入
在这里插入图片描述
parent的父项目
在这里插入图片描述
dependencies项目管理依赖
在这里插入图片描述

2.2 依赖的导入(以web模块为例)

pom.xml
在这里插入图片描述
spring-boot-starter:场景启动器,帮我们导入了模块的相关依赖
在这里插入图片描述

3 自动配置

3.1 启动类

@SpringBootApplication
public class SpringBootTestApplication {

   public static void main(String[] args) {
      SpringApplication.run(SpringBootTestApplication.class, args);
   }
}

3.2 @SpringBootApplication注解

此注解标注在类上表明此类是SpringBoot的主配置类,SpringBoot应用就应该运行此类的main方法启动应用

@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 {}

3.3 @SpringBootConfiguration注解

标注在类上,表明此类是SpringBoot的配置类,此注解也是一个组合注解,靠的是@Configuration起作用,此注解是Spring的底层注解,标明这是一个配置类

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration 
public @interface SpringBootConfiguration {
}

其实@Configuration就是容器中的一个组件

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
    String value() default "";
}

3.4 @EnableAutoConfiguration 注解

开启自动配置

@AutoConfigurationPackage
@Import({EnableAutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {}

3.4.1 @AutoConfigurationPackage注解

此注解将主配置类(@SpringBootApplication标注的类)所在包同级目录及所有子包里面所有的组件扫描到Spring容器中

@Import({Registrar.class})
public @interface AutoConfigurationPackage {

@Import注解,给容器中导入一个组件

Registrar类

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
    Registrar() {
    }

    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        AutoConfigurationPackages.register(registry, new String[]{(new AutoConfigurationPackages.PackageImport(metadata)).getPackageName()});
    }

    public Set<Object> determineImports(AnnotationMetadata metadata) {
        return Collections.singleton(new AutoConfigurationPackages.PackageImport(metadata));
    }
}

拿到包名:
new AutoConfigurationPackages.PackageImport(metadata)).getPackageName()

在这里插入图片描述

3.4.2 @Import({EnableAutoConfigurationImportSelector.class})注解

给容器中导入选择器(EnableAutoConfigurationImportSelector)组件
选择器将所有需要的组件以全类名的方式返回,这些组件会被添加到容器中
在这里插入图片描述
在这里插入图片描述
给容器中导入自动配置类(xxxAutoConfiguration),这些配置类会给容器中导入这个场景所需要的组件,并为之配置好

配置类在哪来的?

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    List 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;
}

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

protected ClassLoader getBeanClassLoader() {
    return this.beanClassLoader; //类加载器
}

loadFactoryNames方法

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

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

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

        return result;
    } catch (IOException var8) {
        throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + "META-INF/spring.factories" + "]", var8);
    }
}

在这里插入图片描述
此方法从类路径下META-INF/spring.factories中获取EnableAutoConfiguration指定的值,将这些值作为自动配置类导入到容器中,使其自动配置生效
所有的配置都在spring-boot-autoconfigure-1.5.8.RELEASE.jar包中

4 自动配置原理

4.1 yml配置文件可配属性

参照网址
https://docs.spring.io/spring-boot/docs/1.5.8.RELEASE/reference/htmlsingle/#common-application-properties

4.2 原理

1.SpringBoot启动加载主配置类,开启了自动配置功能@EnableAutoConfiguration
2.@EnableAutoConfiguration

  • 使用EnableAutoConfigurationImportSelector给容器中导入组件
  • selectImports方法起作用
  • loadFactoryNames方法加载配置文件
    扫描所有jar包类路径下META-INF/spring.factories配置文件,封装成properties对 象,并从中获取EnableAutoConfiguration.class类名对应的属性值(即每一个自动配 置类的全路径名称),把他们添加到容器中

3.以HttpEncodingAutoConfiguration为例解释自动配置

@Configuration 
@EnableConfigurationProperties({HttpEncodingProperties.class})
@ConditionalOnWebApplication
@ConditionalOnClass({CharacterEncodingFilter.class})
@ConditionalOnProperty(
    prefix = "spring.http.encoding",
    value = {"enabled"},
    matchIfMissing = true
)
public class HttpEncodingAutoConfiguration {
}
  • @Configuration:表明是配置类,给容器中添加组件
  • EnableConfigurationProperties:启用指定类的ConfigurationProperties功能
@ConfigurationProperties(prefix = "spring.http.encoding") 
//从配置文件中获取指定前缀的属性值和bean中对应的值进行绑定,配置文件中写什么配置可参考xxxProperties配置文件
public class HttpEncodingProperties {
}
  • @ConditionalOnWebApplication
@Conditional({OnWebApplicationCondition.class}) //这是Spring注解
public @interface ConditionalOnWebApplication {
}
此注解根据不同的条件,若满足此条件,此注解的bean配置才会生效
这个注解作用是判断当前应用是否是web应用
  • @ConditionalOnClass:判断当前项目有没有这个类
    CharacterEncodingFilter是SpringMVC中解决乱码的过滤器
  • @ConditionalOnProperty:判断配置文件中是否存在某个配置
    配置名称为prefix+value=spring.http.encoding.enabled
    matchIfMissing=即使不存在此配置,默认此配置也是生效的

4.3 总结

  • SpringBoot启动会加载大量的自动配置类
  • 我们需要的功能SpringBoot有没有帮我们配置好
  • 看自动配置类中配置了哪些组件,只要组件有,就不需要我们再配置了
  • 给容器中的自动配置类添加组件的时候,会从对应的properties对象中获取属性,我们在配置文件中配置这些属性即可
  • 记住两个重要的约定吧:
    – xxxAutoConfiguration:自动配置类注解,将配置添加到Spring容器中
    – xxxProperties:配置类对应的属性封装类

5 SpringMVC的自动配置

5.1 官方文档中有这样一段话

在这里插入图片描述

5.2 定制视图解析器

@SpringBootApplication
public class SpringBootTestApplication {

   public static void main(String[] args) {
      SpringApplication.run(SpringBootTestApplication.class, args);
   }

   @Bean
   public ViewResolver myViewResolver(){
      return new MyViewResolver();
   }

   private class MyViewResolver implements ViewResolver{
      @Override
      public View resolveViewName(String s, Locale locale) throws Exception {
         return null;
      }
   }

}

发送请求后查看
在这里插入图片描述

5.3 格式化器小结

示例:

@Bean
@ConditionalOnProperty(prefix = "spring.mvc",name = {"date-format"}) //有此配置才注册
public Formatter<Date> dateFormatter() {
    return new DateFormatter(this.mvcProperties.getDateFormat());
}

由下图得知,如若我们自己定制格式化器,只需要创建实现了Converter接口的bean,将其注册到容器中即可
在这里插入图片描述
在这里插入图片描述

5.4 扩展SpringMVC

编写一个配置类@Configuration,是WebMvcConfigurerAdapter类型,不能标注@EnableWebMvc注解,这是我们自己的配置和SpringBoot的自动配置联合生效

@Configuration
public class MyWebMvc extends WebMvcConfigurerAdapter {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        super.addViewControllers(registry);
        registry.addViewController("/aaa").setViewName("error/404");

    }
}

原理(示例)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.5 接管SpringMvc

如果我们只使用我们自己的配置,不使用SpringBoot的自动配置,可将@EnableWebMvc注解添加到配置类上,使SpringMvc的自动配置失效,全面接管SpringMVC

@Configuration
@EnableWebMvc
public class MyWebMvc extends WebMvcConfigurerAdapter {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        super.addViewControllers(registry);
        registry.addViewController("/aaa").setViewName("error/404");

    }
}

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

5.6 SpringBoot自动配置总结

  • SpringBoot在自动配置组件的时候,先看容器中有没有用户自己的配置,若有则使用用户的配置,若没有才自动配置,还有一种情况就是将自动配置和用户配置合并
  • SpringBoot里面有xxxConfigurer帮助我们进行扩展配置

猜你喜欢

转载自blog.csdn.net/weixin_42997554/article/details/86526650
今日推荐