spring-@Bean-源码

前言

需要明确的是 本文仅仅是演示一个调用过程,读者需要对 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;
}

说明

  1. 获取所有 @Bean 注解的所有方法包装成 MethodMetadata 放进 ConfigurationClassMap中
  2. 当执行完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 注册到容器中去了

流程图

在这里插入图片描述

参考

扫描注解:这偏文章讲述了是如何扫描的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值