版本
版本: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); }
参考
SpringBoot之@EnableAutoConfiguration注解
SpringBootApplication-@Import(AutoConfigurationImportSelector.class)