SpringBoot自动装配源码解析
序:众所周知spring-boot入门容易精通难,说到底spring-boot是对spring已有的各种技术的整合封装,因为封装了所以使用简单,也因为封装了所以越来越多的"拿来主义"者们不愿意去关注其具体实现!为了更好的使用spring-boot所以必要的源码探索是非常有必要的!今天开始探索的第一步:自动装配原理-----------------(此处默认各位看官熟悉spring的各种基础注解)
1.要谈自动装配我们需要从项目的初始注解入手:@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 { ... }
2.这个下面实现自动装配的注解为:@EnableAutoConfiguration
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import({AutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; Class<?>[] exclude() default {}; String[] excludeName() default {}; }
3.在这个注解下我们需要关注两个注解:@AutoConfigurationPackage、@Import({AutoConfigurationImportSelector.class})
a.我们先来看看@AutoConfigurationPackage
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Import({Registrar.class}) public @interface AutoConfigurationPackage { }
这个下面引入了:Registrar
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports { Registrar() { } public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName()); } public Set<Object> determineImports(AnnotationMetadata metadata) { return Collections.singleton(new AutoConfigurationPackages.PackageImport(metadata)); } }
这是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); } } .... }
此处是去获取真正自动配置类的集合,我们需要关注标蓝的方法:
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> 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; }
还看不出来什么,还需要往下走一层:
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) { String factoryClassName = factoryClass.getName(); return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList()); } 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 { 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 factoryClassName = ((String)entry.getKey()).trim(); String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue()); int var10 = var9.length; for(int var11 = 0; var11 < var10; ++var11) { String factoryName = var9[var11]; result.add(factoryClassName, factoryName.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-boot会去META-INF/spring.factories找org.springframework.boot.autoconfigure.EnableAutoConfiguration的value.这个的具体位置如图:
这个下面配置了所有自动配置,以其中一个为例(其余类似),分析其可配参数。(AopAutoConfiguration)
@Configuration @ConditionalOnClass({EnableAspectJAutoProxy.class, Aspect.class, Advice.class, AnnotatedElement.class}) @ConditionalOnProperty( prefix = "spring.aop", name = {"auto"}, havingValue = "true", matchIfMissing = true ) public class AopAutoConfiguration { public AopAutoConfiguration() { } @Configuration @EnableAspectJAutoProxy( proxyTargetClass = true ) @ConditionalOnProperty( prefix = "spring.aop", name = {"proxy-target-class"}, havingValue = "true", matchIfMissing = true ) public static class CglibAutoProxyConfiguration { public CglibAutoProxyConfiguration() { } } @Configuration @EnableAspectJAutoProxy( proxyTargetClass = false ) @ConditionalOnProperty( prefix = "spring.aop", name = {"proxy-target-class"}, havingValue = "false", matchIfMissing = false ) public static class JdkDynamicAutoProxyConfiguration { public JdkDynamicAutoProxyConfiguration() { } } }
我们可以在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的自动装配过程我们就基本看完了~
- spring boot 源码解析40-CounterService,GaugeService默认自动装配解析
- Spring的Autowired自动装配(XML版本+Annotation版本+源码+解析)
- Spring源码解析-autowiring自动装配的实现
- SpringBoot自动装配原理解析
- 【源码解析】自动配置的这些细节都不知道,别说你会 springboot
- Spring Boot自动配置源码解析
- 【Spring Boot】SpringBoot-自动配置源码解析
- SpringBoot SpringApplication底层源码分析与自动装配
- SpringBoot 源码解析 (五)----- Spring Boot的核心能力 - 自动配置源码解析
- springboot源码解析:自己实现一个springboot自动配置
- SpringBoot自动装配流程源码分析
- (二)SpringBoot源码解析--自动注入过程 Autowired原理(1)
- spring boot学习二:Spring Boot自动装配分析与实战
- spring boot 源码解析5-SpringApplication#run第5步
- spring boot 源码解析15-spring mvc零配置
- 附4 springboot源码解析-run()
- 深入浅析SpringBoot中的自动装配
- Springboot 源码解析(启动时)
- Spring Boot 自动装配(二) - @SpringBootApplication、@AutoConfigurationPackage、@EnableAutoConfiguration
- SpringBoot 的 yml文件 属性读取部分源码解析