시리즈 소스 스프링 부팅 2의 (a) - 시스템 초기화 ApplicationContextInitializer입니다

ApplicationContextInitializer 문서 인터페이스는 이렇게 작성된 것입니다 :

1, ApplicationContextInitializer는 콜백 인터페이스 () ConfigurableApplicationContext # 1 리프레시 전에 ConfigurableApplicationContext 초기화 갱신을 수행하는데 사용된다. SpringApplication # prepareContext () 메소드는 초기화 방법 ApplicationContextInitializer 구현 클래스를 수행합니다.

일반적으로 어떤 응용 프로그램의 맥락에서 필요한 2 ConfigurableApplicationContext # getEnvironment 예 () 소스 레지스터 또는 활성 프로파일 속성은 웹 애플리케이션을 초기화한다.

3, 시스템 초기화 org.springframework.core.Ordered 정렬 된 인터페이스를 달성하거나 호출하기 전에 정렬하기 위해 예를 들어 @Order 노트를 사용하는 것이 권장된다.

도시되지 않은 경우, ApplicationContextInitializer 무슨 뜻인지 말을 인터페이스 문서를 이해하기 어렵다. 그것은 지금이다 초기화 시스템을 사용하는 방법 세 가지 종류를 소개하기 시작했다.

첫 번째 : 사용 spring.factories 구성

(1) 새로운 FirstInitializer ApplicationContextInitializer 인터페이스를 달성

/**
 * 使用@Order注解(第3点)
 */
@Order(1)
public class FirstInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {

    /**
     * 在resources目录下新建/META-INF/spring.factories目录与文件。
     * 在resources/META-INF/spring.factories配置:
     * org.springframework.context.ApplicationContextInitializer=com.example.springbootdemo.FirstInitializer
     *
     * spring.factories的配置规则是: 接口全名=实现类全名
     */
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        /**
         * 本方法代码是添加属性 key1=value1。
         *
         * 可通过以下方式获取添加的属性:
         * @Value("${key1}")
         * String key1;
         */
        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        Map<String, Object> map = new HashMap<>();
        map.put("key1", "value1");

        // 新建属性源,并添加属性源。(第2点)
        MapPropertySource mps = new MapPropertySource("firstInitializer", map);
        environment.getPropertySources().addLast(mps);

        System.out.println("#############FirstInitializer.initialize 运行");
    }

}

자원 디렉토리에 2, 뉴 /META-INF/spring.factories 디렉토리 및 파일

spring.factories에 추가

org.springframework.context.ApplicationContextInitializer = com.example.springbootdemo.FirstInitializer

3, 다음과 같은 방법으로 속성 값을 받고 :

@Value ( "$ {키 1}")
문자열 키 1;

4, 프로젝트를 시작, 값을 얻을 수있을 것입니다.

도 5는 @Order를 사용하지 않고, 정렬 정렬하여 구현 인터페이스. 새로운 FirstOrderedInitializer.java

/**
 * 通过实现Ordered接口实现排序
 */
public class FirstOrderedInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {

    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        System.out.println("#############FirstOrderedInitializer.initialize 运行");
    }

    // 返回排序值
    @Override
    public int getOrder() {
        return 11;
    }
}

6 spring.factories를 추가

org.springframework.context.ApplicationContextInitializer = com.example.springbootdemo.FirstInitializer, \
com.example.springbootdemo.FirstOrderedInitializer

7, 프로그램을 실행, 콘솔 출력

############# FirstInitializer.initialize 실행
############# FirstOrderedInitializer.initialize 실행

@Order 정렬 값을 사용하여 FirstInitializer 주석은 1, FirstOrderedInitializer # getOrder ()는 11를 반환합니다. 그것은 볼 수 있습니다 : 정렬의 작은 값을 먼저 수행.

제 : 하드 코딩 addInitializers (새 SecondInitializer ());

1, 새로운 SecondInitializer.java

@Order(2)
public class SecondInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {

    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {

        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        Map<String, Object> map = new HashMap<>();
        map.put("key2", "value2");

        MapPropertySource mps = new MapPropertySource("secondInitializer", map);
        environment.getPropertySources().addLast(mps);

        System.out.println("#############SecondInitializer.initialize 运行");
    }
}

