springboot 加載 META-INF/spring.factories方式
springboot 加載 META-INF/spring.factories
用戶應(yīng)用程序Application
ConfigurableApplicationContext context = SpringApplication.run(NacosSpringBootYamlApplication.class, args);
SpringApplication類
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) { return run(new Class<?>[] { primarySource }, args); }
// 這里Class是數(shù)組 public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) { return new SpringApplication(primarySources).run(args); }
public SpringApplication(Class<?>... primarySources) { this(null, primarySources); }
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); // 這里就是SpringMvcApplication的實(shí)例 this.webApplicationType = WebApplicationType.deduceFromClasspath();// deduce(推斷)web類型(servlet、reactive、NoWeb) setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));// 這里會(huì)處理加載所有的spring.factories文件的內(nèi)容到緩存 找到*META-INF/spring.factories*中聲明的所有ApplicationContextInitializer的實(shí)現(xiàn)類并將其實(shí)例化 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); //找到*META-INF/spring.factories*中聲明的所有ApplicationListener的實(shí)現(xiàn)類并將其實(shí)例化 this.mainApplicationClass = deduceMainApplicationClass(); //獲得當(dāng)前執(zhí)行main方法的類對(duì)象,這里就是SpringMvcApplication的實(shí)例 }
具體加載該classLoader下的所有spring.factories到緩存
如果緩存已經(jīng)存在,則直接根據(jù)key,返回?cái)?shù)據(jù)
/** key:是spring.factories的key value:是根據(jù)key分組,把同個(gè)key的不同value放到list里面 */ private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) { MultiValueMap<String, String> result = cache.get(classLoader); if (result != null) { //已經(jīng)處理過了 直接返回 return result; } //url: // file:/C:/Users/kongqi/.m2/repository/org/springframework/spring-beans/5.1.9.RELEASE/spring-beans-5.1.9.RELEASE.jar!/META-INF/spring.factories try { //得到classloader下的所有jar包中的spring.factories的文件 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); // 得到spring.factories的內(nèi)容 for (Map.Entry<?, ?> entry : properties.entrySet()) { // key: spring.factories的key value: spring.factories的value String factoryClassName = ((String) entry.getKey()).trim(); // spring.factories的key for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {//value根據(jù)逗號(hào),分隔 result.add(factoryClassName, factoryName.trim()); //factoryClassName其實(shí)就是spring.factories的key 由于value是List類型 MultiValueMap value有多個(gè) } } } cache.put(classLoader, result); return result; } catch (IOException ex) { throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } }
流程圖
建立META-INF/spring.factories文件的意義何在
平常我們?nèi)绾螌ean注入到容器當(dāng)中
@Configuration @EnableConfigurationProperties(HelloProperties.class) public class HelloServiceAutoConfiguration { @Autowired HelloProperties helloProperties; @Bean public HelloService helloService() { HelloService service = new HelloService(); service.setHelloProperties( helloProperties ); return service; } }
一般就建立配置文件使用@Configuration,里面通過@Bean進(jìn)行加載bean
或者使用@Compont注解在類上進(jìn)行類的注入
注意:
在我們主程序入口的時(shí)候:
@SpringBootApplication這個(gè)注解里面的東西
@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
@ComponentScan注解指掃描@SpringBootApplication注解的入口程序類所在的basepackage下的
所有帶有@Component注解的bean,從而注入到容器當(dāng)中。
但是
如果是加入maven坐標(biāo)依賴的jar包,就是項(xiàng)目根目錄以外的Bean是怎么添加的??
這個(gè)時(shí)候注解@EnableAutoConfiguration的作用就來了
導(dǎo)入了AutoConfigurationImportSelector這個(gè)類:
這個(gè)類里面有一個(gè)方法
/** * Return the auto-configuration class names that should be considered. By default * this method will load candidates using {@link SpringFactoriesLoader} with * {@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; }
@EnableAutoConfiguration注解來注冊(cè)項(xiàng)目包外的bean。而spring.factories文件,則是用來記錄項(xiàng)目包外需要注冊(cè)的bean類名
為什么需要spring.factories文件,
因?yàn)槲覀冋麄€(gè)項(xiàng)目里面的入口文件只會(huì)掃描整個(gè)項(xiàng)目里面下的@Compont @Configuration等注解
但是如果我們是引用了其他jar包,而其他jar包只有@Bean或者@Compont等注解,是不會(huì)掃描到的。
除非你引入的jar包沒有Bean加載到容器當(dāng)中
所以我們是通過寫/META-INF/spring.factories文件去進(jìn)行加載的。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- Spring中的spring.factories文件用法(Spring如何加載第三方Bean)
- springboot自動(dòng)配置原理以及spring.factories文件的作用詳解
- SpringBoot借助spring.factories文件跨模塊實(shí)例化Bean
- 關(guān)于SpringBoot3.x中spring.factories功能被移除的解決方案
- SpringBoot?spring.factories加載時(shí)機(jī)分析
- springBoot?之spring.factories擴(kuò)展機(jī)制示例解析
- SpringBoot 自動(dòng)掃描第三方包及spring.factories失效的問題解決
- SpringBoot3.x中spring.factories?SPI?服務(wù)發(fā)現(xiàn)機(jī)制的改變問題小結(jié)
- SpringBoot之spring.factories的使用方式
- 在SpringBoot3中spring.factories配置不起作用的原因和解決方法
- 淺談spring.factories文件的作用
相關(guān)文章
詳解Servlet入門級(jí)設(shè)置(超詳細(xì) IDEA2020版)
這篇文章主要介紹了詳解Servlet入門級(jí)設(shè)置(超詳細(xì) IDEA2020版),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11深入理解spring boot異步調(diào)用方式@Async
Spring為任務(wù)調(diào)度與異步方法執(zhí)行提供了注解支持。通過在方法上設(shè)置@Async注解,可使得方法被異步調(diào)用。下面這篇文章主要給大家介紹了關(guān)于spring boot異步調(diào)用方式@Async的相關(guān)資料,需要的朋友可以參考下。2017-07-07