首頁>技術>

@SpringbootApplication

這個註解標記的類為Springboot程式的主配置類,進入這個註解

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

可以發現有兩個註解比較關鍵**@SpringBootConfiguration** @EnableAutoConfiguration

根據字面意思為 Springboot配置 和 自動配置

@SpringBootConfiguration

進入這個註解

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Configurationpublic @interface SpringBootConfiguration {}

發現有@Configuration註解 該註解在Spring中也有接觸就是表示一個配置類的意思 javaConfig來代替applicationContext.xml這種配置檔案的

再進入@Configuration

@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Componentpublic @interface Configuration {}

發現有@Conponent註解 這是註解會被Spring自動裝載成bean元件

所以可以知道@SpringbootApplication這個註解標記的類是一個Spring的配置類,且會被註冊成bean@EnableAutoConfiguration

使能夠自動裝配

進入該註解

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@AutoConfigurationPackage@Import(AutoConfigurationImportSelector.class)public @interface EnableAutoConfiguration {}

有一個@AutoConfigurationPackage 和匯入了一個類@Import(AutoConfigurationImportSelector.class)

自動配置包註解 自動配置匯入選擇器@AutoConfigurationPackage

進入該註解

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

匯入了一個AutoConfigurationPackages.Registrar.class

自動配置包類的靜態內部類 註冊器類 打個的斷點debug

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {    //將註解元資料進行註冊 getPackageName		@Override		public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {			register(registry, new PackageImport(metadata).getPackageName());		}		@Override		public Set<Object> determineImports(AnnotationMetadata metadata) {			return Collections.singleton(new PackageImport(metadata));		}	}
可以發現已經能夠獲取到包名說白了就是將主配置類(即@SpringBootApplication標註的類)的所在包及子包裡面所有元件掃描載入到Spring容器。所以包名一定要注意。@Import(AutoConfigurationImportSelector.class)

進入該類

protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,			AnnotationMetadata annotationMetadata) {		if (!isEnabled(annotationMetadata)) {			return EMPTY_ENTRY;		}		AnnotationAttributes attributes = getAttributes(annotationMetadata);		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);		configurations = removeDuplicates(configurations);		Set<String> exclusions = getExclusions(annotationMetadata, attributes);		checkExcludedClasses(configurations, exclusions);		configurations.removeAll(exclusions);		configurations = filter(configurations, autoConfigurationMetadata);		fireAutoConfigurationImportEvents(configurations, exclusions);		return new AutoConfigurationEntry(configurations, exclusions);	}

List configurations = getCandidateConfigurations(annotationMetadata, attributes);

可發現配置都透過這個方法獲得

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;	}protected Class<?> getSpringFactoriesLoaderFactoryClass() {		return EnableAutoConfiguration.class;	}	protected ClassLoader getBeanClassLoader() {		return this.beanClassLoader;	}//進入SpringFactoriesLoader.loadFactoryNames()方法public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {		String factoryTypeName = factoryType.getName();		return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());	}//進入  loadSpringFactories(classLoader)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 ?                                                                          //public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";					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 factoryTypeName = ((String) entry.getKey()).trim();					for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {						result.add(factoryTypeName, factoryImplementationName.trim());					}				}			}			cache.put(classLoader, result);			return result;		}		catch (IOException ex) {			throw new IllegalArgumentException("Unable to load factories from location [" +					FACTORIES_RESOURCE_LOCATION + "]", ex);		}	}//public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

List configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());

透過ClassLoader載入使用了這個**@EnableAutoConfiguration**註解的類

這個方法會載入jar包中 META-INF/spring.factories 檔案中配置的配置物件

SpringBoot在啟動的時候從類路徑下的META-INF/spring.factories中獲取EnableAutoConfiguration指定的值,將這些值作為自動配置類匯入到容器中,自動配置類就生效,幫我們進行自動配置工作。以前我們需要自己配置的東西,自動配置類都幫我們完成了。

spring.factories檔案也是一組一組的key=value的形式,其中一個key是EnableAutoConfiguration類的全類名,而它的value是一個xxxxAutoConfiguration的類名的列表,這些類名以逗號分隔,如下圖所示:

接下來看看都匯入了哪些元件被新增到容器中

selectImports方法

@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());	}//進入 getAutoConfigurationEntry(autoConfigurationMetadata,annotationMetadata) 打個斷點看看;

可以看見每個要匯入的元件都以全類名的方法返回

@Conditional xxx

條件註解,透過判斷類路徑下有沒有相應配置的 jar 包來確定是否載入和自動配置這個類。

具體幾個@Conditon*註解的含義

@ConditionalOnBean : 僅僅在當前上下文中存在某個物件時,才會例項化一個Bean

@ConditionalOnMissingBean : DI容器中不存在該型別Bean時起效

@ConditionalOnClass : 某個class位於類路徑上,才會例項化一個Bean),該註解的引數對應的類必須存在,否則不解析該註解修飾的配置類

@ConditionalOnMissingClass : classpath中不存在該類時起效

@ConditionalOnExpression :當表示式為true的時候,才會例項化一個Bean

@ConditionalOnMissingBean :僅僅在當前上下文中不存在某個物件時,才會例項化一個Bean,該註解表示,如果存在它修飾的類的bean,則不需要再建立這個bean,可以給該註解傳入引數例如

@ConditionOnMissingBean(name = "example"),這個表示如果name為“example”的bean存在,這該註解修飾的程式碼塊不執行

@ConditionalOnMissingClass :某個class類路徑上不存在的時候,才會例項化一個Bean

@ConditionalOnSingleCandidate : DI容器中該型別Bean只有一個或@Primary的只有一個時起效

@ConditionalOnProperty : 引數設定或者值一致時起效

@ConditionalOnResource : 指定的檔案存在時起效

@ConditionalOnJndi : 指定的JNDI存在時起效

@ConditionalOnJava : 指定的Java版本存在時起效

@ConditionalOnWebApplication : Web應用環境下起效

@ConditionalOnNotWebApplication : 非Web應用環境下起效

結論SpringBoot在啟動的時候從類路徑下的META-INF/spring.factories中獲取EnableAutoConfiguration指定的值將這些值作為自動配置類匯入容器 , 自動配置類就生效 , 幫我們進行自動配置工作;整個J2EE的整體解決方案和自動配置都在springboot-autoconfigure的jar包中;它會給容器中匯入非常多的自動配置類 (xxxAutoConfiguration), 就是給容器中匯入這個場景需要的所有元件 , 並配置好這些元件 ;有了自動配置類 , 免去了我們手動編寫配置注入功能元件等的工作;SpringApplication.run分析

分析該方法主要分兩部分,一部分是SpringApplication的例項化,二是run方法的執行;

SpringApplication這個類主要做了以下四件事情:

1、推斷應用的型別是普通的專案還是Web專案

2、查詢並載入所有可用初始化器 , 設定到initializers屬性中

3、找出所有的應用程式監聽器,設定到listeners屬性中

4、推斷並設定main方法的定義類,找到執行的主類

檢視構造器:

public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {    // ......    this.webApplicationType = WebApplicationType.deduceFromClasspath();    this.setInitializers(this.getSpringFactoriesInstances();    this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));    this.mainApplicationClass = this.deduceMainApplicationClass();}
run 方法流程分析

14
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 效能高1倍,價格低3/4!資料庫實時同步新選擇