春 - ソースコード解析 - springbootのブートプロセス

1、初期構造

図1に示すように、初期化処理の例とApplicationListener ApplicationContextInitializer、ウェブに現在の環境か否かを判定しながら

//SpringApplication.java    257
//1.根据 { "javax.servlet.Servlet",
// "org.springframework.web.context.ConfigurableWebApplicationContext" } 是否存在, 决定web环境
this.webEnvironment = deduceWebEnvironment();

//2.加载所有的 ApplicationContextInitializer (META-INF/spring.factories)
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));

//3.加载所有的 ApplicationListener (META-INF/spring.factories)
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));

//4.定义 main 方法
this.mainApplicationClass = deduceMainApplicationClass();

図2に示すように、コアファイルMETA-INF / spring.factories、使用SpringFactoriesLoader.loadFactoryNames(タイプ、クラスローダー)が読み込ま

//SpringFactoriesLoader.java    109行
//读取 "META-INF/spring.factories" 文件
Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));

while (urls.hasMoreElements()) {
    URL url = urls.nextElement();
    Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
    String factoryClassNames = properties.getProperty(factoryClassName);
    result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(
    factoryClassNames)));
}

2、ブートプロセス

1、オン時間の記録

StopWatch stopWatch = new StopWatch();
stopWatch.start();
//...省略
stopWatch.stop();

2、すべてのリスナーを初期化し、管理するためのクラスを使用するすべてのモニタは、すべてのイベントを公開します

SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.started();

//getRunListeners 方法,读取的也是上面的文件,加载所有的 SpringApplicationRunListener
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
				SpringApplicationRunListener.class, types, this, args));

3、環境の環境を設定します

//1.启动参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//2.此处配置的是 StandardServletEnvironment,并合并启动参数到环境中,并发布 SpringApplicationRunListeners 事件
ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);

4、プリントバナー

Banner printedBanner = printBanner(environment);

 5、容器、及び前処理容器を作成します

//1.创建的是 AnnotationConfigEmbeddedWebApplicationContext
context = createApplicationContext();
prepareContext(context, environment, listeners, applicationArguments,printedBanner);
//1.设置 environment
context.setEnvironment(environment);
//2.调用所有的 ApplicationContextInitializer
applyInitializers(context);
//3.发布 SpringApplicationRunListeners 事件
listeners.contextPrepared(context);
//4.注册当前 Application 类到容器中
load(context, sources.toArray(new Object[sources.size()]));
//5.发布 SpringApplicationRunListeners 事件
listeners.contextLoaded(context);

6、コンテナをリフレッシュし、実際には、リフレッシュされません

//1.最终调用的是 AbstractApplicationContext 的 refresh 方法
refreshContext(context);

7、ランナーを呼びます

//调用 ApplicationRunner 和 CommandLineRunner 的 run 方法,可以用来启动其他的服务
List<Object> runners = new ArrayList<Object>();
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
AnnotationAwareOrderComparator.sort(runners);
for (Object runner : new LinkedHashSet<Object>(runners)) {
    if (runner instanceof ApplicationRunner) {
        callRunner((ApplicationRunner) runner, args);
    }
    if (runner instanceof CommandLineRunner) {
        callRunner((CommandLineRunner) runner, args);
    }
}

3、@設定注釈ロードプロセス

図1に示すように、ロード・プロセスは、クラスを処理するために使用されるConfigurationClassPostProcessor

//1.获取所有的bean
String[] candidateNames = registry.getBeanDefinitionNames();
for(...){
    //2.判断对应bean是否为配置类,如果是,则加入到configCandidates
}

//3.对configCandidates 进行 排序,按照@Order 配置的值进行排序
Collections.sort(configCandidates, new Comparator<BeanDefinitionHolder>() {
    @Override
    public int compare(BeanDefinitionHolder bd1, BeanDefinitionHolder bd2) {
        int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
        int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
        return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0;
    }
});

//4.调用ConfigurationClassParser#parse进行解析
parser.parse(candidates);
parser.validate();

//5.将解析过的配置类加入到configClasses,并去重
Set<ConfigurationClass> configClasses = new LinkedHashSet<ConfigurationClass>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);

//6.解析bean
this.reader.loadBeanDefinitions(configClasses);

2、@コンフィギュレーションのアノテーションクラス解決プロセス

//ConfigurationClassBeanDefinitionReader.java    124行
//1.解析每个方法,寻找 @Bean 注解
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
    loadBeanDefinitionsForBeanMethod(beanMethod);
}

//2.解析 import 标签,按照 xml 方式去解析 bean
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());

4、@インポート注釈ローディングプロセス

1、ConfigurationClassParser.parseを呼び出すConfigurationClassPostProcessorが解析されて行きます

public void parse(Set<BeanDefinitionHolder> configCandidates) {
    //...省略
    processDeferredImportSelectors();
}

2、例えば:@EnableAutoConfiguration

ノートは@import(EnableAutoConfigurationImportSelector.class)に使用します

public String[] selectImports(AnnotationMetadata metadata) {
	if (!isEnabled(metadata)) {
		return NO_IMPORTS;
	}
	try {
		AnnotationAttributes attributes = getAttributes(metadata);
        //1.读取 META-INF/spring.factories 文件下所有 EnableAutoConfiguration 类型的类
		List<String> configurations = getCandidateConfigurations(metadata,attributes);
		configurations = removeDuplicates(configurations);
		Set<String> exclusions = getExclusions(metadata, attributes);
		configurations.removeAll(exclusions);
		configurations = sort(configurations);
		recordWithConditionEvaluationReport(configurations, exclusions);
		return configurations.toArray(new String[configurations.size()]);
	}
	catch (IOException ex) {
		throw new IllegalStateException(ex);
	}
}

@インポートを使用する3、いくつかの方法

  • 最も簡単な方法は、クラスに直接導入され、
@Configuration
@Import(value={UserServiceImpl.class})
public class Config {}
  • ImportBeanDefinitionRegistrar方法を使用します
public class UserServiceBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
                                        BeanDefinitionRegistry registry) {
        //通过registry就可以注入到容器里
    }

}
  • @ImportSelector方法を使用します
@Configuration()
@Import(UserServiceImportSelect.class)
public class Config {

}

public class UserServiceImportSelect implements ImportSelector{

    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        
    }
}

 

おすすめ

転載: blog.csdn.net/sky_eyeland/article/details/92794349