这篇文章主要讲解了“Spring Boot配置类加载流程示例”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Spring Boot配置类加载流程示例”吧!
本文基于Spring Boot 1.4.1.RELEASE版本
启动代码如下
@SpringBootApplication
public class SampleApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(SampleApplication.class, args);
}
}
然后开始分析流程,由于Spring细节众多,所以我们只关注重点就行了,不然容易迷失在其中
//ConfigurationClassPostProcessor.java
//第273行
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<BeanDefinitionHolder>();
String[] candidateNames = registry.getBeanDefinitionNames();
//遍历已经注册的所有bean
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
//判断这个bean是不是已经被加载过的配置类
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
//如果没加载过,判断一下是不是配置类
//这个判断逻辑很简单,有兴趣的朋友可以自己了解一下
//因为是工具类,其实不看也不影响大局,注意这里check完之后,上边的校验就是true了
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
if (configCandidates.isEmpty()) {
return;
}
//这段代码的功能是将配置类按照Order排序,但其实没有用,
//因为此时的configCandidates列表中只有一个元素,就是SampleApplication
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;
}
});
//省略部分代码
//这里就是配置解析的关键
parser.parse(candidates);
//省略部分代码
}
接下来看ConfigurationClassParser这个类
//ConfigurationClassParser.java
//第166行
public void parse(Set<BeanDefinitionHolder> configCandidates) {
this.deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>();
//遍历所有的配置类,根据类型调用不同的parse方法
//这里分成的三种类型各代表什么,暂时不太清楚
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
//省略部分代码
}
不同的parse方法会将各种参数组装成ConfigurationClass对象,传给processConfigurationClass()
//ConfigurationClassParser.java
//第208行
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
//判断当前要解析的bean是否符合解析的条件
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
if (configClass.isImported()) {
if (existingClass.isImported()) {
existingClass.mergeImportedBy(configClass);
}
return;
}
else {
this.configurationClasses.remove(configClass);
for (Iterator<ConfigurationClass> it = this.knownSuperclasses.values().iterator(); it.hasNext(); ) {
if (configClass.equals(it.next())) {
it.remove();
}
}
}
}
//省略部分代码
}
//ConditionEvaluator.java
//第73行
//AnnotatedTypeMetadata:类上的注解信息
//ConfigurationPhase:PARSE_CONFIGURATION-在解析配置时校验;REGISTER_BEAN-在注册bean时校验
public boolean shouldSkip(AnnotatedTypeMetadata metadata, ConfigurationPhase phase) {
//如果没有配置条件,直接返回
if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
return false;
}
//如果不指定phase,配置类使用PARSE_CONFIGURATION,其他使用REGISTER_BEAN
if (phase == null) {
if (metadata instanceof AnnotationMetadata &&
ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
}
return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
}
//获取Condition并判断条件
List<Condition> conditions = new ArrayList<Condition>();
for (String[] conditionClasses : getConditionClasses(metadata)) {
for (String conditionClass : conditionClasses) {
Condition condition = getCondition(conditionClass, this.context.getClassLoader());
conditions.add(condition);
}
}
AnnotationAwareOrderComparator.sort(conditions);
for (Condition condition : conditions) {
ConfigurationPhase requiredPhase = null;
if (condition instanceof ConfigurationCondition) {
requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
}
if (requiredPhase == null || requiredPhase == phase) {
if (!condition.matches(this.context, metadata)) {
return true;
}
}
}
return false;
}
开始解析配置类之前,会先判断当前类是否符合条件以及是否已经解析过,然后才会进入解析流程
//ConfigurationClassParser.java
//第208行
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
//省略部分代码
//递归处理配置类和它的父类
SourceClass sourceClass = asSourceClass(configClass);
do {
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}
解析的流程有点多,我们分段处理
1、处理嵌套(内部)的配置类
//ConfigurationClassParser.java
//第252行
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
//先递归处理嵌套(内部)的配置类
processMemberClasses(configClass, sourceClass);
//省略部分代码
}
//ConfigurationClassParser.java
//第326行
private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
for (SourceClass memberClass : sourceClass.getMemberClasses()) {
if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
!memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
if (this.importStack.contains(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
//回到最开始解析的地方,递归处理
processConfigurationClass(memberClass.asConfigClass(configClass));
}
finally {
this.importStack.pop();
}
}
}
}
}
2、处理@PropertySource注解
//ConfigurationClassParser.java
//第252行
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
//省略部分代码
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class, org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
//解析properties配置文件并放到Spring环境中
processPropertySource(propertySource);
}
else {
logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
//省略部分代码
}
3、处理@ComponentScan注解
//ConfigurationClassParser.java
//第252行
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
//省略部分代码
//获取所有的@ComponentScan注解
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
//根据@ComponentScan注解获取bean
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
//判断扫描的bean中是否有配置类,有的话继续递归解析
if (ConfigurationClassUtils.checkConfigurationClassCandidate(holder.getBeanDefinition(), this.metadataReaderFactory)) {
parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());
}
}
}
}
//省略部分代码
}
4、处理@Import注解,@Import作用是导入Java配置类
Spring Boot的@EnableAutoConfiguration注解也会在这里处理,所以如果你的自动配置类被@ComponentScan注解扫描到了,只会被当做普通的配置类,自动配置排序相关的注解(@AutoConfigureAfter等等)都是无效的
//ConfigurationClassParser.java
//第252行
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
//省略部分代码
processImports(configClass, sourceClass, getImports(sourceClass), true);
//省略部分代码
}
//ConfigurationClassParser.java
//第441行
private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
Set<SourceClass> imports = new LinkedHashSet<SourceClass>();
Set<SourceClass> visited = new LinkedHashSet<SourceClass>();
collectImports(sourceClass, imports, visited);
return imports;
}
//ConfigurationClassParser.java
//第461行
private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited) throws IOException {
//visited保存所有处理过的类,防止重复处理
if (visited.add(sourceClass)) {
//取sourceClass上的所有@Import注解,包括其他注解中的@Import注解
for (SourceClass annotation : sourceClass.getAnnotations()) {
String annName = annotation.getMetadata().getClassName();
//这里不太懂为啥判断java开头
if (!annName.startsWith("java") && !annName.equals(Import.class.getName())) {
collectImports(annotation, imports, visited);
}
}
imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
}
}
//ConfigurationClassParser.java
//第494行
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) throws IOException {
if (importCandidates.isEmpty()) {
return;
}
//校验是否存在循环依赖
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignable(ImportSelector.class)) {
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
ParserStrategyUtils.invokeAwareMethods(
selector, this.environment, this.resourceLoader, this.registry);
//如果是DeferredImportSelector接口,先暂存起来,在ConfigurationClassParser.parse(Set<BeanDefinitionHolder>)方法的最后处理(即其他配置类加载完之后)
if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
this.deferredImportSelectors.add(
new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
}
//普通的ImportSelector接口直接递归处理
else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
//ImportBeanDefinitionRegistrar接口在ConfigurationClassParser.parse(Set<BeanDefinitionHolder>)方法执行完毕后处理(即所有配置类加载完之后)
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
ParserStrategyUtils.invokeAwareMethods(
registrar, this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
//既不是ImportSelector也不是ImportBeanDefinitionRegistrar,当做普通的@Configuration类处理
else {
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass));
}
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
}
finally {
this.importStack.pop();
}
}
}
5、处理@ImportResource注解,@ImportResource作用是导入XML配置
//ConfigurationClassParser.java
//第252行
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
//省略部分代码
if (sourceClass.getMetadata().isAnnotated(ImportResource.class.getName())) {
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
//xml配置文件跟ImportBeanDefinitionRegistrar接口一样,也会暂存起来
//在ConfigurationClassParser.parse(Set<BeanDefinitionHolder>)方法执行完毕后处理(即所有配置类加载完之后)
configClass.addImportedResource(resolvedResource, readerClass);
}
}
//省略部分代码
}
6、处理单独的@Bean方法
//ConfigurationClassParser.java
//第252行
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
//省略部分代码
Set<MethodMetadata> beanMethods = sourceClass.getMetadata().getAnnotatedMethods(Bean.class.getName());
for (MethodMetadata methodMetadata : beanMethods) {
//暂存起来,在ConfigurationClassParser.parse(Set<BeanDefinitionHolder>)方法执行完毕后处理(即所有配置类加载完之后)
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
//省略部分代码
}
7、处理实现的接口中的default方法
//ConfigurationClassParser.java
//第252行
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
//省略部分代码
processInterfaces(configClass, sourceClass);
//省略部分代码
}
//ConfigurationClassParser.java
//第349行
private void processInterfaces(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
for (SourceClass ifc : sourceClass.getInterfaces()) {
Set<MethodMetadata> beanMethods = ifc.getMetadata().getAnnotatedMethods(Bean.class.getName());
for (MethodMetadata methodMetadata : beanMethods) {
if (!methodMetadata.isAbstract()) {
//暂存起来,在ConfigurationClassParser.parse(Set<BeanDefinitionHolder>)方法执行完毕后处理(即所有配置类加载完之后)
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
}
//递归处理
processInterfaces(configClass, ifc);
}
}
8、处理父类中的方法
//ConfigurationClassParser.java
//第252行
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
//省略部分代码
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (!superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
//如果存在符合条件的父类,返回它,然后继续解析
//doProcessConfigurationClass方法被调用的地方是一个while循环,只要不为null就会一直调用
return sourceClass.getSuperClass();
}
}
//省略部分代码
}
9、处理之前暂存的DeferredImportSelector接口
//ConfigurationClassParser.java
//第166行
public void parse(Set<BeanDefinitionHolder> configCandidates) {
//省略部分代码
processDeferredImportSelectors();
}
//ConfigurationClassParser.java
//第473行
private void processDeferredImportSelectors() {
List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
this.deferredImportSelectors = null;
Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR);
for (DeferredImportSelectorHolder deferredImport : deferredImports) {
ConfigurationClass configClass = deferredImport.getConfigurationClass();
try {
String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata());
processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
}
}
}
10、加载xml配置文件、ImportBeanDefinitionRegistrar接口实现类以及标注了@Bean的方法
//ConfigurationClassPostProcessor.java
//第273行
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
//省略部分代码
this.reader.loadBeanDefinitions(configClasses);
//省略部分代码
}
//ConfigurationClassBeanDefinitionReader.java
//第113行
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
for (ConfigurationClass configClass : configurationModel) {
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
}
}
//ConfigurationClassBeanDefinitionReader.java
//第124行
private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass,
TrackedConditionEvaluator trackedConditionEvaluator) {
//省略部分代码
if (configClass.isImported()) {
//将配置类自己也注册成一个bean
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
//将标记了@Bean的方法加载成bean
loadBeanDefinitionsForBeanMethod(beanMethod);
}
//加载XML配置文件
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
//加载ImportBeanDefinitionRegistrar接口的实现
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
感谢各位的阅读,以上就是“Spring Boot配置类加载流程示例”的内容了,经过本文的学习后,相信大家对Spring Boot配置类加载流程示例这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。