概述
Storing auto-configuration packages for reference later (e.g. by JPA entity scanner).
保存自动配置类以供之后的使用,比如给JPA entity
扫描器用来扫描开发人员通过注解@Entity
定义的entity
类。
具体来讲,是注册如下bean
定义到容器 :
bean
名称 :org.springframework.boot.autoconfigure.AutoConfigurationPackages
bean
类 :AutoConfigurationPackages$BasePackages
bean
角色 : 基础设施bean
实例构造函数第一个参数 : 被使用类所在包名 (比如@SpringBootApplication
注解所在类的包名)
该Bean
的注册主要是由如下在应用程序入口类上的注解@SpringBootApplication
引入的 :
@SpringBootApplication
=> @EnableAutoConfiguration
=> @AutoConfigurationPackage
=> @Import(AutoConfigurationPackages.Registrar.class)
源代码分析
1. 注册时机
该Bean
的注册发生在Spring boot
应用的启动过程中的如下位置 :
SpringApplication.run()
=> refreshContext()
=> EmbeddedWebApplicationContext.refresh()
=> AbstractApplicationContext.invokeBeanFactoryPostProcessors()
=> PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()
=> ConfigurationClassPostProcessor.processConfigBeanDefinitions()
=> ConfigurationClassBeanDefinitionReader.loadBeanDefinitions()
=> loadBeanDefinitionsFromRegistrars()
=> AutoConfigurationPackages$Registrar.registerBeanDefinitions()
=> AutoConfigurationPackages.register()
2. 注册逻辑
该Bean
的注册逻辑如下
// AutoConfigurationPackages 类
// 定义Bean的名称
// org.springframework.boot.autoconfigure.AutoConfigurationPackages
private static final String BEAN = AutoConfigurationPackages.class.getName();
/**
* Programmatically registers the auto-configuration package names.
* 程序方式注册自动配置包的名称。
* Subsequent invocations will add the given package names to those that have
* already been registered. You can use this method to manually define the base
* packages that will be used for a given BeanDefinitionRegistry. Generally it's
* recommended that you don't call this method directly, but instead rely on the
* default convention where the package name is set from your @EnableAutoConfiguration
* configuration class or classes.
* @param registry the bean definition registry
* @param packageNames the package names to set , 缺省配置spring boot web应用的情况下,
* 这里是应用程序入口类所在的包
*/
public static void register(BeanDefinitionRegistry registry, String... packageNames) {
// 这里参数 packageNames 缺省情况下就是一个字符串,是使用了注解
// @SpringBootApplication 的 Spring Boot 应用程序入口类所在的包
if (registry.containsBeanDefinition(BEAN)) {
// 如果该bean已经注册,则将要注册包名称添加进去
BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);
ConstructorArgumentValues constructorArguments = beanDefinition
.getConstructorArgumentValues();
constructorArguments.addIndexedArgumentValue(0,
addBasePackages(constructorArguments, packageNames));
}
else {
//如果该bean尚未注册,则注册该bean,参数中提供的包名称会被设置到bean定义中去
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(BasePackages.class);
beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0,
packageNames);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(BEAN, beanDefinition);
}
}