引言:主要是为了个人学习,方便后期查看。
SpringBoot的入口
@SpringBootApplication
public class MallTany01Application {
public static void main(String[] args) {
SpringApplication.run(MallTany01Application.class, args);
}
}
@SpringBootApplication
注解标注主程序类,表明这是一个Spring Boot应用。
@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 {
其中@SpringBootConfiguration
表明该类是springBoot的配置类。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
其中包含@Configuration
注解,@Configuration
就是告诉SpringBoot这是一个配置类,相当于Spring中的xml配置文件。此外在@Configuration
包含元注解@Component
。@Component
他的作用就是给IOC容器添加组件 。
所以@SpringBootConfiguration
注解的作用就是标识一个配置类,并且添加到IOC容器中。
@EnableAutoConfiguration
为自动配置注解。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
}
@AutoConfigurationPackage
:自动配置包。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
其中@Import
注解的作用为向容器中添加组件。接下来简单解释一下@Import
注解。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
/**
* {@link Configuration @Configuration}, {@link ImportSelector},
* {@link ImportBeanDefinitionRegistrar}, or regular component classes to import.
*/
Class<?>[] value();
}
@Import
可以传入 Configuration,ImportSelector,ImportBeanDefinitionRegistrar,regular component classes。此处的@Import
传入的是实现了ImportBeanDefinitionRegistrar
接口的类。
ImportBeanDefinitionRegistrar
接口
public interface ImportBeanDefinitionRegistrar {
/**
* Register bean definitions as necessary based on the given annotation metadata of
* the importing {@code @Configuration} class.
* <p>Note that {@link BeanDefinitionRegistryPostProcessor} types may <em>not</em> be
* registered here, due to lifecycle constraints related to {@code @Configuration}
* class processing.
* <p>The default implementation delegates to
* {@link #registerBeanDefinitions(AnnotationMetadata, BeanDefinitionRegistry)}.
* @param importingClassMetadata annotation metadata of the importing class
* @param registry current bean definition registry
* @param importBeanNameGenerator the bean name generator strategy for imported beans:
* {@link ConfigurationClassPostProcessor#IMPORT_BEAN_NAME_GENERATOR} by default, or a
* user-provided one if {@link ConfigurationClassPostProcessor#setBeanNameGenerator}
* has been set. In the latter case, the passed-in strategy will be the same used for
* component scanning in the containing application context (otherwise, the default
* component-scan naming strategy is {@link AnnotationBeanNameGenerator#INSTANCE}).
* @since 5.2
* @see ConfigurationClassPostProcessor#IMPORT_BEAN_NAME_GENERATOR
* @see ConfigurationClassPostProcessor#setBeanNameGenerator
*/
default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
BeanNameGenerator importBeanNameGenerator) {
registerBeanDefinitions(importingClassMetadata, registry);
}
/**
* Register bean definitions as necessary based on the given annotation metadata of
* the importing {@code @Configuration} class.
* <p>Note that {@link BeanDefinitionRegistryPostProcessor} types may <em>not</em> be
* registered here, due to lifecycle constraints related to {@code @Configuration}
* class processing.
* <p>The default implementation is empty.
* @param importingClassMetadata annotation metadata of the importing class
* @param registry current bean definition registry
*/
default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
}
}
其中registerBeanDefinitions
方法中包含有2个参数:
-
AnnotationMetadata:导入类的注解原信息
-
BeanDefinitionRegistry:注册当前bean。
-
BeanDefinitionRegistry
接口存在void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException;
其中
beanName
:bean的名字。beanDefinition
:bean的定义。在此处。
beanDefinition
是通过他的实现类GenericBeanDefinition
来创建的
-
回到主题。@Import(AutoConfigurationPackages.Registrar.class)
。@Import
注解中放入的是AutoConfigurationPackages.Registrar.class
。
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));
}
}
从Registrar
类中可以看出,它继承了ImportBeanDefinitionRegistrar
接口。实现了registerBeanDefinitions
方法。
其中 register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
包含有2个参数
-
registry
:BeanDefinitionRegistry,用来注册bean -
new PackageImports(metadata).getPackageNames().toArray(new String[0])
-
private static final class PackageImports { private final List<String> packageNames; PackageImports(AnnotationMetadata metadata) { AnnotationAttributes attributes = AnnotationAttributes .fromMap(metadata.getAnnotationAttributes(AutoConfigurationPackage.class.getName(), false)); List<String> packageNames = new ArrayList<>(); for (String basePackage : attributes.getStringArray("basePackages")) { packageNames.add(basePackage); } for (Class<?> basePackageClass : attributes.getClassArray("basePackageClasses")) { packageNames.add(basePackageClass.getPackage().getName()); } //packageNames初始时为空。 if (packageNames.isEmpty()) { packageNames.add(ClassUtils.getPackageName(metadata.getClassName())); } this.packageNames = Collections.unmodifiableList(packageNames); }
packageNames.add(ClassUtils.getPackageName(metadata.getClassName()));
其中metadata.getClassName()
使用的AnnotationMetadata
接口实现类StandardAnnotationMetadata
下的getclassName()
方法 。@Override public String getClassName() { return this.introspectedClass.getName(); }
private final Class<?> introspectedClass;
所以
metadata.getClassName()
得到是introspectedClass。也就是标注注解的原始类。实验中MallTany01Application
的全类名为class com.zwd.mall.tany01.MallTany01Application
因此
this.packageNames
为com.zwd.mall.tany01
register(registry, com.zwd.mall.tany01);
public static void register(BeanDefinitionRegistry registry, String... packageNames) { //是否包含org.springframework.boot.autoconfigure.AutoConfigurationPackages,初始时不包含 if (registry.containsBeanDefinition(BEAN)) { BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN); ConstructorArgumentValues constructorArguments = beanDefinition.getConstructorArgumentValues(); constructorArguments.addIndexedArgumentValue(0, addBasePackages(constructorArguments, packageNames)); } else { //new了一个BeanDefinitionRegistry接口的实现类,利用该实现类来定义bean GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); beanDefinition.setBeanClass(BasePackages.class); beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, packageNames); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); //注册com.zwd.mall.tany01下的bean registry.registerBeanDefinition(BEAN, beanDefinition); } }
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration {
@Import(AutoConfigurationImportSelector.class)
此处导入了AutoConfigurationImportSelector
类public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
-
其中public interface DeferredImportSelector extends ImportSelector {}
在前面@Inport
中就可以传入实现了ImportSelector
接口的类
public interface ImportSelector {
/**
* Select and return the names of which class(es) should be imported based on
* the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
* @return the class names, or an empty array if none
*/
String[] selectImports(AnnotationMetadata importingClassMetadata);
/**
* Return a predicate for excluding classes from the import candidates, to be
* transitively applied to all classes found through this selector's imports.
* <p>If this predicate returns {@code true} for a given fully-qualified
* class name, said class will not be considered as an imported configuration
* class, bypassing class file loading as well as metadata introspection.
* @return the filter predicate for fully-qualified candidate class names
* of transitively imported configuration classes, or {@code null} if none
* @since 5.2.4
*/
@Nullable
default Predicate<String> getExclusionFilter() {
return null;
}
}
selectImports
方法返回一个字符串数组。返回的是要导入类的名称。
AnnotationMetadata
:当前标注Import注解的所有信息。
所以在类AutoConfigurationImportSelector
中我们定位到 selectImports
方法
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
//返回到导入的类的名称
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
方法
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//此处是获取配置类
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
SpringFactoriesLoader.loadFactoryNames(
interface org.springframework.boot.autoconfigure.EnableAutoConfiguration,
类加载器);
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
//工厂名:org.springframework.boot.autoconfigure.EnableAutoConfiguration
String factoryTypeName = factoryType.getName();
//加载spring工厂
return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
//FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
//加载所有META-INF/spring.factories下的自动配置文件
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
下图列出的是
jar:file:/D:/InstallationPath/m2/repository/org/springframework/boot/spring-boot/2.3.4.RELEASE/spring-boot-2.3.4.RELEASE.jar!/META-INF/spring.factories下的配置类
所有spring.factories下的配置类
最后在得到的result中找到前缀为org.springframework.boot.autoconfigure.EnableAutoConfiguration
的配置类
这样就完成了初始化自动配置加载。
总结
@AutoConfigurationPackage
:加载主程序入口所在包下的所有组件@Import(AutoConfigurationImportSelector.class)
:将/META-INF/spring.factories
中所有前缀为org.springframework.boot.autoconfigure.EnableAutoConfiguration
的配置进行加载。