Spring Boot是由Pivotal團(tuán)隊(duì)提供的全新框架偷溺,其設(shè)計(jì)目的是用來(lái)簡(jiǎn)化新Spring應(yīng)用的初始搭建以及開發(fā)過(guò)程挺身。該框架使用了特定的方式來(lái)進(jìn)行配置,從而使開發(fā)人員不再需要定義樣板化的配置蒿囤。通過(guò)這種方式从隆,Spring Boot致力于在蓬勃發(fā)展的快速應(yīng)用開發(fā)領(lǐng)域(rapid application development)成為領(lǐng)導(dǎo)者。
Spring Boot特點(diǎn)
1. 創(chuàng)建獨(dú)立的Spring應(yīng)用程序
2. 嵌入的Tomcat果复,無(wú)需部署WAR文件
3. 簡(jiǎn)化Maven配置
4. 自動(dòng)配置Spring
5. 提供生產(chǎn)就緒型功能陈莽,如指標(biāo),健康檢查和外部配置
6. 絕對(duì)沒(méi)有代碼生成和對(duì)XML沒(méi)有要求配置
安裝Spring Boot
從最根本上來(lái)講据悔,Spring Boot就是一些庫(kù)的集合传透,它能夠被任意項(xiàng)目的構(gòu)建系統(tǒng)所使用。簡(jiǎn)便起見(jiàn)极颓,該框架也提供了命令行界面朱盐,它可以用來(lái)運(yùn)行和測(cè)試Boot應(yīng)用〔ぢ。框架的發(fā)布版本兵琳,包括集成的CLI(命令行界面),可以在Spring倉(cāng)庫(kù)中手動(dòng)下載和安裝骇径。一種更為簡(jiǎn)便的方式是使用Groovy環(huán)境管理器(Groovy enVironment Manager躯肌,GVM),它會(huì)處理Boot版本的安裝和管理破衔。Boot及其CLI可以通過(guò)GVM的命令行g(shù)vm install springboot進(jìn)行安裝清女。在OS X上安裝Boot可以使用Homebrew包管理器。為了完成安裝晰筛,首先要使用brew tap pivotal/tap切換到Pivotal倉(cāng)庫(kù)中嫡丙,然后執(zhí)行brew install springboot命令拴袭。
要進(jìn)行打包和分發(fā)的工程會(huì)依賴于像 Maven或 Gradle這樣的構(gòu)建系統(tǒng)。為了簡(jiǎn)化依賴圖曙博,Boot的功能是模塊化的拥刻,通過(guò)導(dǎo)入Boot所謂的“starter”模塊,可以將許多的依賴添加到工程之中父泳。為了更容易地管理依賴版本和使用默認(rèn)配置般哼,框架提供了一個(gè)parent POM,工程可以繼承它惠窄。
SpringBoot 知識(shí)點(diǎn)匯總
SpringBoot 自動(dòng)配置的原理蒸眠?
首先自動(dòng)配置是配置
spring-boot-autoconfigure-2.0.4.RELEASE.jar包下MATA-INF下的spring.properties 文件中org.springframework.boot.autoconfigure.EnableAutoConfiguration所對(duì)應(yīng)自動(dòng)配置類。
其次springBoot啟動(dòng)類中的@springBootApplication隱含的引入了
EnableAutoConfigurationImportSelector;
// 注解鏈
@SpringBootApplication
=> @EnableAutoConfiguration
=> @Import(EnableAutoConfigurationImportSelector.class)
在SpringApplication的run方法中睬捶,會(huì)調(diào)context = createApplicationContext();在實(shí)例化這個(gè)
ConfigurableApplicationContext時(shí)黔宛,不管是AnnotationConfigEmbeddedWebApplicationContext或AnnotationConfigApplicationContext時(shí)(這兩個(gè)類是專門處理Spring注解方式配置的容器,直接依賴于注解作為容器配置信息來(lái)源的IoC容器擒贸。?AnnotationConfigWebApplicationContext是AnnotationConfigApplicationContext的web版本臀晃,兩者的用法以及對(duì)注解的處理方式幾乎沒(méi)有什么差別),都會(huì)實(shí)例化一個(gè)AnnotatedBeanDefinitionReader介劫。例如AnnotationConfigEmbeddedWebApplicationContext實(shí)例化代碼:
public AnnotationConfigEmbeddedWebApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
這里將構(gòu)造
AnnotatedBeanDefinitionReader徽惋,在AnnotatedBeanDefinitionReader實(shí)例化過(guò)程中,會(huì)向beanFactory注冊(cè)CommonAnnotationBeanPostProcessor座韵、AutowiredAnnotationBeanPostProcessor险绘、ConfigurationClassPostProcessor等:
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
Assert.notNull(environment, "Environment must not be null");
this.registry = registry;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, Object source) {
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
if (beanFactory != null) {
if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
}
if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
}
}
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<BeanDefinitionHolder>(4);
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition();
try {
def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
AnnotationConfigUtils.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
}
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
}
return beanDefs;
}
也就是說(shuō)createApplicationContext()完后,beanFactory的beanDefinitionMap會(huì)有6個(gè)值誉碴。
SpringApplication的run方法中宦棺,在調(diào)用createApplicationContext();后會(huì)調(diào)用prepareContext(context, environment, listeners, applicationArguments,printedBanner):
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
// ….
// Load the sources
Set<Object> sources = getSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[sources.size()]));
listeners.contextLoaded(context);
}
getSources()返回的就是new SpringApplication(Application.class)傳入的參數(shù),即我們的主類黔帕,然后調(diào)用了load()方法代咸,在load()中會(huì)生成BeanDefinitionLoader實(shí)例,并把主類注冊(cè)到IOC容器中成黄。
OK呐芥,到這里即在調(diào)用我們熟悉的
AbstractApplicationContext#refresh()前,beanFactory有7個(gè)定義好的beanDefinition奋岁。
public void refresh() throws BeansException, IllegalStateException {
Object var1 = this.startupShutdownMonitor;
synchronized(this.startupShutdownMonitor) {
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
this.postProcessBeanFactory(beanFactory);
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
ConfigurationClassPostProcessor是BeanFactoryPostProcessor的子類思瘟,會(huì)在Spring容器refresh時(shí),invokeBeanFactoryPostProcessors(beanFactory)方法中調(diào)用到闻伶。ConfigurationClassPostProcessor會(huì)解析到我們的主類滨攻,把@Import中的類拿出來(lái),調(diào)用它的selectImports()方法。
ConfigurationClassPostProcessor 中ConfigurationClassParser分析配置類時(shí)铡买,如果發(fā)現(xiàn)注@Import(ImportSelector)的情況更鲁,就會(huì)創(chuàng)建一個(gè)相應(yīng)的ImportSelector對(duì)象霎箍, 并調(diào)用其方法 public String[] selectImports(AnnotationMetadata annotationMetadata), 這里?EnableAutoConfigurationImportSelector的導(dǎo)入@Import(EnableAutoConfigurationImportSelector.class) 就屬于這種情況,所以ConfigurationClassParser會(huì)實(shí)例化一個(gè)?EnableAutoConfigurationImportSelector 并調(diào)用它的 selectImports() 方法奇钞。
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException("postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
} else if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException("postProcessBeanFactory already called on this post-processor against " + registry);
} else {
this.registriesPostProcessed.add(registryId);
this.processConfigBeanDefinitions(registry);
}
} //BeanFactoryPostProcessor接口唯一的方法,被ConfigurationClassPostProcessor實(shí)現(xiàn)了漂坏;
//該方法中對(duì)配置類中的@import中的類進(jìn)行解析
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList();
String[] candidateNames = registry.getBeanDefinitionNames();
String[] var4 = candidateNames;
int var5 = candidateNames.length;
for(int var6 = 0; var6 < var5; ++var6) {
String beanName = var4[var6];
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (!ConfigurationClassUtils.isFullConfigurationClass(beanDef) && !ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
} else if (this.logger.isDebugEnabled()) {
this.logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
if (!configCandidates.isEmpty()) {
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry)registry;
if (!this.localBeanNameGeneratorSet) {
BeanNameGenerator generator = (BeanNameGenerator)sbr.getSingleton("org.springframework.context.annotation.internalConfigurationBeanNameGenerator");
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}
if (this.environment == null) {
this.environment = new StandardEnvironment();
}
ConfigurationClassParser parser = new ConfigurationClassParser(this.metadataReaderFactory, this.problemReporter, this.environment, this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet(configCandidates);
HashSet alreadyParsed = new HashSet(configCandidates.size());
do {
parser.parse(candidates);
parser.validate();
Set<ConfigurationClass> configClasses = new LinkedHashSet(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(registry, this.sourceExtractor, this.resourceLoader, this.environment, this.importBeanNameGenerator, parser.getImportRegistry());
}
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet();
Iterator var12 = alreadyParsed.iterator();
while(var12.hasNext()) {
ConfigurationClass configurationClass = (ConfigurationClass)var12.next();
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
String[] var23 = newCandidateNames;
int var24 = newCandidateNames.length;
for(int var14 = 0; var14 < var24; ++var14) {
String candidateName = var23[var14];
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) && !alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
} while(!candidates.isEmpty());
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
((CachingMetadataReaderFactory)this.metadataReaderFactory).clearCache();
}
}
}
public void parse(Set<BeanDefinitionHolder> configCandidates) {
this.deferredImportSelectors = new LinkedList();
Iterator var2 = configCandidates.iterator();
while(var2.hasNext()) {
BeanDefinitionHolder holder = (BeanDefinitionHolder)var2.next();
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
this.parse(((AnnotatedBeanDefinition)bd).getMetadata(), holder.getBeanName());
} else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition)bd).hasBeanClass()) {
this.parse(((AbstractBeanDefinition)bd).getBeanClass(), holder.getBeanName());
} else {
this.parse(bd.getBeanClassName(), holder.getBeanName());
}
} catch (BeanDefinitionStoreException var6) {
throw var6;
} catch (Throwable var7) {
throw new BeanDefinitionStoreException("Failed to parse configuration class [" + bd.getBeanClassName() + "]", var7);
}
}
this.processDeferredImportSelectors();
}
private void processDeferredImportSelectors() {
List<ConfigurationClassParser.DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
this.deferredImportSelectors = null;
if (deferredImports != null) {
deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
Map<Object, ConfigurationClassParser.DeferredImportSelectorGrouping> groupings = new LinkedHashMap();
Map<AnnotationMetadata, ConfigurationClass> configurationClasses = new HashMap();
Iterator var4 = deferredImports.iterator();
while(var4.hasNext()) {
ConfigurationClassParser.DeferredImportSelectorHolder deferredImport = (ConfigurationClassParser.DeferredImportSelectorHolder)var4.next();
Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
ConfigurationClassParser.DeferredImportSelectorGrouping grouping = (ConfigurationClassParser.DeferredImportSelectorGrouping)groupings.computeIfAbsent(group != null ? group : deferredImport, (key) -> {
return new ConfigurationClassParser.DeferredImportSelectorGrouping(this.createGroup(group));
});
grouping.add(deferredImport);
configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(), deferredImport.getConfigurationClass());
}
var4 = groupings.values().iterator();
while(var4.hasNext()) {
ConfigurationClassParser.DeferredImportSelectorGrouping grouping = (ConfigurationClassParser.DeferredImportSelectorGrouping)var4.next();
grouping.getImports().forEach((entry) -> {
ConfigurationClass configurationClass = (ConfigurationClass)configurationClasses.get(entry.getMetadata());
try {
this.processImports(configurationClass, this.asSourceClass(configurationClass), this.asSourceClasses(entry.getImportClassName()), false); //調(diào)用processImports方法
} catch (BeanDefinitionStoreException var5) {
throw var5;
} catch (Throwable var6) {
throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" + configurationClass.getMetadata().getClassName() + "]", var6);
}
});
}
}
}
private void processImports(ConfigurationClass configClass, ConfigurationClassParser.SourceClass currentSourceClass, Collection<ConfigurationClassParser.SourceClass> importCandidates, boolean checkForCircularImports) {
if (!importCandidates.isEmpty()) {
if (checkForCircularImports && this.isChainedImportOnStack(configClass)) {
this.problemReporter.error(new ConfigurationClassParser.CircularImportProblem(configClass, this.importStack));
} else {
this.importStack.push(configClass);
try {
Iterator var5 = importCandidates.iterator();
while(true) {
while(true) {
while(var5.hasNext()) {
ConfigurationClassParser.SourceClass candidate = (ConfigurationClassParser.SourceClass)var5.next();
Class candidateClass;
if (candidate.isAssignable(ImportSelector.class)) {
candidateClass = candidate.loadClass();
ImportSelector selector = (ImportSelector)BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
ParserStrategyUtils.invokeAwareMethods(selector, this.environment, this.resourceLoader, this.registry);
if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
this.deferredImportSelectors.add(new ConfigurationClassParser.DeferredImportSelectorHolder(configClass, (DeferredImportSelector)selector));
} else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); //執(zhí)行@import類的selectImports方法景埃;
Collection<ConfigurationClassParser.SourceClass> importSourceClasses = this.asSourceClasses(importClassNames);
this.processImports(configClass, currentSourceClass, importSourceClasses, false);
}
} else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar = (ImportBeanDefinitionRegistrar)BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
ParserStrategyUtils.invokeAwareMethods(registrar, this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
} else {
this.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
this.processConfigurationClass(candidate.asConfigClass(configClass));
}
}
return;
}
}
} catch (BeanDefinitionStoreException var15) {
throw var15;
} catch (Throwable var16) {
throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" + configClass.getMetadata().getClassName() + "]", var16);
} finally {
this.importStack.pop();
}
}
}
}
// selectImports 的具體執(zhí)行邏輯 注釋參考https://blog.csdn.net/andy_zhang2007/article/details/78580980
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
try {
// 從配置文件中加載 AutoConfigurationMetadata
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 獲取所有候選配置類EnableAutoConfiguration
// 使用了內(nèi)部工具使用SpringFactoriesLoader,查找classpath上所有jar包中的
// META-INF\spring.factories顶别,找出其中key為
// org.springframework.boot.autoconfigure.EnableAutoConfiguration
// 的屬性定義的工廠類名稱谷徙。
// 雖然參數(shù)有annotationMetadata,attributes,但在 AutoConfigurationImportSelector 的
// 實(shí)現(xiàn) getCandidateConfigurations()中,這兩個(gè)參數(shù)并未使用
List<String> configurations = getCandidateConfigurations(annotationMetadata,
attributes);
// 去重
configurations = removeDuplicates(configurations);
// 排序 : 先按字典序驯绎,再按order屬性完慧,再考慮注解 @AutoConfigureBefore @AutoConfigureAfter
configurations = sort(configurations, autoConfigurationMetadata);
// 應(yīng)用 exclusion 屬性
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
// 應(yīng)用過(guò)濾器AutoConfigurationImportFilter,
// 對(duì)于 spring boot autoconfigure剩失,定義了一個(gè)需要被應(yīng)用的過(guò)濾器 :
// org.springframework.boot.autoconfigure.condition.OnClassCondition屈尼,
// 此過(guò)濾器檢查候選配置類上的注解@ConditionalOnClass,如果要求的類在classpath
// 中不存在拴孤,則這個(gè)候選配置類會(huì)被排除掉
configurations = filter(configurations, autoConfigurationMetadata);
// 現(xiàn)在已經(jīng)找到所有需要被應(yīng)用的候選配置類
// 廣播事件 AutoConfigurationImportEvent
fireAutoConfigurationImportEvents(configurations, exclusions);
return configurations.toArray(new String[configurations.size()]);
}
catch (IOException ex) {
throw new IllegalStateException(ex);
}
}
/**
* Return the auto-configuration class names that should be considered. By default
* this method will load candidates using SpringFactoriesLoader with
* getSpringFactoriesLoaderFactoryClass().
* @param metadata the source metadata
* @param attributes the 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;
}
/**
* Return the class used by SpringFactoriesLoader to load configuration
* candidates.
* @return the factory class
*/
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
/**
* 根據(jù)autoConfigurationMetadata信息對(duì)候選配置類configurations進(jìn)行過(guò)濾
**/
private List<String> filter(List<String> configurations,
AutoConfigurationMetadata autoConfigurationMetadata) {
long startTime = System.nanoTime();
String[] candidates = configurations.toArray(new String[configurations.size()]);
// 記錄候選配置類是否需要被排除,skip為true表示需要被排除,全部初始化為false,不需要被排除
boolean[] skip = new boolean[candidates.length];
// 記錄候選配置類中是否有任何一個(gè)候選配置類被忽略脾歧,初始化為false
boolean skipped = false;
// 獲取AutoConfigurationImportFilter并逐個(gè)應(yīng)用過(guò)濾
for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
// 對(duì)過(guò)濾器注入其需要Aware的信息
invokeAwareMethods(filter);
// 使用此過(guò)濾器檢查候選配置類跟autoConfigurationMetadata的匹配情況
boolean[] match = filter.match(candidates, autoConfigurationMetadata);
for (int i = 0; i < match.length; i++) {
if (!match[i]) {
// 如果有某個(gè)候選配置類不符合當(dāng)前過(guò)濾器,將其標(biāo)記為需要被排除演熟,
// 并且將 skipped設(shè)置為true鞭执,表示發(fā)現(xiàn)了某個(gè)候選配置類需要被排除
skip[i] = true;
skipped = true;
}
}
}
if (!skipped) {
// 如果所有的候選配置類都不需要被排除,則直接返回外部參數(shù)提供的候選配置類集合
return configurations;
}
// 邏輯走到這里因?yàn)閟kipped為true芒粹,表明上面的的過(guò)濾器應(yīng)用邏輯中發(fā)現(xiàn)了某些候選配置類
// 需要被排除兄纺,這里排除那些需要被排除的候選配置類,將那些不需要被排除的候選配置類組成
// 一個(gè)新的集合返回給調(diào)用者
List<String> result = new ArrayList<String>(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<String>(result);
}
/**
* 使用內(nèi)部工具 SpringFactoriesLoader化漆,查找classpath上所有jar包中的
* META-INF\spring.factories估脆,找出其中key為
* org.springframework.boot.autoconfigure.AutoConfigurationImportFilter
* 的屬性定義的過(guò)濾器類并實(shí)例化。
* AutoConfigurationImportFilter過(guò)濾器可以被注冊(cè)到 spring.factories用于對(duì)自動(dòng)配置類
* 做一些限制获三,在這些自動(dòng)配置類的字節(jié)碼被讀取之前做快速排除處理旁蔼。
* spring boot autoconfigure 缺省注冊(cè)了一個(gè) AutoConfigurationImportFilter :
* org.springframework.boot.autoconfigure.condition.OnClassCondition
**/
protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class,
this.beanClassLoader);
}
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();
List<String> factoryClassNames = Arrays.asList(StringUtils.commaDelimitedListToStringArray((String)entry.getValue()));
result.addAll((String)entry.getKey(), factoryClassNames);
}
}
cache.put(classLoader, result);
return result;
} catch (IOException var9) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var9);
}
}
}
而loadSpringFactories會(huì)掃描所有jar包下的 META‐INF/spring.factories文件,并封裝成properties屬性對(duì)象疙教;并以key-value的形式存放在MultiValueMap對(duì)象中棺聊,List configurations =?
getCandidateConfigurations(annotationMetadata, attributes);獲取候選的配置時(shí),只需要獲取key為org.springframework.boot.autoconfigure.EnableAutoConfiguration的list保存的value,然后返回到processImports方法中贞谓,最終注冊(cè)到IOC容器中限佩;整個(gè)自動(dòng)配置結(jié)束;