2, 코드 SecondInitializer를 추가하여, 부트 클래스를 수정

@SpringBootApplication
public class SpringBootDemoApplication {

    public static void main(String[] args) {

        //SpringApplication.run(SpringBootDemoApplication.class, args);

        // 第2中添加系统初始化器的方式
        SpringApplication springApplication = new SpringApplication(SpringBootDemoApplication.class);
        springApplication.addInitializers(new SecondInitializer());
        springApplication.run(args);
    }

}

셋째 application.properties 배치 context.initializer.classes

1, 새로운 ThirdInitializer.java

@Order(3)
public class ThirdInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {

    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {

        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        Map<String, Object> map = new HashMap<>();
        map.put("key3", "value3");

        MapPropertySource mps = new MapPropertySource("thirdInitializer", map);
        environment.getPropertySources().addLast(mps);

        System.out.println("#############ThirdInitializer.initialize 运行");
    }
}

2 application.properties 배치

context.initializer.classes = com.example.springbootdemo.ThirdInitializer

3, 콘솔 출력 다음 프로젝트를 시작

############# ThirdInitializer.initialize 실행
############# FirstInitializer.initialize 실행
############# SecondInitializer.initialize 실행
############# FirstOrderedInitializer.initialize 실행

ThirdInitializer 코멘트 FirstInitializer, SecondInitializer 처음 실행보다는 @Order (3), 그러나 ThirdInitializer입니다. 이니셜 라이저 context.initializer.classes 구성의 사용은 먼저 실행되지 않는 이유는 무엇입니까? 이 질문은 나중에 응답합니다.

소스 설명

봄 부트 버전은 2.2.4.RELEASE입니다.

SpringBootDemoApplication.java에 대한 첫 번째 클래스 코드 다시 시작 

SpringApplication.run (SpringBootDemoApplication.class, 인수);

봄 부팅은 대부분 기존의 시작 모드를 사용하여 소스 코드를 분석합니다.

1, 실행 방법으로, 다음과 같은 코드를 볼 때까지

// 源码位置org.springframework.boot.SpringApplication#run(java.lang.Class<?>[], java.lang.String[])
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
	return new SpringApplication(primarySources).run(args);
}

대략 그 결론을 내릴 수, 코드 SpringApplication.run (SpringBootDemoApplication.class, 인수)를 사용하여 스프링 부팅, 프로젝트를 시작 자연에서 SpringApplication 인스턴스를 만든 다음 실행 방법 인스턴스를 실행하는 것입니다. 실행 방법을 실행하기 시작 프로젝트를 완료했다.

1.1, SpringApplication 생성자를 입력 디버그 계속

// 源码位置 org.springframework.boot.SpringApplication#SpringApplication(org.springframework.core.io.ResourceLoader, java.lang.Class<?>...)
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();
}

1.1.1 방법 다음 setInitializers 소스 :

// 源码位置 org.springframework.boot.SpringApplication#setInitializers
public void setInitializers(Collection<? extends ApplicationContextInitializer<?>> initializers) {
	/**
	 * 系统初始化器可以有多个,形成一个系统初始化器列表。
	 * 在创建SpringApplication对象时,将系统初始化器列表赋值给SpringApplication的initializers属性。
	 */
    this.initializers = new ArrayList<>(initializers);
}

1.1.2 getSpringFactoriesInstances (ApplicationListener.class) 수집 시스템은 초기화의 함수

메소드 디버그의 본문에

// 源码位置 org.springframework.boot.SpringApplication#getSpringFactoriesInstances(java.lang.Class<T>, java.lang.Class<?>[], java.lang.Object...)
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;
}

1.1.2.1, 클래스 로더 getClassLoader를 classLoader가 = ();

