系统初始化器

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.lang.NonNull;

/**
 * @author itning
 * @date 2020/4/28 20:43
 */
@Order(1)
public class FirstApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(@NonNull ConfigurableApplicationContext applicationContext) {
        System.out.println("FirstApplicationContextInitializer");
    }
}

实现ApplicationContextInitializer接口即可,并且必须是ConfigurableApplicationContext子类

如何使其生效?三种方式:

  1. 关键代码:springApplication.addInitializers(new FirstApplicationContextInitializer());

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import top.itning.springboottest.config.FirstApplicationContextInitializer;
    
    /**
    * @author itning
    */
    @SpringBootApplication
    public class SpringbootTestApplication {
       public static void main(String[] args) {
           //SpringApplication.run(SpringbootTestApplication.class, args);
           SpringApplication springApplication = new SpringApplication(SpringbootTestApplication.class);
           springApplication.addInitializers(new FirstApplicationContextInitializer());
           springApplication.run(args);
       }
    }
    
  2. 只需要在应用配置文件中application.yml配置:context.initializer.classes=xxx.xxx.xxx.XX

    1
    2
    3
    
    context:
     initializer:
       classes: xxx.xxx.xxx.XX
    
  3. resources目录新建META-INF文件夹并且新建文件:spring.factories

    1
    
    org.springframeword.context.ApplicationContextInitializer=xxx.xxx.xxx.XX
    

源码解析;

1
2
3
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
		return new SpringApplication(primarySources).run(args);
}

实例化SpringApplication的代码:

1
2
3
4
5
6
7
8
9
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((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
}

关键代码:setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));

1
2
3
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
		return getSpringFactoriesInstances(type, new Class<?>[] {});
}

泛型T即为ApplicationContextInitializer

1
2
3
4
5
6
7
8
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);
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
}

首先,获得类加载器:ClassLoader classLoader = getClassLoader();

然后,Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));通过调用静态方法SpringFactoriesLoader.loadFactoryNames(type, classLoader)来获得所有定义org.springframeword.context.ApplicationContextInitializer的值

最后进行排序。

当调用run()方法时:

1
prepareContext(context, environment, listeners, applicationArguments, printedBanner);

会调用

1
applyInitializers(context);

同过for循环来调用initialize方法:

1
2
3
4
5
6
7
8
protected void applyInitializers(ConfigurableApplicationContext context) {
		for (ApplicationContextInitializer initializer : getInitializers()) {
			Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
					ApplicationContextInitializer.class);
			Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
			initializer.initialize(context);
		}
}

其中第一个被调用initialize的类是org.springframework.boot.context.config.DelegatingApplicationContextInitializer,该类会加载在application.yml中属性为private static final String PROPERTY_NAME = "context.initializer.classes";的类并进行调用initialize方法

springApplication.addInitializers(new FirstApplicationContextInitializer());直接将参数加入到List集合中。

1
2
3
4
5
private List<ApplicationContextInitializer<?>> initializers;

public void addInitializers(ApplicationContextInitializer<?>... initializers) {
		this.initializers.addAll(Arrays.asList(initializers));
}