自动配置[源码分析] - 自动配置包
文章目录
这里的自动配置包就是指的启动类所在包, 为什么我们会将该包下的所有类进行一个扫描?
首先我们要看自动配置原理, 肯定是从@SpringBootApplication注解开始:
这个注解就会为我们一步一步解开SpringBoot的自动配置原理
- 所有的特性都是在源码中有体现的, 都是程序员写的
@SpringBootApplication注解源码:
/*
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.core.annotation.AliasFor;
import org.springframework.data.repository.Repository;
/**
* Indicates a {@link Configuration configuration} class that declares one or more
* {@link Bean @Bean} methods and also triggers {@link EnableAutoConfiguration
* auto-configuration} and {@link ComponentScan component scanning}. This is a convenience
* annotation that is equivalent to declaring {@code @Configuration},
* {@code @EnableAutoConfiguration} and {@code @ComponentScan}.
*
* @author Phillip Webb
* @author Stephane Nicoll
* @author Andy Wilkinson
* @since 1.2.0
*/
@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 {
...
}
可以看到我们的@SpringBootApplication注解是一个合成注解
那么除了元注解, 我们就看以下的几个注解:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
1. @SpringBootConfiguration注解
该注解点入到源码中可以发现其实就是一个@Configuration注解, 那么也就时标记为一个配置类, 也就是将当前类标记为主配置类
- @SpringBootConfiguration注解源码:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
...
}
2.@ComponentScan (excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
该注解就配置了一个包扫描, 只不过是一个比较特殊的包扫描, 特殊在是使用了TypeFilter指定了一个包扫描规则
- 细心的人可以发现这里并没有指明包扫描的位置, 那么报扫描的位置是在哪里指定的?
- 其实是在@EnableAutoConfiguration注解中:
3.@EnableAutoConfiguration注解
@EnableAutoConfiguration注解源码:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
...
}
可以看到@EnableAutoConfiguration注解也是一个合成注解
我们先来看:
-
@AutoConfigurationPackage注解:
-
根据名称我们就能推导出这个注解的功能, 就是自动配置包, 那么就是我们本篇文章的核心了, 那么是如何自动配置包的? 我们就来看一下这个注解的源码:
-
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Import(AutoConfigurationPackages.Registrar.class) public @interface AutoConfigurationPackage { ... }
可以看到该注解其实是一个@Import注解, 那么这个Import注解的功能又是什么?
-
我们知道@Import注解的功能是导入一个组件, 那么这里导入的组件是什么?
-
我们点入到AutoConfigurationPackages.Registrar.class类中查看一下
-
这里其实是@Import注解的一个高级用法, @Import高级 : 使用@ImportBeanDefinitionRegister, 这就是我们自定义了一个类, 使用该类中的方法可以手动完成对组件的注册, 我们点击到源码中可以看到:
-
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports { @Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0])); } @Override public Set<Object> determineImports(AnnotationMetadata metadata) { return Collections.singleton(new PackageImports(metadata)); } }
可以看到有一个registerBeanDefinitions()方法, 该方法中使用registry对象注册了对应的一些组件, 那么是注册了哪些组件?
- new PackageImports(metadata).getPackageNames().toArray(new String[0])其实就是获取的注解所在的类的元信息, 通过这些元信息, 就可以获取到该类所在的包, 然后直接对这个包中的所有组件都进行了注册, 也就是导入到了容器中
-
-
-