zoukankan      html  css  js  c++  java
  • Spring Boot自动配置类

     
    前提
    1、一般来说,xxxAware接口,都提供了一个setXxx的方法,以便于其实现类将Xxx注入自身的xxx字段中,从而进行操作。
    例如 ApplicationContextAware ,就提供了 void setApplicationContext(ApplicationContext applicationContext) throws BeansException,从而让其实现可以直接操作 applicationContext 。
    2、Spring中的 BeanFactory,这是访问bean container 的root interface。其实现类的对象通常拥有一系列 bean 定义,并以不同的String 名字来区分。
    但是,官方文档不建议直接使用这种方式获取bean,而是建议使用注入的方式获取bean(@Autowire)。--这个,前期不能使用初始化注入吧?
     

    正文

    Spring Boot提供的自动配置都是位于包 org.springframework.boot.autoconfigure 之下。

    注意,
           ① 这里是Spring Boot提供的,而非第三方(如MyBatis-Spring-Boot-Starter)提供的。
           ② 不包含Spring Boot Actuator部分的。 
     
    Spring Boot的自动配置类可以通过autoconfig report查看,需要开启 --debug-Debug。或者在 Actuator 项目的autoconfig 端点查看。
     
    这里先从Web开始学习
    由于Spring Boot的web Starter集成了Spring MVC,而非其他,所以实际上提供的Web自动配置为Spring MVC的自动配置。
    Spring MVC的自动配置在包 org.springframework.boot.autoconfigure.web 之下,该包中的内容如下:

    从上图中可以清楚的看到Spring Boot为Spring MVC提供了哪些自动配置:
    • DispatcherServletAutoConfiguration.class
    • EmbeddedServletContainerAutoConfiguration.class
    • ErrorMvcAutoConfiguration.class
    • GsonHttpMessageConvertersConfiguration.class
    • HttpEncodingAutoConfiguration.class
    • HttpMessageConvertersAutoConfiguration.class
    • JacksonHttpMessageConvertersConfiguration.class
    • MultipartAutoConfiguration.class
    • ServerPropertiesAutoConfiguration.class
    • WebClientAutoConfiguration.class
    • WebMvcAutoConfiguration.class
    另外,还有一类文件:xxxProperties.class。这些文件都是 @ConfigurationProperties classes 。
    在 @Configuration classes上可以使用 @EnableConfigurationProperties 进行 @ConfigurationProperties classes 的注入。 -- 也可以在@Configuration classes内部使用@Bean,略麻烦。
     
    接下来,我们有针对性的来捋一遍。
     
    先看一下这些类的声明
     1 @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
     2 @Configuration
     3 @ConditionalOnWebApplication
     4 @ConditionalOnClass(DispatcherServlet.class)
     5 @AutoConfigureAfter(EmbeddedServletContainerAutoConfiguration.class)
     6 public class DispatcherServletAutoConfiguration { ... }
     7 
     8 @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
     9 @Configuration
    10 @ConditionalOnWebApplication
    11 @Import(BeanPostProcessorsRegistrar.class)
    12 public class EmbeddedServletContainerAutoConfiguration { ... }
    13 
    14 @Configuration
    15 @ConditionalOnClass(Gson.class)
    16 class GsonHttpMessageConvertersConfiguration { ... }
    17 
    18 @Configuration
    19 @EnableConfigurationProperties(HttpEncodingProperties.class)
    20 @ConditionalOnWebApplication
    21 @ConditionalOnClass(CharacterEncodingFilter.class)
    22 @ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)
    23 public class HttpEncodingAutoConfiguration { ... }
    24 
    25 @Configuration
    26 @ConditionalOnClass(HttpMessageConverter.class)
    27 @AutoConfigureAfter({ GsonAutoConfiguration.class, JacksonAutoConfiguration.class })
    28 @Import({ JacksonHttpMessageConvertersConfiguration.class, GsonHttpMessageConvertersConfiguration.class })
    29 public class HttpMessageConvertersAutoConfiguration { ... }
    30 
    31 @Configuration
    32 class JacksonHttpMessageConvertersConfiguration{ ... }
    33 
    34 @Configuration
    35 @ConditionalOnClass({ Servlet.class, StandardServletMultipartResolver.class, MultipartConfigElement.class })
    36 @ConditionalOnProperty(prefix = "spring.http.multipart", name = "enabled", matchIfMissing = true)
    37 @EnableConfigurationProperties(MultipartProperties.class)
    38 public class MultipartAutoConfiguration { ... }
    39 
    40 @Configuration
    41 @EnableConfigurationProperties
    42 @ConditionalOnWebApplication
    43 public class ServerPropertiesAutoConfiguration { ... }
    44 
    45 @Configuration
    46 @AutoConfigureAfter(HttpMessageConvertersAutoConfiguration.class)
    47 public class WebClientAutoConfiguration { ... }
    48 
    49 @Configuration
    50 @ConditionalOnWebApplication
    51 @ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurerAdapter.class })
    52 @ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
    53 @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
    54 @AutoConfigureAfter(DispatcherServletAutoConfiguration.class)
    55 public class WebMvcAutoConfiguration { ... }
    View Code
    整理一下优先级
    最高级
            EmbeddedServletContainerAutoConfiguration
            DispatcherServletAutoConfiguration 
    次高级
            WebMvcAutoConfiguration
    无级别
            HttpEncodingAutoConfiguration
            MultipartAutoConfiguration
            ServerPropertiesAutoConfiguration
      依赖链(属于无级别)
            GsonHttpMessageConvertersConfiguration
            JacksonHttpMessageConvertersConfiguration
            HttpMessageConvertersAutoConfiguration
            WebClientAutoConfiguration
     
    一、先看一下 EmbeddedServletContainerAutoConfiguration,这是内置Servlet容器的自动配置 -- 默认就是那个 pivotal-tc-server (定制版tomcat,商业的)。
    该类的声明如下:
     1 @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) // 自动配置里面的最高优先级
     2 @Configuration
     3 @ConditionalOnWebApplication // 仅限于web应用
     4 @Import(BeanPostProcessorsRegistrar.class) // 导入内置容器的设置
     5 public class EmbeddedServletContainerAutoConfiguration {
     6     @Configuration
     7     @ConditionalOnClass({ Servlet.class, Tomcat.class })
     8     @ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
     9     public static class EmbeddedTomcat {
    10         // ...
    11     }
    12 
    13     @Configuration
    14     @ConditionalOnClass({ Servlet.class, Server.class, Loader.class, WebAppContext.class })
    15     @ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
    16     public static class EmbeddedJetty {
    17         // ...
    18     }
    19 
    20     @Configuration
    21     @ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class })
    22     @ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
    23     public static class EmbeddedUndertow {
    24         // ...
    25     }
    26 
    27     public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {
    28         // ...
    29     }
    30 }
     
    @ConditionalOnWebApplication 是基于application context 是否 web application context 进行判断。
    @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) ,这里的 Ordered.HIGHEST_PRECEDENCE  其实是int类型的最小值,代表最高的优先级。
    @Import(BeanPostProcessorsRegistrar.class,这里 BeanPostProcessorsRegistrar 中进行的操作是注册了一个bean,  EmbeddedServletContainerCustomizerBeanPostProcessor 。是通过 ImportBeanDefinitionRegistrar  进行早期注册。
     
    这个配置类,内部共有4个静态内部类:3个容器类(tomcat、jetty、undertow)、1个bean注册类。
    1. 3个容器类是基于classpath中的class文件来判断使用哪个容器,默认使用内置容器。
    2. 1个bean注册类则是注册了一个 BeanPostProcessor bean,用于对容器进行定制。
     
    下面重点看一下这个bean注册类的相关。
    1、EmbeddedServletContainerCustomizerBeanPostProcessor
    public class EmbeddedServletContainerCustomizerBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware {
        // ...
    }

    2、BeanPostProcessor接口,该接口内容如下:

    1 public interface BeanPostProcessor {
    2     Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    3     Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
    4 }
    View Code

    根据方法的名字可以知道这是对在bean初始化之前、之后进行操作的方法。

    该接口的Javadoc如下:
    1. BeanPostProcessor则是一个工厂钩子(factory hook),用于对新beans实例进行定制修改,例如检查它们的标记接口或者使用代理包装它们。
    2. ApplicationContexts能够自动探测BeanPostProcessor beans,并将他们应用到后续创建的任意beans中。
    3. 简单bean工厂允许代码化的注册post-processors,并将注册的post-processors应用到该工厂创建的所有bean中。
    4. 典型的做法是,通过标记接口装配beans时,post-processors会实现postProcessBeforeInitialization;而使用代理包装beans时则会实现postProcessAfterInitialization
    EmbeddedServletContainerCustomizerBeanPostProcessor 中提供了 postProcessBeforeInitialization 的实现(对bean有更多的操作,而非直接返回bean),对内置容器进行了定制操作。(插一句,这里的定制操作是通过applicationContext 中 EmbeddedServletContainerCustomizer beans进行的,所以需要先获取applicationContext(ApplicationContextAware的功劳),再从applicationContext中获取EmbeddedServletContainerCustomizer beans)
    3、回过头来再看一下BeanPostProcessorsRegistrar
    1 public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {
    2     // ...
    3 }
    View Code

    这是个静态内部类,实现了两个接口。

     
    4、接口ImportBeanDefinitionRegistrar
    public interface ImportBeanDefinitionRegistrar {
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
    }

    该接口用于在系统处理@Configuration class时注册更多的bean。是bean定义级别的操作,而非@Bean method/instance级别的。

    这个方法,应该是在Spring加载bean时被Spring调用。
    org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader

    未完待续。

     
     
     
     
     
  • 相关阅读:
    rabbitmq channel参数详解
    rabbitmq direct、fanout、topic 三种Exchange java 代码比较
    spark 性能优化
    spark sql 窗口函数over partition by
    Python爬虫从入门到进阶(4)之xpath的使用
    Python爬虫从入门到进阶(3)之requests的使用
    Python爬虫从入门到进阶(2)之urllib库的使用
    Mac环境下Redis的安装
    Mac环境下Vagrant的安装
    Mac环境下Scrapy的安装
  • 原文地址:https://www.cnblogs.com/larryzeal/p/5879395.html
Copyright © 2011-2022 走看看