getClassLoader를 ()는 결과 AppClassLoader 인스턴스를 반환합니다.
BootstrapClassLoader, ExtClassLoader, AppClassLoader : 자바는 세 개의 클래스 로더와 함께 제공됩니다. 클래스 패스에서 AppClassLoader로드 클래스 파일과 디렉토리 항아리 패키지. 우리는 타사 항아리 패키지 코드를 작성하고 코드 종속성은 보통으로로드됩니다.
실행은 System.getProperty ( "java.class.path를")는, 관광지 현재 프로젝트의 클래스 경로 예.

1.1.2.2 설정 <문자열> = 새 이름 LinkedHashSet의 <> (SpringFactoriesLoader.loadFactoryNames (유형 classLoader가));

유형은이 코드의 ApplicationContextInitializer 인터페이스는 클래스 집합 형 인터페이스의 구현 클래스의 전체 이름을 얻기 위해입니다. 내부 SpringFactoriesLoader.loadFactoryNames 방법으로.

// 源码位置 org.springframework.core.io.support.SpringFactoriesLoader#loadFactoryNames
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
    String factoryTypeName = factoryType.getName();
    /**
     * 重点代码是 loadSpringFactories(classLoader)。
     * 先讲结论,loadSpringFactories(classLoader)返回一个LinkedMultiValueMap对象,此对象一个key对应多个value。
     * key是接口全类名,value是接口的实现类全类名,value可以有多个。
     */
    return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}

디버깅 loadSpringFactories (classLoader가) 내부

// 源码位置 org.springframework.core.io.support.SpringFactoriesLoader#loadSpringFactories
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
	MultiValueMap<String, String> result = cache.get(classLoader);
	if (result != null) {
		return result;
	}

	try {
		/**
		 * FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
		 * 通过AppClassLoader加载Classpath下的META-INF/spring.factories
		 * 当前工程和依赖的第三方jar包中的META-INF/spring.factories都会被加载进来
		 */
		Enumeration<URL> urls = (classLoader != null ?
				classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
				ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
		result = new LinkedMultiValueMap<>();
		while (urls.hasMoreElements()) {
			URL url = urls.nextElement();
			// resource是包含了spring.factories文件路径的资源对象
			UrlResource resource = new UrlResource(url);
			// 使用spring.factories中配置的键值对创建Properties对象
			Properties properties = PropertiesLoaderUtils.loadProperties(resource);
			// 循环properties的键值对
			for (Map.Entry<?, ?> entry : properties.entrySet()) {
				String factoryTypeName = ((String) entry.getKey()).trim();
				for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
					/**
					 * factoryTypeName是spring.factories中配置的key,比如:ApplicationContextInitializer接口全类名
					 * factoryImplementationName是key对应的value,比如:ApplicationContextInitializer实现类FirstInitializer的全类名
					 */
					result.add(factoryTypeName, factoryImplementationName.trim());
				}
			}
		}
		cache.put(classLoader, result);
		
        /**
		 * result是一个LinkedMultiValueMap。key是接口全名,value是接口的实现类全类名,value可以是多个。
		 * 需要注意的是:
		 * 1、AppClassLoader会获取Classpath下所有jar包的spring.factories文件
		 * 2、并将spring.factories中所有的配置添加到result中
		 * 基于以上两点,就不难理解为什么要用缓存了
		 * cache.put(classLoader, result); 、 MultiValueMap<String, String> result = cache.get(classLoader);
		 * AppClassLoader把classpath下所有的spring.factories读取到缓存中。下次要用spring.factories配置时,从缓存中拿就好了
		 */
		return result;
	}
	catch (IOException ex) {
		throw new IllegalArgumentException("Unable to load factories from location [" +
				FACTORIES_RESOURCE_LOCATION + "]", ex);
	}
}

이 코드 줄의 역할,이 설정 <문자열> 이름 = 새로운 LinkedHashSet의 <> (SpringFactoriesLoader.loadFactoryNames (유형, 클래스 로더)) 결론. 대략 다음과 같은 두 개의 작은 단계로 나누어 :

1, AppClassLoader GET spring.factories는 클래스 경로의 경로에 파일을

2, spring.factories 속성을 읽고 객체를 생성

