文章目录
- @SpringBootApplication
- @SpringBootConfiguration
- @EnableAutoConfiguration
- @AutoConfigurationPackage
- @Import(AutoConfigurationImportSelector.class)
- AutoConfigurationImportSelector流程分析
@SpringBootApplication
这个注解是springboot的启动注解,配置了这个注解的方法就是springboot项目的入口;
一般springboot项目的启动类:
@SpringBootApplication
public class SpringBootPlusApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringBootPlusApplication.class, args);
// 打印项目信息
PrintApplicationInfo.print(context);
}
}
我们看看SpringBootApplication注解:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
@ConfigurationPropertiesScan
public @interface SpringBootApplication {
}
@ComponentScan表示包扫描,FilterType.CUSTOM表示自定义扫描;可以看一下TypeExcludeFilter这类,实现TypeFilterl类,重写match方法进行判断是否加入spring容器中;这里不做过多详解,主要讲@SpringBootConfiguration、@EnableAutoConfiguration这两个注解;
@SpringBootConfiguration
源码:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration(proxyBeanMethods = false)
public @interface SpringBootConfiguration {
@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}
这个注解就一个@Configuration注解,就相当于把当前标注了@SpringBootConfiguration注解的类标记为配置类;
@Configuration类里面有@Component注解…
@EnableAutoConfiguration
EnableAutoConfiguration这个注解从名字上面来看,这个注解应该是跟自动装配相关的注解了;
先看看enableAutoCOnfiguration注解的源码:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
}
前四个是元注解,就不提了,后面两个@AutoConfigurationPackage和导入了入AutoConfigurationImportSelector这个类;
@AutoConfigurationPackage
这个类从名字上面看应该是自配配置包的:
先看看源码:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
}
这里主要导入了AutoConfigurationPackages.Registrar.class类:
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
register(registry, new PackageImport(metadata).getPackageName());
}
@Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new PackageImport(metadata));
}
}
这个类获取到了使用这个注解的包路径,然后扫描注册对应包路径下所有组件,注册到spring容器中;
@Import(AutoConfigurationImportSelector.class)
先看AutoConfigurationImportSelector实现的接口:
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
}
实现的aware接口,就是在类中获取spring容器的组件,这里获取的是:beanFactory,environment,beanClassLoader,resourceLoader;
最主要的接口是DeferredImportSelector,这个接口继承了ImportSelector接口,
- ImportSelector这个接口在调用地方是在,spring容器处理Import注解的时候,如果@import注解导入的类实现了ImportSelector接口,则会调用selectImports方法获取Import的类:
基于被引入的Configuration类的AnnotationMetadata信息选择并返回需要引入的类名列表;
ImportSelector的实现和@import通常在处理方式上是一致的,可以在所以的配置类,就是@Configuration标记的类处理完成后在进行筛选;
- DeferredImportSelector接口实现了ImportSelector接口,表明他们作用差不多,DeferredImportSelector接口在所有的@Configuration处理完成之后才会调用,在需要筛选的引入类型具备@Conditional(条件注入指定类的时候)非常有用;最后会执行selectImports方法;
AutoConfigurationImportSelector流程分析
DeferredImportSelector会通过getImportGroup返回执行的类,然后执行内部类AutoConfigurationGroup方法的process方法,然后执行getAutoConfigurationEntry方法,我们就从AutoConfigurationImportSelector的process开始:
通过process的getAutoConfigurationEntry来获取自动装配的Entry对象:
然后进到getCandidateConfigurations方法,getCandidateConfigurations就加载出了spring-boot-autuator-atoconfig包下META-INF\spring,factories文件,第一次的时候cache里面是空的,就会通过classloader加载META-INF/spring.factories文件,通过配置的key/vlaue保存到缓存中.给后面使用:
然后spring通过加载这些类,将这些配置类加入到spring容器中,可以看ConfigurationClassParser的processGroupImports方法,通过执行getImports方法,点进去就看见是执行DeferredImportSelector的selectImports方法;
这时候通过加载meta-inf文件夹下的spring.factories文件配置的配置类路径,进行加载对应的类,这时候自动装配就基本完成了,剩下的就是这些配置类可以通过@ConditionalOnBean等一系列注解来判断加不加载当前类:
举个例子:HttpEncodingAutoConfiguration类
可通过是否配置了spring.http.encoding来进行判断是否加载当前配置类…
更多@ConditionalOnBean详解