springboot源码分析-自动装配
2021/10/2 17:11:38
本文主要是介绍springboot源码分析-自动装配,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
1.概述
springboot是用main方法来启动服务的,mian方法都加有 SpringBootApplication这个注解,这个注解是springboot自动装配的实现
首先看SpringBootApplication这个注解的源码
/* * Copyright 2012-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.boot.autoconfigure; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.context.TypeExcludeFilter; import org.springframework.boot.context.properties.ConfigurationPropertiesScan; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; import org.springframework.core.annotation.AliasFor; import org.springframework.data.repository.Repository; /** * 表示声明一个或多个的 {@link Configuration 配置} 类 * {@link Bean @Bean} 方法并触发 {@link EnableAutoConfiguration * 自动配置},{@link ComponentScan 组件扫描},以及 * {@link ConfigurationPropertiesScan 配置属性扫描}。这是一个 * 相当于声明 {@code @Configuration} 的便利注解, * {@code @EnableAutoConfiguration}、{@code @ComponentScan} 和 * {@code @ConfigurationPropertiesScan}。 * * @author Phillip Webb * @author Stephane Nicoll * @author Andy Wilkinson * @since 1.2.0 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited //表示能从子类的注解中获取到父类的注解属性 @SpringBootConfiguration //注解继承了Configuration注解并且增加了开启代理的配置 @EnableAutoConfiguration //自动装配的主要实现 @ComponentScan(excludeFilters = {@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class)}) //扫包 @ConfigurationPropertiesScan //属性文件内容自动填充bean public @interface SpringBootApplication { /** * 排除特定的自动配置类,以便它们永远不会被应用。 * * @return 要排除的类@SpringBootApplication */ @AliasFor(annotation = EnableAutoConfiguration.class) Class<?>[] exclude() default {}; /** * 排除特定的自动配置类名称,以便它们永远不会被 * 适用。 * * @return 要排除的类名 * @since 1.3.0 */ @AliasFor(annotation = EnableAutoConfiguration.class) String[] excludeName() default {}; /** * 用于扫描带注释组件的基本包。使用 {@link #scanBasePackageClasses} * 用于基于字符串的包名称的类型安全替代方案。 * <p> * <strong>注意:</strong>这个设置是一个别名 * 仅限 {@link ComponentScan @ComponentScan}。它对 {@code @Entity} 没有影响 * 扫描或 Spring Data {@link Repository} 扫描。对于那些你应该添加的 * {@link org.springframework.boot.autoconfigure.domain.EntityScan @EntityScan} 和 * {@code @Enable...Repositories} 注释。 * * @return base packages to scan * @since 1.3.0 */ @AliasFor(annotation = ComponentScan.class, attribute = "basePackages") String[] scanBasePackages() default {}; /** * {@link #scanBasePackages} 的类型安全替代方案,用于指定要使用的包 * 扫描带注释的组件。将扫描指定的每个类的包。 * <p> * 考虑在每个包中创建一个特殊的无操作标记类或接口 * 除了被此属性引用外,没有其他用途。 * <p> * <strong>注意:</strong>这个设置是一个别名 * 仅限 {@link ComponentScan @ComponentScan}。它对 {@code @Entity} 没有影响 * 扫描或 Spring Data {@link Repository} 扫描。对于那些你应该添加的 * {@link org.springframework.boot.autoconfigure.domain.EntityScan @EntityScan} 和 * {@code @Enable...Repositories} 注释。 * * @return base packages to scan * @since 1.3.0 */ @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses") Class<?>[] scanBasePackageClasses() default {}; /** * 指定 {@link Bean @Bean} 方法是否应该被代理以强制执行 * bean 生命周期行为,例如返回共享的单例 bean 实例,即使在 * 在用户代码中直接调用 {@code @Bean} 方法的情况。此功能需要 * 方法拦截,通过运行时生成的 CGLIB 子类实现 * 带有限制,例如配置类及其方法不被 * 允许声明 {@code final}。 * <p> * 默认为 {@code true},允许在 * 配置类以及对这个配置的外部调用 * {@code @Bean} 方法,例如来自另一个配置类。如果不需要这个 * 因为每个特定配置的 {@code @Bean} 方法都是 * 自包含并设计为容器使用、开关的普通工厂方法 * 将此标志设置为 {@code false} 以避免 CGLIB 子类处理。 * <p> * 关闭bean方法拦截有效处理{@code @Bean}方法 * 单独像在非 {@code @Configuration} 类上声明时一样,也就是 * “@Bean Lite 模式”(参见 {@link Bean @Bean 的 javadoc})。因此在行为上 * 相当于删除 {@code @Configuration} 构造型。 * * @return whether to proxy {@code @Bean} methods * @since 2.2 */ @AliasFor(annotation = Configuration.class) boolean proxyBeanMethods() default true; }
-
Inherited注解:表示子类能继承当前注解的属性
-
SpringBootConfiguration注解:父注解是Configuration,没明白和Configuration的区别
-
EnableAutoConfiguration注解:自动装配的实现
-
ComponentScan注解:扫包,如果不配置,默认扫描当前包
-
ConfigurationPropertiesScan:配置文件里的属性自动填充到bean
主要看EnableAutoConfiguration注解
/* * Copyright 2012-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.boot.autoconfigure; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.servlet.server.ServletWebServerFactory; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.core.io.support.SpringFactoriesLoader; /** * 启用 Spring 应用程序上下文的自动配置,尝试猜测和 * 配置您可能需要的bean。自动配置类通常是 * 根据您的类路径和您定义的 bean 应用。例如,如果你 * 在你的类路径上有 {@code tomcat-embedded.jar} 你可能想要一个 * {@link TomcatServletWebServerFactory}(除非你已经定义了你自己的 * {@link ServletWebServerFactory} bean)。 * <p> * 使用 {@link SpringBootApplication @SpringBootApplication} 时,自动配置 * 自动启用上下文,因此添加此注释没有 * 附加效果。 * <p> * 自动配置尝试尽可能智能,并会像您一样后退 * 定义更多你自己的配置。您可以随时手动 {@link #exclude()} 任何 * 您永远不想应用的配置(如果您不想应用,请使用 {@link #excludeName()} * 可以访问它们)。您还可以通过 * {@code spring.autoconfigure.exclude} 属性。始终应用自动配置 * 在注册用户定义的 bean 之后。 * <p> * 用{@code @EnableAutoConfiguration}注解的类的包, * 通常通过 {@code @SpringBootApplication},具有特定意义,经常使用 * 作为“默认”。例如,它会在扫描 {@code @Entity} 类时使用。 * 一般建议您放置 {@code @EnableAutoConfiguration} (如果您是 * 不在根包中使用 {@code @SpringBootApplication}) 以便所有子包 * 和类可以搜索。 * <p> * 自动配置类是常规 Spring {@link Configuration @Configuration} * 豆子。它们使用 {@link SpringFactoriesLoader} 机制(键控 * 针对此类)。通常自动配置bean是 * {@link Conditional @Conditional} bean(最常使用 * {@link ConditionalOnClass @ConditionalOnClass} 和 * {@link ConditionalOnMissingBean @ConditionalOnMissingBean} 注释)。 * * @author Phillip Webb * @author Stephane Nicoll * @see ConditionalOnBean * @see ConditionalOnMissingBean * @see ConditionalOnClass * @see AutoConfigureAfter * @see SpringBootApplication * @since 1.0.0 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage //配置扫描包的bean,可以通过这个bean获取到扫描的包路径 @Import(AutoConfigurationImportSelector.class) //引入自动装配的配置 public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; /** * 排除特定的自动配置类,以便它们永远不会被应用。 * * @return the classes to exclude */ Class<?>[] exclude() default {}; /** * 排除特定的自动配置类名称,以便它们永远不会被 * 适用。 * * @return the class names to exclude * @since 1.3.0 */ String[] excludeName() default {}; }
-
AutoConfigurationPackage注解:引入一个AutoConfigurationPackages的bean,bean里有个BasePackages的静态内部类保存要扫描的包名称,可以同步AutoConfigurationPackages的get方法获取所有的扫描包的配置
-
AutoConfigurationImportSelector注解:引入所有自动配置的bean
AutoConfigurationImportSelector源码
https://blog.csdn.net/qq_39482039/article/details/120585957
AutoConfigurationImportSelector主要实现DeferredImportSelector接口,实现了getImportGroup方法返回了AutoConfigurationImportSelector中的AutoConfigurationGroup内部类,会先调用AutoConfigurationGroup内部类的process方法,来将自动配置项设置到当前类的属性中,以便selectImports方法使用
@Override public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) { Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector, () -> String.format("Only %s implementations are supported, got %s", AutoConfigurationImportSelector.class.getSimpleName(), deferredImportSelector.getClass().getName())); //获取自动装配的配置 AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector) .getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata); this.autoConfigurationEntries.add(autoConfigurationEntry); for (String importClassName : autoConfigurationEntry.getConfigurations()) { this.entries.putIfAbsent(importClassName, annotationMetadata); } }
getAutoConfigurationEntry方法获取自动装配的配置
/** * 根据 {@link AnnotationMetadata} 返回 {@link AutoConfigurationEntry} * 导入 {@link Configuration @Configuration} 类。 * * @param autoConfigurationMetadata 自动配置元数据 * @param annotationMetadata 配置类的注解元数据 * @return the auto-configurations that should be imported */ protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } AnnotationAttributes attributes = getAttributes(annotationMetadata); //META-INF/spring.factories下获取路径是org.springframework.boot.autoconfigure.EnableAutoConfiguration的配置 List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); //去重,并可以由子类拓展 configurations = removeDuplicates(configurations); //获取排除的自动配置 Set<String> exclusions = getExclusions(annotationMetadata, attributes); //校验配置信息是否可加载,并且不能排除自动配置信息 checkExcludedClasses(configurations, exclusions); //从自动配置移除忽略的 configurations.removeAll(exclusions); //通过META-INF/spring.factories下AutoConfigurationImportFilter来过滤不需要的bean. //也就是通过OnBeanCondition,OnClassCondition,OnWebApplicationCondition来过滤不需要的bean. configurations = filter(configurations, autoConfigurationMetadata); //执行自动装配加载的监听器 fireAutoConfigurationImportEvents(configurations, exclusions); //封装到AutoConfigurationEntry并返回 return new AutoConfigurationEntry(configurations, exclusions); }
getCandidateConfigurations方法META-INF/spring.factories下获取路径是org.springframework.boot.autoconfigure.EnableAutoConfiguration的配置
/** * 返回应考虑的自动配置类名称。默认情况下 * 此方法将使用 {@link SpringFactoriesLoader} 加载候选对象 * {@link #getSpringFactoriesLoaderFactoryClass()}。 * * @param metadata the source metadata * @param attributes the {@link #getAttributes(AnnotationMetadata) annotation * attributes} * @return a list of candidate configurations */ 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; }
removeDuplicates转为hashset去重
protected final <T> List<T> removeDuplicates(List<T> list) { return new ArrayList<>(new LinkedHashSet<>(list)); }
getExclusions获取注解要排除的自动配置
/** * 返回任何限制候选配置的排除项。 * * @param metadata the source metadata * @param attributes the {@link #getAttributes(AnnotationMetadata) annotation * attributes} * @return exclusions or an empty set */ protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) { Set<String> excluded = new LinkedHashSet<>(); excluded.addAll(asList(attributes, "exclude")); excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName"))); excluded.addAll(getExcludeAutoConfigurationsProperty()); return excluded; }
checkExcludedClasses方法自动配置项必须可加载,并且排除的自动配置必须包含在当前的配置项中
private void checkExcludedClasses(List<String> configurations, Set<String> exclusions) { List<String> invalidExcludes = new ArrayList<>(exclusions.size()); for (String exclusion : exclusions) { //校验是否可以加载,并且要加载的属性中不包含排除的 if (ClassUtils.isPresent(exclusion, getClass().getClassLoader()) && !configurations.contains(exclusion)) { invalidExcludes.add(exclusion); } } //如果不能加载或者自动配置里不包含排除的配置项,抛异常提示报错 if (!invalidExcludes.isEmpty()) { handleInvalidExcludes(invalidExcludes); } }
filter方法通过法META-INF/spring.factories下配置的AutoConfigurationImportFilter来过滤不需要的bean
private List<String> filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) { long startTime = System.nanoTime(); String[] candidates = StringUtils.toStringArray(configurations); boolean[] skip = new boolean[candidates.length]; boolean skipped = false; for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) { invokeAwareMethods(filter); boolean[] match = filter.match(candidates, autoConfigurationMetadata); for (int i = 0; i < match.length; i++) { if (!match[i]) { skip[i] = true; candidates[i] = null; skipped = true; } } } if (!skipped) { return configurations; } List<String> result = new ArrayList<>(candidates.length); for (int i = 0; i < candidates.length; i++) { if (!skip[i]) { result.add(candidates[i]); } } if (logger.isTraceEnabled()) { int numberFiltered = configurations.size() - result.size(); logger.trace("Filtered " + numberFiltered + " auto configuration class in " + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms"); } return new ArrayList<>(result); } protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() { return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader); }
fireAutoConfigurationImportEvents方法执行META-INF/spring.factories下配置的 AutoConfigurationImportListener类型的监听器
private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) { //获取到自动配置的监听器 List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners(); if (!listeners.isEmpty()) { AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions); for (AutoConfigurationImportListener listener : listeners) { //设置Aware invokeAwareMethods(listener); //执行监听器 listener.onAutoConfigurationImportEvent(event); } } } protected List<AutoConfigurationImportListener> getAutoConfigurationImportListeners() { return SpringFactoriesLoader.loadFactories(AutoConfigurationImportListener.class, this.beanClassLoader); }
AutoConfigurationGroup中的selectImports方法会将返回的类名数组注解为bean
@Override public Iterable<Entry> selectImports() { if (this.autoConfigurationEntries.isEmpty()) { return Collections.emptyList(); } //获取要排除的 Set<String> allExclusions = this.autoConfigurationEntries.stream() .map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet()); //获取到自动当前自动装配的属性 Set<String> processedConfigurations = this.autoConfigurationEntries.stream() .map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream) .collect(Collectors.toCollection(LinkedHashSet::new)); processedConfigurations.removeAll(allExclusions); //排序 return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream() .map((importClassName) -> new Entry(this.entries.get(importClassName), importClassName)) .collect(Collectors.toList()); }
这篇关于springboot源码分析-自动装配的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-26Mybatis官方生成器资料详解与应用教程
- 2024-11-26Mybatis一级缓存资料详解与实战教程
- 2024-11-26Mybatis一级缓存资料详解:新手快速入门
- 2024-11-26SpringBoot3+JDK17搭建后端资料详尽教程
- 2024-11-26Springboot单体架构搭建资料:新手入门教程
- 2024-11-26Springboot单体架构搭建资料详解与实战教程
- 2024-11-26Springboot框架资料:新手入门教程
- 2024-11-26Springboot企业级开发资料入门教程
- 2024-11-26SpringBoot企业级开发资料详解与实战教程
- 2024-11-26Springboot微服务资料:新手入门全攻略