文章目录
前言
需要明确的是 本文仅仅是演示一个调用过程,读者需要对 spring有一个基本的认知
案例
@ComponentScan
public class BeanContext {
public static void main(String[] args) {
AnnotationConfigApplicationContext ax = new AnnotationConfigApplicationContext(BeanContext.class);
}
}
@Configuration
public class BeanBeanA {
@Bean
public BeanBeanB getB() {
return new BeanBeanB();
}
}
public class BeanBeanB {
}
扫描 Bean
扫描 Bean 仅仅是扫描 @Component
注解或者 派生注解而我们的 @Configuration
属于是派生注解所以 配置类会被扫描到
protected final SourceClass doProcessConfigurationClass(
ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
throws IOException {
// 处理 @ComponentScan 注解
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
// 判断如果 如果 componentScans 不是空
if (!componentScans.isEmpty() &&!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
// 循环所有 @ComponentScan
for (AnnotationAttributes componentScan : componentScans) {
// 这个Class 是有 @ComponentScan -> 立即执行扫描
// 去执行解析...
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// 循环所有的 符合条件的 BeanDefinitionHolder
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
//检测有没有 @Configuration 、@Component、@ComponentScan、@Import、@ImportResource 注解
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
//这里是去 递归调用去了...
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// No superclass -> processing is complete
return null;
}
处理 @Bean 注解
通过 扫描到 @Configuration
会进行一个判断,判断是否是 一些特定注解,当是的时候会进行 递归调用
protected final void parse(@Nullable String className, String beanName) throws IOException {
// 通过className 解析成 MetadataReader 对象 ,也就是元数据
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
// 构建了一个 ConfigurationClass 对象
processConfigurationClass(new ConfigurationClass(reader, beanName), DEFAULT_EXCLUSION_FILTER);
}
- 递归调用…
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
// 判断是否应该被跳过
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
//处理 Imported 的情况,只有在递归的什么才能获取到
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
// 如果不是NUll
if (existingClass != null) {
//
if (configClass.isImported()) {
if (existingClass.isImported()) {
existingClass.mergeImportedBy(configClass);
}
// Otherwise ignore new imported config class; existing non-imported class overrides it.
return;
} else {
// Explicit bean definition found, probably replacing an import.
// Let's remove the old one and go with the new one.
this.configurationClasses.remove(configClass);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
}
// 从当前配置类 configClass 开始向上沿着类继承结构逐层执行 doProcessConfigurationClass,
// 直到遇到的父类是由Java提供的类结束循环
SourceClass sourceClass = asSourceClass(configClass, filter);
do {
// 去处理 Configuration 相关的类
sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
}
while (sourceClass != null);
//添加到configurationClasses中
this.configurationClasses.put(configClass, configClass);
}
- 这里又调回来了,当然这里精简了大量的代码
protected final SourceClass doProcessConfigurationClass(
ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
throws IOException {
// 获取 目标类标所有注了 @Bean 注解的方法
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
// 将包装成 BeanMethod 放到 集合当中...
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
return null;
}
- 获取所有 标有@Bean 注解的方法
private Set<MethodMetadata> retrieveBeanMethodMetadata(SourceClass sourceClass) {
// 获取目标类 元数据
AnnotationMetadata original = sourceClass.getMetadata();
// 获取 目标类 标注了 @Bean 注解的所有方法,将其包装成 MethodMetadata
Set<MethodMetadata> beanMethods = original.getAnnotatedMethods(Bean.class.getName());
// 当 不是 NUll的 时候 并且 采用的是 JAVA 反射的时候才会走这里
if (beanMethods.size() > 1 && original instanceof StandardAnnotationMetadata) {
// 尝试通过 ASM 读取类文件,确定声明顺序…
// 不同的是,JVM的标准反射以随机的方式返回方法,即使是在相同JVM和相同应用程序的不同运行之间也是如此。
// 省略代码 ..
}
return beanMethods;
}
说明
- 获取所有 @Bean 注解的所有方法包装成
MethodMetadata
放进ConfigurationClass
Map中 - 当执行完
processConfigurationClass()
后也就将ConfigurationClass
放进configurationClasses
Map中
注册 @Bean 方法
将 @Bean 注解标注的方法注册 到 容器中,这里精简了大量的代码…
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
do {
//这里是去解析
parser.parse(candidates); //这里执行完毕
//去校验
parser.validate();
// 获取到 放到 Map 的所有 key 包括我们的 BeanBeanB
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
//这里处理
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
}
while (!candidates.isEmpty());
}
loadBeanDefinitions
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
// 循环
for (ConfigurationClass configClass : configurationModel) {
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
}
}
loadBeanDefinitionsForConfigurationClass
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
// 精简了大量的代码...
//遍历配置类上所有的@Bean方法返回的bean并注册
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
// 这里是去处理 装载了 @Bean 下的Model
loadBeanDefinitionsForBeanMethod(beanMethod);
}
// 精简了大量的代码...
}
loadBeanDefinitionsForBeanMethod
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
// 获取 目标类
ConfigurationClass configClass = beanMethod.getConfigurationClass();
// 获取目标类的元数据
MethodMetadata metadata = beanMethod.getMetadata();
// 获取 方法名称
String methodName = metadata.getMethodName();
// 根据条件判断 是否跳过
if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
configClass.skippedBeanMethods.add(methodName);
return;
}
if (configClass.skippedBeanMethods.contains(methodName)) {
return;
}
// 将 @Bean 注解的属性进行解析
AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
// @Bean.name解析
List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
// 获取第一个别名,没有别名就用方法名
String beanName = (!names.isEmpty() ? names.remove(0) : methodName);
// 注册别名 beanName----别名
for (String alias : names) {
//注册剩下的别名 放到别名Map中 ,key 是别名 value 是名称
this.registry.registerAlias(beanName, alias);
}
// 之前是否已经有效地覆盖了此内容(例如通过XML)?
if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
if (beanName.equals(beanMethod.getConfigurationClass().getBeanName())) {
throw new BeanDefinitionStoreException(beanMethod.getConfigurationClass().getResource().getDescription(),
beanName, "Bean name derived from @Bean method '" + beanMethod.getMetadata().getMethodName() +
"' clashes with bean name for containing configuration class; please make those names unique!");
}
return;
}
// 封装为 ConfigurationClassBeanDefinition,表示是来自配置类里的bean定义
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
// 设置 来源的 类
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
// 是否是静态方法
if (metadata.isStatic()) {
// static @Bean method
if (configClass.getMetadata() instanceof StandardAnnotationMetadata) {
beanDef.setBeanClass(((StandardAnnotationMetadata) configClass.getMetadata()).getIntrospectedClass());
}
else {
beanDef.setBeanClassName(configClass.getMetadata().getClassName());
}
//设置工厂方法的名字,也就是方法名
beanDef.setUniqueFactoryMethodName(methodName);
}
else {
//设置 FactoryBeanName 也就说 这里设置的是 (谁)去调用我们这个 标注了 @Bean 注解的方法
beanDef.setFactoryBeanName(configClass.getBeanName());
// 设置: FactoryMethodName =方法名称
// 设置: isFactoryMethodUnique=true,默认是False
beanDef.setUniqueFactoryMethodName(methodName);
}
if (metadata instanceof StandardMethodMetadata) {
beanDef.setResolvedFactoryMethod(((StandardMethodMetadata) metadata).getIntrospectedMethod());
}
// 设置自定装配模式默认是构造器
beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
// 设置一个上下文属性
beanDef.setAttribute(org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.
SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);
//处理通用注解,注解里可能还有自动装配注解等
AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);
// 解析 @Bean.autowire 自动装配
Autowire autowire = bean.getEnum("autowire");
// 如果存在
if (autowire.isAutowire()) {
// 如果是自动装配,也就是 BY_NAME 或者 BY_TYPE,再设置了一次自动装配模式
beanDef.setAutowireMode(autowire.value());
}
// 解析 @Bean.autowireCandidate 自动装配候选,默认是true
boolean autowireCandidate = bean.getBoolean("autowireCandidate");
if (!autowireCandidate) {
beanDef.setAutowireCandidate(false);
}
// 获取初始化 方法的名称
String initMethodName = bean.getString("initMethod");
if (StringUtils.hasText(initMethodName)) {
beanDef.setInitMethodName(initMethodName);
}
//获取销毁 方法的名称
String destroyMethodName = bean.getString("destroyMethod");
beanDef.setDestroyMethodName(destroyMethodName);
// 默认是 不创建代理
ScopedProxyMode proxyMode = ScopedProxyMode.NO;
// 解析 @Scope 注解
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);
// 如果 不是 Null 则代表了设置了 @Scope 的范围
if (attributes != null) {
beanDef.setScope(attributes.getString("value"));
proxyMode = attributes.getEnum("proxyMode");
// 如果是默认的 则设置为 不进行代理
if (proxyMode == ScopedProxyMode.DEFAULT) {
proxyMode = ScopedProxyMode.NO;
}
}
// Replace the original bean definition with the target one, if necessary
BeanDefinition beanDefToRegister = beanDef;
if (proxyMode != ScopedProxyMode.NO) {
BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(
new BeanDefinitionHolder(beanDef, beanName), this.registry,
proxyMode == ScopedProxyMode.TARGET_CLASS);
beanDefToRegister = new ConfigurationClassBeanDefinition(
(RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata);
}
// 去注册
this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}
后言
本文讲述了 @Bean
注解方法是如何被扫描到 如何处理注解 最后包装成 BeanDefinition 注册到容器中去了
流程图
参考
扫描注解:这偏文章讲述了是如何扫描的