zoukankan      html  css  js  c++  java
  • SpringBoot自动装配源码解析

    序:众所周知spring-boot入门容易精通难,说到底spring-boot是对spring已有的各种技术的整合封装,因为封装了所以使用简单,也因为封装了所以越来越多的"拿来主义"者们不愿意去关注其具体实现!为了更好的使用spring-boot所以必要的源码探索是非常有必要的!今天开始探索的第一步:自动装配原理-----------------(此处默认各位看官熟悉spring的各种基础注解

    1.要谈自动装配我们需要从项目的初始注解入手:@SpringBootApplication

     1 @Target({ElementType.TYPE})
     2 @Retention(RetentionPolicy.RUNTIME)
     3 @Documented
     4 @Inherited
     5 @SpringBootConfiguration
     6 @EnableAutoConfiguration
     7 @ComponentScan(
     8     excludeFilters = {@Filter(
     9     type = FilterType.CUSTOM,
    10     classes = {TypeExcludeFilter.class}
    11 ), @Filter(
    12     type = FilterType.CUSTOM,
    13     classes = {AutoConfigurationExcludeFilter.class}
    14 )}
    15 )
    16 public @interface SpringBootApplication {
    17     ...38 }

    2.这个下面实现自动装配的注解为:@EnableAutoConfiguration

     1 @Target({ElementType.TYPE})
     2 @Retention(RetentionPolicy.RUNTIME)
     3 @Documented
     4 @Inherited
     5 @AutoConfigurationPackage
     6 @Import({AutoConfigurationImportSelector.class})
     7 public @interface EnableAutoConfiguration {
     8     String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
     9 
    10     Class<?>[] exclude() default {};
    11 
    12     String[] excludeName() default {};
    13 }

    3.在这个注解下我们需要关注两个注解:@AutoConfigurationPackage、@Import({AutoConfigurationImportSelector.class})

    a.我们先来看看@AutoConfigurationPackage

    1 @Target({ElementType.TYPE})
    2 @Retention(RetentionPolicy.RUNTIME)
    3 @Documented
    4 @Inherited
    5 @Import({Registrar.class})
    6 public @interface AutoConfigurationPackage {
    7 }

    这个下面引入了:Registrar

     1 static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
     2         Registrar() {
     3         }
     4 
     5         public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
     6             AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());
     7         }
     8 
     9         public Set<Object> determineImports(AnnotationMetadata metadata) {
    10             return Collections.singleton(new AutoConfigurationPackages.PackageImport(metadata));
    11         }
    12     }

    这是AutoConfigurationPackage的一个静态类,标蓝处的动作为为指定@ComponentScan的扫描路径,此处打断点启动项目我们可以发现这个为项目的顶级包名。(这个下面不做深入介绍,此内容不属于本文重点,有兴趣自行深入了解)如图:

    这儿确保了将项目目录下所有的bean注入到容器 

     b.接下来我们看看引入的AutoConfigurationImportSelector(个人觉得这个是自动配置的灵魂)

    public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
        private static final AutoConfigurationImportSelector.AutoConfigurationEntry EMPTY_ENTRY = new AutoConfigurationImportSelector.AutoConfigurationEntry();
        private static final String[] NO_IMPORTS = new String[0];
        private static final Log logger = LogFactory.getLog(AutoConfigurationImportSelector.class);
        private static final String PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE = "spring.autoconfigure.exclude";
        private ConfigurableListableBeanFactory beanFactory;
        private Environment environment;
        private ClassLoader beanClassLoader;
        private ResourceLoader resourceLoader;
      .... protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) { if (!this.isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } else { AnnotationAttributes attributes = this.getAttributes(annotationMetadata); List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes); configurations = this.removeDuplicates(configurations); Set<String> exclusions = this.getExclusions(annotationMetadata, attributes); this.checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = this.filter(configurations, autoConfigurationMetadata); this.fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions); } }   .... }

    此处是去获取真正自动配置类的集合,我们需要关注标蓝的方法:

    1 protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    2         List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
    3         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.");
    4         return configurations;
    5     }

    还看不出来什么,还需要往下走一层:

     1 public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
     2         String factoryClassName = factoryClass.getName();
     3         return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
     4     }
     5 
     6     private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
     7         MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
     8         if (result != null) {
     9             return result;
    10         } else {
    11             try {
    12                 Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
    13                 LinkedMultiValueMap result = new LinkedMultiValueMap();
    14 
    15                 while(urls.hasMoreElements()) {
    16                     URL url = (URL)urls.nextElement();
    17                     UrlResource resource = new UrlResource(url);
    18                     Properties properties = PropertiesLoaderUtils.loadProperties(resource);
    19                     Iterator var6 = properties.entrySet().iterator();
    20 
    21                     while(var6.hasNext()) {
    22                         Entry<?, ?> entry = (Entry)var6.next();
    23                         String factoryClassName = ((String)entry.getKey()).trim();
    24                         String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
    25                         int var10 = var9.length;
    26 
    27                         for(int var11 = 0; var11 < var10; ++var11) {
    28                             String factoryName = var9[var11];
    29                             result.add(factoryClassName, factoryName.trim());
    30                         }
    31                     }
    32                 }
    33 
    34                 cache.put(classLoader, result);
    35                 return result;
    36             } catch (IOException var13) {
    37                 throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
    38             }
    39         }
    40     }

    我们可以发现spring-boot会去META-INF/spring.factories找org.springframework.boot.autoconfigure.EnableAutoConfiguration的value.这个的具体位置如图:

    这个下面配置了所有自动配置,以其中一个为例(其余类似),分析其可配参数。(AopAutoConfiguration)

     1 @Configuration
     2 @ConditionalOnClass({EnableAspectJAutoProxy.class, Aspect.class, Advice.class, AnnotatedElement.class})
     3 @ConditionalOnProperty(
     4     prefix = "spring.aop",
     5     name = {"auto"},
     6     havingValue = "true",
     7     matchIfMissing = true
     8 )
     9 public class AopAutoConfiguration {
    10     public AopAutoConfiguration() {
    11     }
    12 
    13     @Configuration
    14     @EnableAspectJAutoProxy(
    15         proxyTargetClass = true
    16     )
    17     @ConditionalOnProperty(
    18         prefix = "spring.aop",
    19         name = {"proxy-target-class"},
    20         havingValue = "true",
    21         matchIfMissing = true
    22     )
    23     public static class CglibAutoProxyConfiguration {
    24         public CglibAutoProxyConfiguration() {
    25         }
    26     }
    27 
    28     @Configuration
    29     @EnableAspectJAutoProxy(
    30         proxyTargetClass = false
    31     )
    32     @ConditionalOnProperty(
    33         prefix = "spring.aop",
    34         name = {"proxy-target-class"},
    35         havingValue = "false",
    36         matchIfMissing = false
    37     )
    38     public static class JdkDynamicAutoProxyConfiguration {
    39         public JdkDynamicAutoProxyConfiguration() {
    40         }
    41     }
    42 }

    我们可以在spring-configuration-metadata.json中找到其对应的配置如下:

    {
          "name": "spring.aop.proxy-target-class",
          "type": "java.lang.Boolean",
          "description": "Whether subclass-based (CGLIB) proxies are to be created (true), as opposed to standard Java interface-based proxies (false).",
          "defaultValue": true
        },

    介绍到这里spring-boot的自动装配过程我们就基本看完了~

  • 相关阅读:
    ASP.NET Core 进程内(InProcess)托管
    ASP.NET Core 中的 Main 方法
    ASP.NET Core Web 项目文件
    5)
    4)
    单词
    html5单词
    3)
    2)
    1)
  • 原文地址:https://www.cnblogs.com/shuyuq/p/10694191.html
Copyright © 2011-2022 走看看