Spring Boot自动装配(三)
在EnableAutoConfiguration类中,还存在一个注解AutoConfigurationPackage
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
//将标注类所在的package添加至BasePacks中,为后续扫描组件提供来源。
public @interface AutoConfigurationPackage {
}
同样的套路,我们去分析AutoConfigurationPackages.Registrar.class
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
register(registry, new PackageImport(metadata).getPackageName());
}
@Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new PackageImport(metadata));
}
}
public static void register(BeanDefinitionRegistry registry, String... packageNames) {
//判断org.springframework.boot.autoconfigure.AutoConfigurationPackages是否已经被注册过。
//Bean是一个常量为AutoConfigurationPackages.class.getName();
//这里是考虑到,@EnableAutoConfiguration被标注在多个类上,这样,Registrar就会被多次@Import。
if (registry.containsBeanDefinition(BEAN)) {
//直接从容器中拿到bean
BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);
//获取constructorArgumentValues,并添加包路径。
ConstructorArgumentValues constructorArguments = beanDefinition
.getConstructorArgumentValues();
constructorArguments.addIndexedArgumentValue(0,
addBasePackages(constructorArguments, packageNames));
}
else {
//初始化beanDefinition,实例为BasePackages
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(BasePackages.class);
//获取constructorArgumentValues,并添加包路径。
beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0,
packageNames);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
//将初始化的beanDefinition注册到Spring容器中。
registry.registerBeanDefinition(BEAN, beanDefinition注册到Spring容器中。);
}
}
在初始化beanDefinition中,beanDefinition.setBeanClass(BasePackages.class);
static final class BasePackages {
private final List<String> packages;
private boolean loggedBasePackageInfo;
BasePackages(String... names) {
List<String> packages = new ArrayList<>();
for (String name : names) {
if (StringUtils.hasText(name)) {
packages.add(name);
}
}
this.packages = packages;
}
public List<String> get() {
if (!this.loggedBasePackageInfo) {
if (this.packages.isEmpty()) {
if (logger.isWarnEnabled()) {
logger.warn("@EnableAutoConfiguration was declared on a class "
+ "in the default package. Automatic @Repository and "
+ "@Entity scanning is not enabled.");
}
}
else {
if (logger.isDebugEnabled()) {
String packageNames = StringUtils
.collectionToCommaDelimitedString(this.packages);
logger.debug("@EnableAutoConfiguration was declared on a class "
+ "in the package '" + packageNames
+ "'. Automatic @Repository and @Entity scanning is "
+ "enabled.");
}
}
this.loggedBasePackageInfo = true;
}
return this.packages;
}
}
首次构造时,将当前标注类所在的package作为参数传入,后续更改时,获取ConstructArgumentValues,追加其中。后续可以根据get()方法直接获取packages。
应用实例:AutoConfigurationPackages#get()
public static List<String> get(BeanFactory beanFactory) {
try {
return beanFactory.getBean(BEAN, BasePackages.class).get(