springboot源码之加载初始化器源码分析(一)

上一篇我们介绍了初始化器的使用方法

这次我们一起来看看初始化器的实现原理

因为初始化器的使用方式有三种,有表面上看的话,初始化器的加载原理也是略有不同的,本篇主要讲解的是使用spring.factories配置初始化器的原理,其他两种下篇继续讲解

我们首先要创建一个springboot的工程,然后启动进行源码追踪

package com.jun.lee;

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

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

 

我们进入到SpringApplication的run方法中,这里做了两个事情,一个就是实例化了SpringApplication类,并且调用了它的run方法

	/**
	 * Static helper that can be used to run a {@link SpringApplication} from the
	 * specified sources using default settings and user supplied arguments.
	 * @param primarySources the primary sources to load
	 * @param args the application arguments (usually passed from a Java main method)
	 * @return the running {@link ApplicationContext}
	 */
	public static ConfigurableApplicationContext run(Class[] primarySources,
			String[] args) {
		return new SpringApplication(primarySources).run(args);
	}

 

我们进入到SpringApplication的构造方法中,可以看到一个 setInitializers的方法,其中调用了getSpringFactoriesInstances的方法并传入了ApplicationContextInitializer的class类对象,这个类就是我们需要重点关注的

	@SuppressWarnings({ "unchecked", "rawtypes" })
	public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		this.webApplicationType = deduceWebApplicationType();
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}

 

我们进入getSpringFactoriesInstances方法,是一个重载方法,我们继续深入

private  Collection getSpringFactoriesInstances(Class type) {
		return getSpringFactoriesInstances(type, new Class[] {});
	}

 

在下面方法中就是初始化器做实现的重点方法

private  Collection getSpringFactoriesInstances(Class type,
			Class[] parameterTypes, Object... args) {
		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
		// Use names and ensure unique to protect against duplicates
		Set names = new LinkedHashSet<>(
                //加载初始化器
				SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        //实例化初始化器
		List instances = createSpringFactoriesInstances(type, parameterTypes,
				classLoader, args, names);
        //对初始化器进行排序
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}

 

我们深入SpringFactoriesLoader.loadFactoryNames(type, classLoader))方法,看看详细的加载过程

private static Map> loadSpringFactories(@Nullable ClassLoader classLoader) {
        //查询缓存
		MultiValueMap result = cache.get(classLoader);
		if (result != null)
			return result;
		try {
            //获取jar包下spring.factories文件的路径
			Enumeration 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);
                //解析每个spring.factories文件,封装为properties
				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                //遍历properties的kv结构
				for (Map.Entry entry : properties.entrySet()) {
                    //将多个value封装为集合结构
					List factoryClassNames = Arrays.asList(
							StringUtils.commaDelimitedListToStringArray((String) entry.getValue()));
					result.addAll((String) entry.getKey(), factoryClassNames);
				}
			}
            //加入到缓存中
			cache.put(classLoader, result);
			return result;
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load factories from location [" +
					FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
	}

 

接下来我们看看createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);方法

private  List createSpringFactoriesInstances(Class type,
			Class[] parameterTypes, ClassLoader classLoader, Object[] args,
			Set names) {
		List instances = new ArrayList<>(names.size());
        //遍历类名
		for (String name : names) {
			try {
				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;
	}

最后执行AnnotationAwareOrderComparator.sort(instances);方法进行排序

public static void sort(List list) {
		if (list.size() > 1) {
			list.sort(INSTANCE);
		}
	}

 

到此初始化器加载完成

你可能感兴趣的:(springboot)