Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

[pull] master from ipipman:master #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
pull merged 2 commits into Mu-L:master from ipipman:master
Jul 26, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 145 additions & 0 deletions springboot-source-code-analysis/(3)工厂加载机制解析.md
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,148 @@ public final class SpringFactoriesLoader {

<img src="https://tva1.sinaimg.cn/large/008i3skNly1grkdwk98bkj31bk0py4bt.jpg" alt="image-20210616203348022" align="left" width="500"/>



#### 源码阅读

##### 1、首先通过setInitializers#()方法设置系统初始化器

```java
@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 = WebApplicationType.deduceFromClasspath();
// 通过setInitializers#()方法,设置系统初始化器
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
```



##### 2、获取系统初始化器实现的全路径名,为它们创建实例子,最终把它们进行排序后注入到Spring容器集合中

```java
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
// 获得类加载器
ClassLoader classLoader = getClassLoader();
// 通过这个SpringFactoriesLoader#loadFactoryNames方法获取Spring中所有系统初始化器实现的全路径名
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 通过createSpringFactoriesInstances#()创建它们的实例
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
// 通过注解@Order进行排序
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
```



##### 3、获取系统初始化器实现的全路径名

```java
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 ?
// 获取 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);
// 通过url路径,获取spring.factories中的配置,并将其转成Properties格式
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryClassName = ((String) entry.getKey()).trim();
for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
// 将初始化器的包名进行返回
result.add(factoryClassName, factoryName.trim());
}
}
}
// 记录到缓存中
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
```



##### 4、创建初始化器的实例

```java
@SuppressWarnings("unchecked")
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<?> 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;
}
```



##### 5、按@Order注解进行排序

```java
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
// 按@Order注解进行排序,值约小的越靠前
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
```



##### 6、将初始化器排序好的实例注册到Spring容器中

```java
public void setInitializers(Collection<? extends ApplicationContextInitializer<?>> initializers) {
this.initializers = new ArrayList<>();
// 将初始化器的实例添加到Spring容器中
this.initializers.addAll(initializers);
}
```



#### 总结

- SpringFactoriesLoader作用: SpringBoot框架中从类路径jar包中读取特定的文件(META-INF/spring.factories)实现扩展类的载入

<img src="https://tva1.sinaimg.cn/large/008i3skNly1gsuhfrqk8gj31a40u0gnw.jpg" alt="image-20210726172128392" align="left" width="800" />

- LoadFactories流程

<img src="https://tva1.sinaimg.cn/large/008i3skNly1gsuhfn61gkj31660u0tbo.jpg" alt="image-20210726172754618" align="left" width="800" />

AltStyle によって変換されたページ (->オリジナル) /