3, 인터페이스 유형 (이 문서가 ApplicationContextInitializer입니다 입력) 구현 클래스의 전체 이름은 클래스를 반환합니다. 결과가 설정 <문자열> 유형이 있으므로 ApplicationContextInitializer 구성 타사 항아리 패키지 spring.factories는, 클래스의 전체 클래스 이름을 읽고 반환됩니다 얻을 수 있습니다.

1.1.2.3 목록 <T> = createSpringFactoriesInstances 인스턴스 (타입 parameterTypes와, classLoader가, 인수, 이름);

전체 클래스의 수집 시스템 초기화의 이름을 돌려, 당신은 수집 시스템 초기화의 인스턴스를 만들 수 있습니다, 소스 코드는 다음입니다 :

// 源码位置 org.springframework.boot.SpringApplication#createSpringFactoriesInstances
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 {
			// AppClassLoader使用类全名把类加载到jvm内存中
			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;
}

1.1.2.4는 AnnotationAwareOrderComparator.sort (인스턴스)이 정렬 시스템 초기화 세트의 한 예이다.

디버그 다음 코드

// 源码位置 org.springframework.core.OrderComparator#doCompare()
private int doCompare(@Nullable Object o1, @Nullable Object o2, @Nullable OrderSourceProvider sourceProvider) {
	boolean p1 = (o1 instanceof PriorityOrdered);
	boolean p2 = (o2 instanceof PriorityOrdered);
	if (p1 && !p2) {
		return -1;
	}
	else if (p2 && !p1) {
		return 1;
	}

	/**
	 * getOrder方法很复杂,本文只关注getOrder方法的两个作用。
	 * 1、获取@Order注解值
	 * 2、获取Ordered接口getOrder方法返回值
	 */
	int i1 = getOrder(o1, sourceProvider);
	int i2 = getOrder(o2, sourceProvider);

	// 排序规则是升序
	return Integer.compare(i1, i2);
}

다음 코드 표시 브레이크 포인트에서 프로그램 실행 디버그
com.example.springbootdemo.FirstOrderedInitializer getOrder 번호 ()
    // 호출 getOrder 순서가 구현 클래스 () 메소드 순위 값을 얻는 
    수익을 2;     
org.springframework.core.annotation.OrderUtils # findOrder ()
    // getOrder 방법은 주석 @Order의 값을 얻기 위해 
    , MergedAnnotation <순서> = orderAnnotation annotations.get (Order.class)
    IF (orderAnnotation.isPresent ()) {
        복귀 orderAnnotation.getInt (MergedAnnotation.VALUE를)
    }

이 시점에서, 시스템 초기화 코드는 끝났어 초기화합니다. 초점 getSpringFactoriesInstances 방법입니다, 다음이 작업을 수행하는 방법을 요약 한 것입니다 :

// 源码位置 org.springframework.boot.SpringApplication#getSpringFactoriesInstances(java.lang.Class<T>, java.lang.Class<?>[], java.lang.Object...)
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
	// getClassLoader()返回AppClassLoader
	ClassLoader classLoader = getClassLoader();
	// 获取系统初始化器全类名集合
	Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
	// 创建系统初始化器集合
	List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
	// 对系统初始化器排序
	AnnotationAwareOrderComparator.sort(instances);
	// 返回排序后的系统初始化器集合
	return instances;
}

SpringApplication.initializers 명확하게 이야기하는 FirstInitializer 원칙이 추가되었습니다.

다음과 같이 소스, SecondInitializer SpringApplication.initializers은 매우 간단한 방식 springApplication.addInitializers (새 SecondInitializer을 ())를 첨가

// 源码位置 org.springframework.boot.SpringApplication#addInitializers
public void addInitializers(ApplicationContextInitializer<?>... initializers) {
	this.initializers.addAll(Arrays.asList(initializers));
}

현재 두 가지 질문을 남겼다 :

1, SecondInitializer : 및 addAll SecondInitializer 잘못된 위치 정렬은 this.initializers의 끝에 추가된다.

2, ThirdInitializer는 application.properties 구성함으로써, this.initializers에 첨가되지 않았다.

