Springboot自动装配原理
一、引言
@SpringBootApplication public class SampleTomcatApplication { public static void main(String[] args) { SpringApplication.run(SampleTomcatApplication.class, args); } }
通常情况下,我们使用springboot开发,入口都是这样的,那么入口类上的注解是怎么生效的?注解又包含了什么信息呢?
二、入口类
public ConfigurableApplicationContext run(String... args) { ``` //完成启动类的加载 prepareContext(context, environment, listeners, applicationArguments, printedBanner); ``` } private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { ··· Set
跟踪源码可以看到,传进来的入口类,是被先注册成一个BeanDefinition,后续就会经历bean的初始化生命周期,并且解析bean上注解。
三、@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) }) public @interface SpringBootApplication { //排除类名数组 @AliasFor(annotation = EnableAutoConfiguration.class) Class<?>[] exclude() default {}; //排除全限定名数组 @AliasFor(annotation = EnableAutoConfiguration.class) String[] excludeName() default {}; //扫描指定包下的所有组件 @AliasFor(annotation = ComponentScan.class, attribute = "basePackages") String[] scanBasePackages() default {}; //扫描指定某个类所在包下的所有组件 @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses") Class<?>[] scanBasePackageClasses() default {}; //自定义beanName生成器 @AliasFor(annotation = ComponentScan.class, attribute = "nameGenerator") Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class; //配置类是否被代理 @AliasFor(annotation = Configuration.class) boolean proxyBeanMethods() default true; }
@SpringBootConfiguration
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration public @interface SpringBootConfiguration { @AliasFor(annotation = Configuration.class) boolean proxyBeanMethods() default true; }
就是一个配置类注解,等同于@Configuration
@EnableAutoConfiguration
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage //导入了一个ImportSelector实现类 @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; Class<?>[] exclude() default {}; String[] excludeName() default {}; }
@AutoConfigurationPackage
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited //导入了一个ImportBeanDefinitionRegistrar实现类 @Import(AutoConfigurationPackages.Registrar.class) public @interface AutoConfigurationPackage { String[] basePackages() default {}; Class<?>[] basePackageClasses() default {}; }
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports { @Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { //注册AutoConfigurationPackages的beandefinition register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0])); } @Override public Set
@Import(AutoConfigurationImportSelector.class)关键注解,自动装配的原理所在,导入的是ImportSelector的实现类,那么会执行他的selectImports方法,并把返回的全限定类名字符串数组注册成beanDefinition。
@Override public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); }
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } //注解获取 AnnotationAttributes attributes = getAttributes(annotationMetadata); //加载配置文件META-INF/spring.factories中配置的key为EnableAutoConfiguration的beanNames Listconfigurations = getCandidateConfigurations(annotationMetadata, attributes); //去重 configurations = removeDuplicates(configurations); //根据exclude属性排除beanName Set exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); //过滤beanNames configurations = getConfigurationClassFilter().filter(configurations); fireAutoConfigurationImportEvents(configurations, exclusions); //包装赋值给configurations return new AutoConfigurationEntry(configurations, exclusions); }
但是实际上这地方并没有执行selectImports方法,因为AutoConfigurationImportSelector重写了process方法,如果我们自定义的Selector没有进行方法重写,那么会调用DefaultDeferredImportSelectorGroup类的process方法
public void process(AnnotationMetadata metadata, DeferredImportSelector selector) { //调用selector的selectImports方法 for (String importClassName : selector.selectImports(metadata)) { this.imports.add(new Entry(metadata, importClassName)); } }
但是AutoConfigurationImportSelector调用的是自己的内部类AutoConfigurationGroup的process方法,不过依然是调用了上面所说的getAutoConfigurationEntry方法,具体为什么这么做,还不清楚
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) { Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector, () -> String.format("Only %s implementations are supported, got %s", AutoConfigurationImportSelector.class.getSimpleName(), deferredImportSelector.getClass().getName())); //自动装配 AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector) .getAutoConfigurationEntry(annotationMetadata); this.autoConfigurationEntries.add(autoConfigurationEntry); for (String importClassName : autoConfigurationEntry.getConfigurations()) { this.entries.putIfAbsent(importClassName, annotationMetadata); } }
这时我们定义在spring.factories中的配置类,都会被加载成beanDefinition,后续还会对他们进行解析,其中有一个类DispatcherServletAutoConfiguration,这个配置类就是为了把DispatcherServlet放入到spring的IOC容器,使用@Bean注解的方式,这里就不详解了。
四、扩展
利用springboot的自动装配原理,我们可以在平时的工作中开发springboot应用的starter工具包,非常实用,而且springboot自己也是这么做的,我们经常用到的带有starter的jar包就是这么来的,具体怎么做,网上也有教程,这么就不做扩展了。