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=

相关文章
相关标签/搜索