SPRINGBOOT启动原理(基于3.x版本)(一)

版本

版本:3.0.1

注解

我们从启动类入手,springboot的启动类上要添加 @SpringBootApplication 注解,我们先看一下这个注解的作用:

@SpringBootApplication

//用于描述类、接口(包括注解类型) 或enum声明
@Target({ElementType.TYPE})
//注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在;
@Retention(RetentionPolicy.RUNTIME)
//表明这个注解应该被 javadoc工具记录
@Documented
//子类将会继承该注解
@Inherited
//相当于@Configuration
@SpringBootConfiguration
//启用 SpringBoot 的自动配置机制
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)

@EnableAutoConfiguration

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
//使用Import自动导入所有符合自动配置条件的Bean定义并加载到IOC容器
@Import(AutoConfigurationImportSelector.class)

这个注解里面比较引人注意的是这两个注解:

@AutoConfigurationPackage

@Import({AutoConfigurationImportSelector.class})

介绍

三种将类交给spring管理,也就是加入IOC容器的方式:

  • @Bean
  • @Componet/@Service
  • @Import

@Import一般作用于@Configuration定义的类上,它有三种用法
先假设我们有3个类

public class Apple {
}

public class Banana {
}

public class Cherry {
}

都通过这个类注入:

@Configuration
public class Fruits {
}
指定class数组方式
@Configuration
@Import(Apple.class)
public class Fruits {
}
ImportSelector方式(Spring Boot底层采用比较得多的方式)
public class BananaImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.test.Banana"};
    }
}

@Configuration
@Import({Apple.class,BananaImportSelector.class})
public class Fruits {
}
ImportBeanDefinitionRegistrar方式
public class CherryDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        RootBeanDefinition rootBeanDefinition=new RootBeanDefinition(Cherry.class);
        //这里还可以给Cherry这个类改个名字,比如Coconut
        registry.registerBeanDefinition("Coconut",rootBeanDefinition);
    }
}

@Configuration
@Import({Apple.class,BananaImportSelector.class,CherryDefinitionRegistrar.class})
public class Fruits {
}

正题

以上,也就是说,在这个地方,要先引入一些类,而且是通过第二种方式来进行的,我们看下这个类:AutoConfigurationImportSelector.class

@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
	//判断EnableAutoConfiguration是否开启,一般默认开启的
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
		
		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
	}

	protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
	//这里又判断了一遍EnableAutoConfiguration是否开启
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
       //这里可以理解为获取到了EnableAutoConfiguration的属性和我们传入的值。
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		//这里可以理解为获取到了所有可以自动注入的类名
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
		//给这些需要自动注入的类名去重,通过list-set-list的方式
		configurations = removeDuplicates(configurations);
		//把我们设置了排出的整个set返回回来
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		//验证一下要排除自动的类是否合法,不合法的话会直接抛异常
		checkExcludedClasses(configurations, exclusions);
		//这里就直接把我们想要排除的类从自动启动里都remove了
		configurations.removeAll(exclusions);
		//TODO:这块另写一篇 获取过滤器,过滤配置类
		configurations = getConfigurationClassFilter().filter(configurations);
		//TODO:这块另写一篇 获取所有的AutoConfigurationImportListener类型的监听器。然后广播AutoConfigurationImportEvent事件
		fireAutoConfigurationImportEvents(configurations, exclusions);
		//配置类名字结合和排除集合封装成AutoConfigurationEntry返回
		return new AutoConfigurationEntry(configurations, exclusions);
	}
	
	protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
	//拿到了EnableAutoConfiguration类的名字
		String name = getAnnotationClass().getName();
		AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true));
		Assert.notNull(attributes, () -> "No auto-configuration attributes found. Is " + metadata.getClassName()
				+ " annotated with " + ClassUtils.getShortName(name) + "?");
		return attributes;
	}
	protected final <T> List<T> removeDuplicates(List<T> list) {
		return new ArrayList<>(new LinkedHashSet<>(list));
	}


	private void checkExcludedClasses(List<String> configurations, Set<String> exclusions) {
		List<String> invalidExcludes = new ArrayList<>(exclusions.size());
		for (String exclusion : exclusions) {
			if (ClassUtils.isPresent(exclusion, getClass().getClassLoader()) && !configurations.contains(exclusion)) {
				invalidExcludes.add(exclusion);
			}
		}
		if (!invalidExcludes.isEmpty()) {
			handleInvalidExcludes(invalidExcludes);
		}
	}
		private ConfigurationClassFilter getConfigurationClassFilter() {
		if (this.configurationClassFilter == null) {
		//这里其实获取到了AutoConfigurationImportFilter
			List<AutoConfigurationImportFilter> filters = getAutoConfigurationImportFilters();
			for (AutoConfigurationImportFilter filter : filters) {
				invokeAwareMethods(filter);
			}
			this.configurationClassFilter = new ConfigurationClassFilter(this.beanClassLoader, filters);
		}
		return this.configurationClassFilter;
	}

	private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) {
		List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners();
		if (!listeners.isEmpty()) {
		//这块主要是获取到了AutoConfigurationImportFilter的三个实现类
			AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);
			for (AutoConfigurationImportListener listener : listeners) {
				invokeAwareMethods(listener);
				listener.onAutoConfigurationImportEvent(event);
			}
		}
	}

	protected List<AutoConfigurationImportListener> getAutoConfigurationImportListeners() {
		return SpringFactoriesLoader.loadFactories(AutoConfigurationImportListener.class, this.beanClassLoader);
	}
	
		private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) {
		List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners();
		if (!listeners.isEmpty()) {
			AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);
			for (AutoConfigurationImportListener listener : listeners) {
				invokeAwareMethods(listener);
				listener.onAutoConfigurationImportEvent(event);
			}
		}
	}

	protected List<AutoConfigurationImportListener> getAutoConfigurationImportListeners() {
		return SpringFactoriesLoader.loadFactories(AutoConfigurationImportListener.class, this.beanClassLoader);
	}
	
参考

@Import注解的应用和扩展

SpringBoot之@EnableAutoConfiguration注解

SpringBootApplication-@Import(AutoConfigurationImportSelector.class)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

盖丽男

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值