SpringBoot到Spring源碼分析之META-INF/spring.factories解析過程

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

說明:本章在以前章節《SpringBoot 啓動流程源碼分析》的基礎上進行繼續源碼分析。java

 

前面咱們分析到SpringApplication類的run方法,這個方法主要在頂層設計上定義了SpringBoot項目的整個啓動過程,同時包括了Spring容器的啓動過程。本章繼前面的基礎上繼續分析META-INF/spring.factories文件的加載過程,META-INF/spring.factories文件是springboot 框架識別並解析starter的核心文件,瞭解springboot加載META-INF/spring.factories文件原理相當重要。spring

 

SpringApplication類的run方法源碼:

  •  
public ConfigurableApplicationContext run(String... args) {
//建立程序計時器 StopWatch stopWatch = new StopWatch(); //啓動程序計時器 stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); //設置java.awt.headless系統屬性值 configureHeadlessProperty(); //從緩存的META-INF/spring.factories Map中獲取 //SpringApplicationRunListeners接口的全部子類 SpringApplicationRunListeners listeners = getRunListeners(args); //回調通知應用開始啓動事件監聽器 listeners.starting();      ...省略其它}

 

程序計數器new StopWatch()源碼分析:

  •  
public StopWatch() {   this("");}
public StopWatch(String id) { this.id = id;}
public void start() throws IllegalStateException { start("");}
public void start(String taskName) throws IllegalStateException { if (this.currentTaskName != null) { throw new IllegalStateException("Can't start StopWatch: it's already running"); } this.currentTaskName = taskName; this.startTimeNanos = System.nanoTime();}

 

java.awt.headless屬性配置源碼分析:

  •  
private static final String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS = "java.awt.headless";private boolean headless = true;
private void configureHeadlessProperty() { System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));}

 

getRunListeners(args)源碼分析,這是本章重點內容:數組

  •  
private SpringApplicationRunListeners getRunListeners(String[] args) {
//SpringApplicationRunListener實現類構造器參數類型數組 //默認實現類爲EventPublishingRunListener Class<?>[] types = new Class<?>[]{SpringApplication.class, String[].class};
//將SpringApplicationRunListener實現類封裝到SpringApplicationRunListeners //SpringApplicationRunListeners支持經過for全部事件list批量執行功能//後面分析starting方法時能夠看到for代碼 return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));}
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) { //須要查找的接口名稱字符串 String factoryClassName = factoryClass.getName(); //讀取磁盤文件進行加載,返回找到封裝結果的Map中key爲須要查找的接口名稱的values return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
//先從緩存查找當前classloader是否加載過 MultiValueMap<String, String> result = cache.get(classLoader); if (result != null) { //若是以前加載過就返回,這裏體驗了讀取文件資源實際作了緩存的 //後面都是從緩存讀取 return result; }
try {
//從當前classloader的classpath下讀取META-INF/spring.factories //封裝返回Enumeration迭代器 Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); result = new LinkedMultiValueMap<>();
//迭代全部META-INF/spring.factories文件 while (urls.hasMoreElements()) { URL url = urls.nextElement(); //將META-INF/spring.factories文件轉爲UrlResource對象 UrlResource resource = new UrlResource(url); //將META-INF/spring.factories文件從UrlResource對象轉爲Properties映射表 Properties properties = PropertiesLoaderUtils.loadProperties(resource); //遍歷META-INF/spring.factories文件entry for (Map.Entry<?, ?> entry : properties.entrySet()) { String factoryClassName = ((String) entry.getKey()).trim(); //遍歷value逗號分隔返回的String[] for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
//放到LinkedMultiValueMap,key爲接口全名稱字符串, //value爲接口實現類的全名稱字符串 result.add(factoryClassName, factoryName.trim()); } } } //保存到ConcurrentReferenceHashMap,key爲當前classloader //value爲全部META-INF/spring.factories文件k,v Map cache.put(classLoader, result); return result; } catch (IOException ex) { throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); }}
private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) { List<T> instances = new ArrayList<>(names.size()); for (String name : names) { try { //獲取Class對象 Class<?> instanceClass = ClassUtils.forName(name, classLoader); //類型判斷 Assert.isAssignable(type, instanceClass); //經過傳入的構造器參數信息獲取構造器 Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes); //實例化 T instance = (T) BeanUtils.instantiateClass(constructor, args); instances.add(instance); } catch (Throwable ex) { throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex); } } return instances;}

 

 

總結

 

  本文基於前面源碼分析文章繼續解讀了springboot讀取META-INF/spring.factories過程。經過classloader從classpath下讀取全部的META-INF/spring.factories文件,而後經過Map鍵值對數據結構保存在spring core模塊下的SpringFactoriesLoader抽象類的靜態屬性cache中。緩存

  •  
public abstract class SpringFactoriesLoader {
/** * 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";

private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class);
private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap<>(); ... 省略其它 }

 

後續全部須要從META-INF/spring.factories文件獲取都是嘗試先從這個緩存的Map中獲取。至於從META-INF/spring.factories文件獲取到各類不一樣接口的做用留到咱們後面繼續以分解式的方式獨立講解。springboot

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

相關文章
相關標籤/搜索