一、引言
@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<Object> sources = getAllSources(); //sources就是启动类,这里面把启动类注册成了一个beanDefinition load(context, sources.toArray(new Object[0])); listeners.contextLoaded(context); } protected void load(ApplicationContext context, Object[] sources) { //初始化了annotatedReader、扫描器等 BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources); if (this.beanNameGenerator != null) { loader.setBeanNameGenerator(this.beanNameGenerator); } if (this.resourceLoader != null) { loader.setResourceLoader(this.resourceLoader); } if (this.environment != null) { loader.setEnvironment(this.environment); } //加载注册 loader.load(); } void load() { for (Object source : this.sources) { load(source); } } private void load(Object source) { Assert.notNull(source, "Source must not be null"); if (source instanceof Class<?>) { load((Class<?>) source); return; } if (source instanceof Resource) { load((Resource) source); return; } if (source instanceof Package) { load((Package) source); return; } if (source instanceof CharSequence) { load((CharSequence) source); return; } throw new IllegalArgumentException("Invalid source type " + source.getClass()); } private void load(Class<?> source) { if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) { // Any GroovyLoaders added in beans{} DSL can contribute beans here GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class); ((GroovyBeanDefinitionReader) this.groovyReader).beans(loader.getBeans()); } if (isEligible(source)) { //把source注册成一个beanDefinition this.annotatedReader.register(source); } }
跟踪源码可以看到,传进来的入口类,是被先注册成一个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<Object> determineImports(AnnotationMetadata metadata) { return Collections.singleton(new PackageImports(metadata)); } }
@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 List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); //去重 configurations = removeDuplicates(configurations); //根据exclude属性排除beanName Set<String> 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包就是这么来的,具体怎么做,网上也有教程,这么就不做扩展了。