spring boot自动配置
@SpringBootApplication
@SpringBootApplication注解是Spring Boot的核心注解,是一个组合注解,核心功能由@EnableAutoConfiguration注解提供.
@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 { }
@EnableAutoConfiguration
自动装配核心功能的实现实际是通过 AutoConfigurationImportSelector类
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { }
AutoConfigurationImportSelector:加载自动装配类
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered { } public interface DeferredImportSelector extends ImportSelector { } public interface ImportSelector { String[] selectImports(AnnotationMetadata var1); }
AutoConfigurationImportSelector 类实现ImportSelector接口,实现接口中的 selectImports方法,方法主要用于获取所有符合条件的类的全限定类名,类需要被加载到 IoC 容器中。
private static final String[] NO_IMPORTS = new String[0]; public String[] selectImports(AnnotationMetadata annotationMetadata) { // <1>.判断自动装配开关是否打开 if (!this.isEnabled(annotationMetadata)) { return NO_IMPORTS; } else { //<2>.获取所有需要装配的bean AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader); AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata,
annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); } }
重点关注一下getAutoConfigurationEntry()方法,主要负责加载自动配置类

getAutoConfigurationEntry()的源码
private static final AutoConfigurationEntry EMPTY_ENTRY = new AutoConfigurationEntry(); AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) { //<1>. if (!this.isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } else { //<2>. AnnotationAttributes attributes = this.getAttributes(annotationMetadata); //<3>. List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes); //<4>. 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); } }
判断自动装配开关是否打开。默认spring.boot.enableautoconfiguration=true,可在 application.properties 或 application.yml 中设置

第 2 步 :用于获取EnableAutoConfiguration注解中的 exclude 和 excludeName
第 3 步:获取需要自动装配的所有配置类,读取META-INF/spring.factories
/* 所有的配置都存放在configurations中,而这些配置都从getCandidateConfiguration中获取,这个方法是用来获取候选的配置。 */
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;
}
获取类路径下spring.factories下key为EnableAutoConfiguration全限定名对应值SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class,this.beanClassLoader))
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) { MultiValueMap<String, String> result = cache.get(classLoader); if (result != null) { return result; } try { 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()) { String factoryClassName = ((String) entry.getKey()).trim(); for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) { result.add(factoryClassName, factoryName.trim()); } } } cache.put(classLoader, result); return result; } catch (IOException ex) { throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } }
SpringBoot项目启动的时候,先导入AutoConfigurationImportSelector,这个类会帮选择所有候选的配置,需要导入的配置都是SpringBoot写好的一个一个的配置类,那么这些配置类的位置,存在与META-INF/spring.factories文件中,通过这个文件,Spring可以找到这些配置类的位置,于是去加载其中的配置。

@ConditionalOnXXX:如果其中的条件都满足,该类才会生效。
所以在加载自动配置类的时候,并不是将spring.factories的配置全量加载进来,而是通过这个注解的判断,如果注解中的类都存在,才会进行加载
RabbitAutoConfiguration
RabbitAutoConfiguration类上的注解:
@Configuration @ConditionalOnClass({ RabbitTemplate.class, Channel.class }) @EnableConfigurationProperties(RabbitProperties.class) @Import(RabbitAnnotationDrivenConfiguration.class) public class RabbitAutoConfiguration { }
@ConditionalOnClass:表示存在对应的Class文件时才会去解析RabbitAutoConfiguration,否则直接跳过不解析,这也是为什么在不导入RabbitMQ依赖Jar时工程能正常启动的原因
@EnableConfigurationProperties:表示对@ConfigurationProperties的内嵌支持,默认会将对应Class这是为bean,例如这里值为RabbitProperties.class,其定义为:
@ConfigurationProperties(prefix = "spring.rabbitmq") public class RabbitProperties { /** * RabbitMQ host. */ private String host = "localhost"; /** * RabbitMQ port. */ private int port = 5672; .... //省略部分代码}
RabbitProperties提供对RabbitMQ的配置信息,随后@EnableConfigurationProperties会将RabbitProperties注册为一个bean。
@Import为导入配置,RabbitAnnotationDrivenConfiguration具体实现如下:
@Configuration @ConditionalOnClass(EnableRabbit.class) class RabbitAnnotationDrivenConfiguration { @Autowired(required = false) private PlatformTransactionManager transactionManager; @Bean @ConditionalOnMissingBean(name = "rabbitListenerContainerFactory") public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory( ConnectionFactory connectionFactory) { SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory(); factory.setConnectionFactory(connectionFactory); if (this.transactionManager != null) { factory.setTransactionManager(this.transactionManager); } return factory; } @EnableRabbit @ConditionalOnMissingBean(name = RabbitListenerConfigUtils.RABBIT_LISTENER_ANNOTATION_PROCESSOR_BEAN_NAME) protected static class EnableRabbitConfiguration { } }
@ConditionalOnMissingBean,其功能为如果存在指定name的bean,则该注解标注的bean不创建,
再回到RabbitAutoConfiguration类的具体实现
@Configuration @ConditionalOnMissingBean(ConnectionFactory.class) protected static class RabbitConnectionFactoryCreator { @Bean public ConnectionFactory rabbitConnectionFactory(RabbitProperties config) { CachingConnectionFactory factory = new CachingConnectionFactory(); String addresses = config.getAddresses(); factory.setAddresses(addresses); if (config.getHost() != null) { factory.setHost(config.getHost()); factory.setPort(config.getPort()); } if (config.getUsername() != null) { factory.setUsername(config.getUsername()); } if (config.getPassword() != null) { factory.setPassword(config.getPassword()); } if (config.getVirtualHost() != null) { factory.setVirtualHost(config.getVirtualHost()); } return factory; } }
创建了默认的ConnectionFactory,需要注意的时,这里的ConnectionFactory无回调的设置
@Bean @ConditionalOnMissingBean(RabbitTemplate.class) public RabbitTemplate rabbitTemplate() { return new RabbitTemplate(this.connectionFactory); }
创建了默认的RabbitTemplate
浙公网安备 33010602011771号