写点什么

SpringBoot 自动装配源码解析

用户头像
Rubble
关注
发布于: 2021 年 08 月 20 日
SpringBoot 自动装配源码解析

来思考个问题,为什么引入 spring-boot-starter-data-redis 依赖后就可以使用 @Autowired 注入 RedisTemplate ?


无疑是 SpringBoot 自动装配,下面就从源码角度探索下其实现。


SpringBoot 自动装配是 SpringBoot 较 springMVC 最大的亮点。

SpringBootApplication 注解

SpringBoot 项目的入口类一般会标注 @SpringBootApplication,其继承的注解有以下几个,也就是加入了注解就自动开始了自动装配,component 扫描,同时入口类也是一个配置类 Configuration。


@SpringBootApplication包含如下注解@SpringBootConfiguration   包含 @Configuration@EnableAutoConfiguration@ComponentScan
复制代码

何时加载

从 main 入口 SpringApplication.run 进行跟踪,在 refreshContext(context)进行加载 ApplicationContext 上下文,继续查找会找到处理 @Configuration 的类,再继续会找到 AutoConfigurationImportSelector 来处理自动装配。


SpringApplication.run方法中refreshContext(context);⬇️AbstractApplicationContextinvokeBeanFactoryPostProcessors(beanFactory);⬇️// 用来处理标记@Configuration的类ConfigurationClassPostProcessorprocessConfigBeanDefinitions(registry);⬇️//实现DeferredImportSelector用来处理 auto-configurationAutoConfigurationImportSelectorprocess()// AutoConfigurationEntry getAutoConfigurationEntry(...){...  // 获取配置  List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);  configurations = removeDuplicates(configurations);  // 排除项  Set<String> exclusions = getExclusions(annotationMetadata, attributes);  checkExcludedClasses(configurations, exclusions);  configurations.removeAll(exclusions);  // 过滤配置 AutoConfigurationImportFilter  configurations = filter(configurations, autoConfigurationMetadata);  // 广播事件  fireAutoConfigurationImportEvents(configurations, exclusions);...}⬇️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;  }⬇️// 真正指定EnableAutoConfiguration的地方protected Class<?> getSpringFactoriesLoaderFactoryClass() {    return EnableAutoConfiguration.class;  }
复制代码


从 META-INF/spring.factories 加载 EnableAutoConfiguration 指定的类


  /**   * 从 META-INF/spring.factories 加载类名称   * classloader ==> AppClassLoader      * Load the fully qualified class names of factory implementations of the given type from    * "META-INF/spring.factories", using the given class loader.   */  public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {    String factoryTypeName = factoryType.getName();    return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());  }
复制代码


SpringFactoriesLoader 类 获取加载工厂类


private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {  ...    try {      // FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";      Enumeration<URL> urls = (classLoader != null ?          classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :          ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));      result = new LinkedMultiValueMap<>();      while (urls.hasMoreElements()) {        URL url = urls.nextElement();        UrlResource resource = new UrlResource(url);        Properties properties = PropertiesLoaderUtils.loadProperties(resource);        for (Map.Entry<?, ?> entry : properties.entrySet()) {          // key 作为factoryTypeName          String factoryTypeName = ((String) entry.getKey()).trim();          for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {            result.add(factoryTypeName, factoryImplementationName.trim());          }        }      }    ...  }
复制代码


调试获取到 13 个配置项, V2.2.5 版本


"org.springframework.boot.diagnostics.FailureAnalysisReporter" -> {LinkedList@4979}  size = 1"org.springframework.boot.diagnostics.FailureAnalyzer" -> {LinkedList@4981}  size = 18"org.springframework.boot.SpringBootExceptionReporter" -> {LinkedList@4983}  size = 1"org.springframework.boot.SpringApplicationRunListener" -> {LinkedList@4985}  size = 1"org.springframework.context.ApplicationListener" -> {LinkedList@4987}  size = 11"org.springframework.boot.env.PropertySourceLoader" -> {LinkedList@4989}  size = 2"org.springframework.context.ApplicationContextInitializer" -> {LinkedList@4991}  size = 7"org.springframework.boot.env.EnvironmentPostProcessor" -> {LinkedList@4993}  size = 4"org.springframework.boot.autoconfigure.AutoConfigurationImportListener" -> {LinkedList@4995}  size = 1"org.springframework.boot.autoconfigure.AutoConfigurationImportFilter" -> {LinkedList@4997}  size = 3"org.springframework.boot.autoconfigure.EnableAutoConfiguration" -> {LinkedList@4999}  size = 124"org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider" -> {LinkedList@5001}  size = 5"org.springframework.beans.BeanInfoFactory" -> {LinkedList@5003}  size = 1
复制代码


AutoConfigurationImportFilter 类型有 3 个,来进行配置过滤。


0 = "org.springframework.boot.autoconfigure.condition.OnBeanCondition"1 = "org.springframework.boot.autoconfigure.condition.OnClassCondition"2 = "org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition"
复制代码


ConfigurationClassParser 是加载配置的核心类


在 doProcessConfigurationClass 方法处理了如下注解及父类处理


@PropertySource@ComponentScan@Import@Bean methods
复制代码


总结


自动装配的核心类有 ConfigurationClassPostProcessor、ConfigurationClassParser、AutoConfigurationImportSelector。


在 ConfigurationClassPostProcessor 配置类处理器,创建了 ConfigurationClassParser 对象对 @Configuration 注解的类进行处理,ConfigurationClassParser 类持有 DeferredImportSelector(即实现类 AutoConfigurationImportSelector)对象实现对配置类的加载、过滤、排除最终获取到配置类。


SpringFactoriesLoader 会加载 META-INF/spring.factories 下的所有类型并以 key-value 的形式缓存。自动配置获取以 EnableAutoConfiguration 为 key 的 value 即定义的配置类。

用户头像

Rubble

关注

还未添加个人签名 2021.06.01 加入

还未添加个人简介

评论

发布
暂无评论
SpringBoot 自动装配源码解析