이 두 질문에, 우리는 .RUN (인수를) 새로운 SpringApplication (primarySources)을 탐구해야, 실행 방법, SpringApplication, 즉 운영 단계를.

사용 SpringApplication.run (SpringBootDemoApplication.class, 인수가) 프로그램을 시작합니다. 소스 코드에서 새로운 SpringApplication (primarySources) .RUN (인수)을 실행한다; 전술 2 구성이 코드가 시스템 초기화 코드 구성 SecondInitializer 매우 유사하다, 필요로하는 클래스 코드를 시작할

@SpringBootApplication
public class SpringBootDemoApplication {

    public static void main(String[] args) {

        //SpringApplication.run(SpringBootDemoApplication.class, args);

        // 第2中添加系统初始化器的方式
        SpringApplication springApplication = new SpringApplication(SpringBootDemoApplication.class);
        springApplication.addInitializers(new SecondInitializer());
        springApplication.run(args);  // 这句代码打上断点调试
    }

}

springApplication.run (인수)에서,이 코드는 브레이크 포인트가 표시된 엔지니어링 시운전을 시작한다.

방법은 디버그를 실행합니다

// 源码位置 org.springframework.boot.SpringApplication.run(java.lang.String...)
public ConfigurableApplicationContext run(String... args) {
    /**
     * run方法很复杂,本文作为spring boot源码系列的第一篇博客,仅关注系统初始化器相关代码。其他代码忽略
     * prepareContext方法内会运行系统初始化器
     */
    prepareContext(context, environment, listeners, applicationArguments, printedBanner);
    // ApplicationContextInitializer接口文档第三点
    refreshContext(context);
}

prepareContext에 디버그 과정

// 源码位置 org.springframework.boot.SpringApplication.prepareContext
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
                            SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
    // 应用初始化器
    applyInitializers(context);

}

applyInitializers 방법 출처 :

// 源码位置 org.springframework.boot.SpringApplication#applyInitializers
protected void applyInitializers(ConfigurableApplicationContext context) {
	/**
	 * getInitializers()获取系统初始化器,并且对系统系统初始化器再次排序,解决了SecondInitializer的排序问题
	 * 循环系统初始化器,并执行系统初始化器的initialize方法
	 */
	for (ApplicationContextInitializer initializer : getInitializers()) {
		Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
				ApplicationContextInitializer.class);
		Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
		initializer.initialize(context);
	}
}

1 getInitializers ()는 시스템 초기화, 시스템을 초기화하는 시스템을 취득하고 다시 정렬

// 源码位置 org.springframework.boot.SpringApplication#asUnmodifiableOrderedSet 
private static <E> Set<E> asUnmodifiableOrderedSet(Collection<E> elements) {
	List<E> list = new ArrayList<>(elements);
	// 再次对系统初始化器集合排序
	list.sort(AnnotationAwareOrderComparator.INSTANCE);
	return new LinkedHashSet<>(list);
}

2 시스템 초기화 장치의 세트를 획득하기 위해 () getInitializers, 시스템 초기화 중 첫 번째 행 DelegatingApplicationContextInitializer, 그것은 지정된 환경 특성 context.initializer.classes 초기화 동작에 위임한다 (위임 시스템 초기화 순서 값은 0이다) 초기화.

소스 DelegatingApplicationContextInitializer.initialize 등의 방법

// 源码位置org.springframework.boot.context.config.DelegatingApplicationContextInitializer#initialize
public void initialize(ConfigurableApplicationContext context) {
	// 获取环境变量
	ConfigurableEnvironment environment = context.getEnvironment();
	// 获取context.initializer.classes配置的初始化器集合
	List<Class<?>> initializerClasses = getInitializerClasses(environment);
	if (!initializerClasses.isEmpty()) {
		// 执行初始化器的initialize方法
		applyInitializerClasses(context, initializerClasses);
	}
}

2.1 getInitializerClasses (환경) 소스 코드 분석

