SpringBoot源码阅读:核心 —— 自动装配(1)

主要内容:

  1. @AutoConfigurationPackage是干什么的
  2. 通过什么来获取主启动类包全路径名

SpringBoot的自动注册用@EnableAutoConfiguration来完成
除开元注解,我们来看看这个注解:

@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

	String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

	/**
	 * Exclude specific auto-configuration classes such that they will never be applied.
	 * @return the classes to exclude
	 */
	Class<?>[] exclude() default {};

	/**
	 * Exclude specific auto-configuration class names such that they will never be
	 * applied.
	 * @return the class names to exclude
	 * @since 1.3.0
	 */
	String[] excludeName() default {};

}

@AutoConfigurationPackage
Indicates that the package containing the annotated class should be registered with
表示包含该注解的类所在的包应该在 AutoConfigurationPackages 中注册。

/**
* {@link ImportBeanDefinitionRegistrar} to store the base package from the importing
* configuration.
* 用于保存导入的配置类所在的根包。很明显,它就是实现把主配置所在根包保存起来以便后期扫描用的
*/
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {

}

Registrar

	static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
		@Override
		public void registerBeanDefinitions(AnnotationMetadata metadata,
				BeanDefinitionRegistry registry) {
			register(registry, new PackageImport(metadata).getPackageName());
		}
	}

这个Registrar实现了ImportBeanDefinitionRegistrar,我们看看这个借口中对这个方法的定义:

	 //导入类的元注解信息
	 @param importingClassMetadata annotation metadata of the importing class
	 @param registry current bean definition registry

拿到这个导入类的元注解信息importingClassMetadata后:

register(registry, new PackageImport(metadata).getPackageName());

我们可以看到,是new了一个PackageImport,在其中metadata.getClassName()获取了一个类名,我们点进这个getClassName看看:

public interface ClassMetadata {
	/**
	 * Return the name of the underlying class.
	 */
	String getClassName();
}

我们发现是个接口,我们在这里打个断点测试一下:
在这里插入图片描述
于是我们去这个实现类看看,并且断点测试也自动来到这个实现类的getClassName方法了:

	@Override
	public String getClassName() {
		return this.introspectedClass.getName();
	}

他最终是返回了个这个名字,就拿到了包名:
在这里插入图片描述
在这里插入图片描述

	public static void register(BeanDefinitionRegistry registry, String... packageNames) {
		//判断当前IOC容器中是否包含 AutoConfigurationPackages
		//private static final String BEAN = AutoConfigurationPackages.class.getName();
		if (registry.containsBeanDefinition(BEAN)) {
			BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);
			ConstructorArgumentValues constructorArguments = beanDefinition
					.getConstructorArgumentValues();
			constructorArguments.addIndexedArgumentValue(0,
					addBasePackages(constructorArguments, packageNames));
		}
		else {
			GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
			beanDefinition.setBeanClass(BasePackages.class);
			beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0,
					packageNames);
			beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
			registry.registerBeanDefinition(BEAN, beanDefinition);
		}
	}

在单步调试的结果下:
在这里插入图片描述
这个packageNames就是我们的基包
拿到这个包后做了什么呢
在这里插入图片描述
也解释了为什么 SpringBoot 的启动器一定要在所有类的最外层。

总结:

  1. @AutoConfigurationPackage中封装的注解能帮我们获取到启动类所在包名,并且存储起来供以后扫描使用
  2. 实际上是通过AnnotationMetadata来获取所在包名如下

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值