zoukankan      html  css  js  c++  java
  • SpringBoot自动配置原理

    引导类

    package com.company;

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;

    @SpringBootApplication
    public class BootDemoApplication {

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

    @SpringBootApplication注解

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

    追run()方法

    /**
    * Static helper that can be used to run a {@link SpringApplication} from the
    * specified source using default settings.
    * @param primarySource the primary source to load
    * @param args the application arguments (usually passed from a Java main method)
    * @return the running {@link ApplicationContext}
    */
    public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
    return run(new Class<?>[] { primarySource }, args);
    }

      

    继续追run()方法

    /**
    * Static helper that can be used to run a {@link SpringApplication} from the
    * specified sources using default settings and user supplied arguments.
    * @param primarySources the primary sources to load
    * @param args the application arguments (usually passed from a Java main method)
    * @return the running {@link ApplicationContext}
    */
    public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
    return new SpringApplication(primarySources).run(args);
    }

    追构造方法

      

    /**
    * Create a new {@link SpringApplication} instance. The application context will load
    * beans from the specified primary sources (see {@link SpringApplication class-level}
    * documentation for details. The instance can be customized before calling
    * {@link #run(String...)}.
    * @param primarySources the primary bean sources
    * @see #run(Class, String[])
    * @see #SpringApplication(ResourceLoader, Class...)
    * @see #setSources(Set)
    */
    public SpringApplication(Class<?>... primarySources) {
    this(null, primarySources);
    }

    继续

    /**
    * Create a new {@link SpringApplication} instance. The application context will load
    * beans from the specified primary sources (see {@link SpringApplication class-level}
    * documentation for details. The instance can be customized before calling
    * {@link #run(String...)}.
    * @param resourceLoader the resource loader to use
    * @param primarySources the primary bean sources
    * @see #run(Class, String[])
    * @see #setSources(Set)
    */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    this.resourceLoader = resourceLoader;
    Assert.notNull(primarySources, "PrimarySources must not be null");
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
      //判断当前项目的应用类型
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    this.mainApplicationClass = deduceMainApplicationClass();
    }

    追getSpringFactoriesInstances

    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
    return getSpringFactoriesInstances(type, new Class<?>[] {});
    }

    继续

      

    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
    ClassLoader classLoader = getClassLoader();
    // Use names and ensure unique to protect against duplicates
    Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
    }

    追loadFactoryNames

    public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
    String factoryTypeName = factoryType.getName();
    return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
    }

    追loadSpringFactories

      

    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
    MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
    if (result != null) {
    return result;
    } else {
    try {
           //这里去加载自动配置文件,如果当前项目classpath中没有,则会去jar包中找。默认的自动配置文件在spring-boot-autoconfigure-2.2.2.RELEASE.jar!META-INFspring.factories
    Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
    LinkedMultiValueMap result = new LinkedMultiValueMap();

    while(urls.hasMoreElements()) {
    URL url = (URL)urls.nextElement();
    UrlResource resource = new UrlResource(url);
    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
    Iterator var6 = properties.entrySet().iterator();

    while(var6.hasNext()) {
    Entry<?, ?> entry = (Entry)var6.next();
    String factoryTypeName = ((String)entry.getKey()).trim();
    String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
    int var10 = var9.length;

    for(int var11 = 0; var11 < var10; ++var11) {
    String factoryImplementationName = var9[var11];
    result.add(factoryTypeName, factoryImplementationName.trim());
    }
    }
    }

    cache.put(classLoader, result);
    return result;
    } catch (IOException var13) {
    throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
    }
    }
    }

    spring.factories部分内容

      

    # 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

    # Auto Configure
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=
    org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,
    org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,
    。。。

      键值对,值对应的都是org.springframework.boot.autoconfigure包中的内容,上图

      

    在这个包下可以找到所有的默认配置

      比如org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration

      

    /**
    * {@link EnableAutoConfiguration Auto-configuration} for {@link EnableWebMvc Web MVC}.
    *
    * @author Phillip Webb
    * @author Dave Syer
    * @author Andy Wilkinson
    * @author Sébastien Deleuze
    * @author Eddú Meléndez
    * @author Stephane Nicoll
    * @author Kristine Jetzke
    * @author Bruce Brouwer
    * @author Artsiom Yudovin
    * @since 2.0.0
    */
    //有很多@Conditional开头的注解,表示在满足条件下才会生效
    @Configuration(proxyBeanMethods = false)
    @ConditionalOnWebApplication(type = Type.SERVLET)//满足类型web应用
    @ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })//项目中存在这些类,引入了相关jar包就会有
    @ConditionalOnMissingBean(WebMvcConfigurationSupport.class)//没有该类型的bean在容器中
    @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
    @AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
    ValidationAutoConfiguration.class })
    public class WebMvcAutoConfiguration {

    找到InternalResourceViewResolver

      

    @Bean
    @ConditionalOnMissingBean//如果自定义配置了,就不会生效
    public InternalResourceViewResolver defaultViewResolver() {
    InternalResourceViewResolver resolver = new InternalResourceViewResolver();
    resolver.setPrefix(this.mvcProperties.getView().getPrefix());
    resolver.setSuffix(this.mvcProperties.getView().getSuffix());
    return resolver;
    }

    如果只想修改其中的属性值,一般也都只需要改变属性值即可,无需自己配置bean,追getter方法就可以找到WebMvcProperties.java

    /**
    * {@link ConfigurationProperties properties} for Spring MVC.
    *
    * @author Phillip Webb
    * @author Sébastien Deleuze
    * @author Stephane Nicoll
    * @author Eddú Meléndez
    * @author Brian Clozel
    * @since 2.0.0
    */
    @ConfigurationProperties(prefix = "spring.mvc")//这是一个配置类,前缀是spring.mvc
    public class WebMvcProperties {

    prefix和suffix是内部类View的属性

      

    public static class View {

    /**
    * Spring MVC view prefix.
    */
    private String prefix;

    /**
    * Spring MVC view suffix.
    */
    private String suffix;

    public String getPrefix() {
    return this.prefix;
    }

    public void setPrefix(String prefix) {
    this.prefix = prefix;
    }

    public String getSuffix() {
    return this.suffix;
    }

    public void setSuffix(String suffix) {
    this.suffix = suffix;
    }

    }

    所以要覆盖的话,只需要在application.yaml中配置spring.mvc.view.prefix和suffix即可。其他想要覆盖的

    spring-boot-autoconfigure-2.2.2.RELEASE.jar!META-INFadditional-spring-configuration-metadata.json和spring-configuration-metadata.json
    中有英文解释,这两个文件用于idea在application.yaml文件中提示用,参考链接https://www.jianshu.com/p/4488ea10ab2f
    spring:
    mvc:
    view:
    prefix: /WEB-INF/pages
    suffix: .html
  • 相关阅读:
    输入url到页面渲染发生了什么
    echarts缓存处理
    jquery 使用mock
    vue axios的封装
    css3实现盒子宽度随文字宽度自适应
    VUE中使用bus传值时,接收页面多次触发接收方法的问题
    原生js 文件 上传 下载封装
    微信小程序使用第三方包
    为什么我们要使用Async、Await关键字
    服务大众的人工智能---认知服务
  • 原文地址:https://www.cnblogs.com/zou-rong/p/12564480.html
Copyright © 2011-2022 走看看