// 源码位置 org.springframework.boot.context.config.DelegatingApplicationContextInitializer#getInitializerClasses
private List<Class<?>> getInitializerClasses(ConfigurableEnvironment env) {
	// PROPERTY_NAME = "context.initializer.classes"
	String classNames = env.getProperty(PROPERTY_NAME);
	List<Class<?>> classes = new ArrayList<>();
	if (StringUtils.hasLength(classNames)) {
		// 通过","分隔context.initializer.classes的值
		for (String className : StringUtils.tokenizeToStringArray(classNames, ",")) {
			// getInitializerClass(className)使用AppClassLoader加载类
			classes.add(getInitializerClass(className));
		}
	}
	return classes;
}

2.2 applyInitializerClasses (컨텍스트 initializerClasses) 자료 분석

// 源码位置 org.springframework.boot.context.config.DelegatingApplicationContextInitializer#applyInitializerClasses
private void applyInitializerClasses(ConfigurableApplicationContext context, List<Class<?>> initializerClasses) {
	Class<?> contextClass = context.getClass();
	List<ApplicationContextInitializer<?>> initializers = new ArrayList<>();
	// initializerClasses是context.initializer.classes指定的类集合
	for (Class<?> initializerClass : initializerClasses) {
		// 实例化系统初始化器
		initializers.add(instantiateInitializer(contextClass, initializerClass));
	}
	// 应用系统初始化器
	applyInitializers(context, initializers);
}

2.2.1 applyInitializers (컨텍스트 초기화) 소스 분석

// 源码位置 org.springframework.boot.context.config.DelegatingApplicationContextInitializer#applyInitializers
private void applyInitializers(ConfigurableApplicationContext context,
		List<ApplicationContextInitializer<?>> initializers) {
	// 先排序,这里是对context.initializer.classes配置的系统初始化器进行排序
	initializers.sort(new AnnotationAwareOrderComparator());
	for (ApplicationContextInitializer initializer : initializers) {
		// 执行初始化器的initialize方法,会进入 ThirdInitializer#initialize 方法中
		initializer.initialize(context);
	}
}

ThirdInitializer가 호출되었다. 이제 DelegatingApplicationContextInitializer (대표 시스템 초기화 장치)의 요약을 할 수 있습니다 :

1 DelegatingApplicationContextInitializer 순위 값은 FirstInitializer 호출되는 제 순위 값보다 작은 SecondInitializer 0이다.

2 DelegatingApplicationContextInitializer 시스템 구성 이니셜 context.initializer.classes 인스턴스화하고, 이러한 시스템의 동작에있어서의 초기화를 초기화한다. context.initializer.classes 있도록 구성된 시스템 초기화가 먼저 실행됩니다.

순위 값 세트 FirstInitializer 0 미만이면 3 DelegatingApplicationContextInitializer 순위 값은 동작 우선, 0 FirstInitializer 것이다.

완료 인스턴스, 프로세스 ThirdInitializer를 실행합니다. 백 org.springframework.boot.SpringApplication #의 applyInitializers 방법에서, 프로세스의 FirstInitializer, FirstOrderedInitializer, SecondInitializer를 계속 실행 설명

// 源码位置 org.springframework.boot.SpringApplication#applyInitializers
protected void applyInitializers(ConfigurableApplicationContext context) {
    /**
     * 循环处理getInitializers()返回的系统初始化器,
     * 排在第一位的是DelegatingApplicationContextInitializer,前面已经讲了此初始化器的运行过程
     * 后面几次循环获得的initializer包含FirstInitializer、FirstOrderedInitializer、SecondInitializer
     * initializer.initialize(context);就直接运行我们自定义的系统初始化器了
     */
    for (ApplicationContextInitializer initializer : getInitializers()) {
        Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
                ApplicationContextInitializer.class);
        Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
        initializer.initialize(context);
    }
}

음, 봄 부팅이 시스템 초기화 내가 다시 계속 업데이트됩니다, 완료 소스 코드를 사용하는 것입니다 봄 부팅 소스 시리즈  , 교환에 오신 것을 환영합니다.

 

 

게시 51 개 원래 기사 · 원 찬양 14 ·은 40000 +를 볼

추천

출처blog.csdn.net/u010606397/article/details/105103629