springboot2.0 主程序類@SpringBootApplication詳解,@SpringBootConfiguration,@EnableAutoConfiguration

1.創建一個springboot項目

《 spring boot2.0 第一個程序《快速開始》》

2.項目主類入口

package com.badger.web;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringbootHelloApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootHelloApplication.class, args);
    }
}

我們首先springboot的第一個註解@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 {

	//自動注入的時候,排序的類
	@AliasFor(annotation = EnableAutoConfiguration.class)
	Class<?>[] exclude() default {};

	//自動注入的時候,排序的類的名字
	@AliasFor(annotation = EnableAutoConfiguration.class)
	String[] excludeName() default {};

	//自動注入的時候,掃描的包路徑	
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
	String[] scanBasePackages() default {};

	//自動注入的時候,掃描的類註解(@Service,@Controller等)
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
	Class<?>[] scanBasePackageClasses() default {};

}

我們可以看到,@SpringBootApplication註解,是三個組合註解:@SpringBootConfiguration  @EnableAutoConfiguration @ComponentScan

1)@SpringBootConfiguration:標註這個類是一個配置類

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {

}

可以看到,這個註解,只是@Configuration註解的派生註解,跟@Configuration註解的功能一致,標註這個類是一個配置類,只不過@SpringBootConfiguration是springboot的註解,而@Configuration是spring的註解,關於@Configuration註解,更詳細的,可以參看《spring註解 @Conditional的使用》

《springboot2.0 @Conditional派生註解@ConditionalOnMissingBean,@ConditionalOnProperty等詳解》

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 {};

}

@EnableAutoConfiguration註解,又是一個組合註解:@AutoConfigurationPackage和@Import(AutoConfigurationImportSelector.class)

@Import(AutoConfigurationImportSelector.class) 導入AutoConfigurationImportSelector.class類

關於@Import註解,可以像@Configuration導入類或者組件,導入類,分三種

  1. 直接導入普通的類
  2. 導入實現了ImportSelector接口的類
  3. 導入實現了ImportBeanDefinitionRegistrar接口的類

可以詳細參考《spring註解 @Import的使用,ImportSelector接口,ImportBeanDefinitionRegistrar接口》

AutoConfigurationImportSelector.class的作用

	@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
		AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
				.loadMetadata(this.beanClassLoader);
		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(
				autoConfigurationMetadata, annotationMetadata);
		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
	}

 直接看重寫的public String[] selectImports(AnnotationMetadata annotationMetadata)方法,查看getAutoConfigurationEntry法

AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(
				autoConfigurationMetadata, annotationMetadata);

 

查看getCandidateConfigurations方法,根據條件配置

 可以看到,加載文件到list中,查看SpringFactoriesLoader.loadFactoryNames的方法

最終,會拿到所有的類的全路徑,然後反射實例化bean,並注入到spring容器中,靜態變量就是獲取文件的路徑

META-INF/spring.factories

/**
	 * The location to look for factories.
	 * <p>Can be present in multiple JAR files.
	 */
	public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

 

這個部分,也是springboot自動裝配的整個過程 

@AutoConfigurationPackage註解:自動配置包

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {

}

@AutoConfigurationPackage註解,自動注入主類下所在包下(com.badger.web.SpringbootHelloApplication),所有的加了註解的類(@Controller,@Service等),以及配置類(@Configuration)

可以看到,就是@Import(AutoConfigurationPackages.Registrar.class)註解,導入(實例化)一個AutoConfigurationPackages.Registrar.class類;

我們直接看這個AutoConfigurationPackages.Registrar.class類的一些簡單實現

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

		@Override
		public void registerBeanDefinitions(AnnotationMetadata metadata,
				BeanDefinitionRegistry registry) {
            //new PackageImport(metadata).getPackageName() 掃描主類包下的所有的類 ,
            //並且注入到spring容器
			register(registry, new PackageImport(metadata).getPackageName());
		}

		@Override
		public Set<Object> determineImports(AnnotationMetadata metadata) {
			return Collections.singleton(new PackageImport(metadata));
		}

	}

,感興趣的,可以繼續看下 

register(registry, new PackageImport(metadata).getPackageName());

3) @ComponentScan註解:包掃描

大家詳細參看《spring註解 @ComponentScan,@ComponentScans 以及@Filter的使用》就可以了 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章