ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

@Autowired实现流程

2022-08-06 19:00:44  阅读:152  来源: 互联网

标签:调用 Autowired 实现 流程 beanName bean 实例 注解 BeanDefinition


@Autowired实现流程

与xml配置方式相比,开启注解处理之后在加载BeanDefinition时会额外添加几个用于处理注解的组件,一个BeanDefinitionRegistryPostProcessor和若干个BeanPostProcessor,这些组件用于在bean的各个生命周期中对标注的注解做相应的处理。

大体流程与不使用注解的方式类似,使用注解的方式只是在某些阶段额外做了一些对于注解的处理。开启注解扫描其实就是在原有的基础上增加了一些功能。

初始化工厂,加载BeanDefinition

同样使用XmlBeanDefinitionReader先将xml配置文件封装为Resource,然后将Resource转成流并使用DOM解析得到Document,然后从根节点开始遍历所有节点。

当扫描到<context:component-scan base-package="bean"/>标签时,会加载用来解析该节点所属namespace的NamespaceHandler,namespace与NamespaceHandler的对应关系在META-INF\spring.handlers文件中,因此会加载ContextNamespaceHandler用来处理\<context:component-scan/>标签。

通过调用Class.forName()实例化ContextNamespaceHandler,并调用其init()方法,在init()方法中会注册该namespace下每个标签对应的BeanDefinitionParser,保存在一个Map中。

@Override
public void init() {
    registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
    registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
    registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
    registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
    registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
    registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
    registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
    registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
}

然后找到与<context:component-scan\>标签对应的BeanDefinitionPaser,调用parse()方法开始解析。

public BeanDefinition parse(Element element, ParserContext parserContext) {
	//...
    // Actually scan for bean definitions and register them.
    ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
    //扫描并注册BeanDefinition
    Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
    //注册处理注解相关的其他组件
    registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
    return null;
}

doScan()方法会扫描并注册BeanDefinition,流程如下:

首先获取标签的base-package属性的值,扫描该包下的所有*.class文件并包装成Resource,遍历每个Resource,获取其元数据,判断该类上是否有@Component注解(@Service@Repository@Controller其实都被@Component标注),并且判断是否有@Conditional注解,如果不符合条件则跳过,符合条件则将该Resource转换为BeanDefinition注册到beanFactory的Map中。

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Assert.notEmpty(basePackages, "At least one base package must be specified");
    Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
    //遍历指定的每个包
    for (String basePackage : basePackages) {
        //扫描当前包下含有@Component的类并封装为BeanDefinition
        Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
        //处理每个BeanDefinition并判断是否需要注册到容器中
        for (BeanDefinition candidate : candidates) {
            ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
            candidate.setScope(scopeMetadata.getScopeName());
            String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
            if (candidate instanceof AbstractBeanDefinition) {
                postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
            }
            if (candidate instanceof AnnotatedBeanDefinition) {
                AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
            }
            //判断该BeanDefinition是否应该注入到容器中
            if (checkCandidate(beanName, candidate)) {
                BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                definitionHolder =
                    AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                beanDefinitions.add(definitionHolder);
                //将BeanDefinition注册到容器中
                registerBeanDefinition(definitionHolder, this.registry);
            }
        }
    }
    return beanDefinitions;
}

findCandidateComponents()方法中会调用isCandidateComponent()方法根据Resource的元数据判断当前类上是否含有@Component注解,如果没有则跳过该类,如果有则判断当前类是否还标注了@Conditional注解,如果标注了则会去处理@Conditional注解判断当前类是否需要跳过。如果该类符合条件则将其封装为BeanDefinition返回。对于每一个BeanDefinition都要根据其类型做相应的处理,例如依据@Lazy注解设置该BeanDefinition的属性。对BeanDefinition做完相应的处理之后会判断每一个BeanDefinition是否应该被注入到容器中,判断条件是:如果容器中不存在beanName相同的BeanDefinition则直接将该BeanDefinition注入到容器中,否则不注册。

至此,doScan()方法结束,也就是说@Component所标记的类已经被封装为BeanDefinition注册到容器中,接下来会调用registerComponents()方法向容器中注入一些处理注解所需要的组件。

registerComponents()方法首先会判断\<context:component-scan>标签的annotation-config的属性是否为true(默认为true,除非在xml中显示配置为false),该属性表示将来是否需要处理已加载到容器中的bean中包含的注解。如果此属性配置为true,则会在注册完@Component标记的类之后会注册一系列处理注解需要的组件,新注册的组件为:ConfigurationClassPostProcessorAutowiredAnnotationBeanPostProcessorEventListenerMethodProcessorDefaultEventListenerFactory

至此,<context:component-scan>标签处理完毕,接着会处理xml中的其他标签,直到对应的BeanDefinition全部注册到容器中。

实例化并有序调用BeanFactoryPostProcessor

大体上分为:分类->排序->调用。首先会实例化并调用BeanDefinitionRegistryPostProcessor接口的实现类,在这里会调用之前注册的ConfigurationClassPostProcessor,因为这个类实现了BeanDefinitionRegistryPostProcessor接口(BeanFactoryPostProcessor接口的扩展),可以在所有BeanDefinition注册到容器之后做一些操作。这个类用于处理与配置相关的注解,比如@Configuration@PropertySources@ComponentScans@ImportResource等注解。

BeanDefinitionRegistryPostProcessor接口的实现类实例化并调用完成后,会实例化并调用仅实现了BeanFactoryPostProcessor接口的类的对应方法。

实例化并有序注册BeanPostProcessor

大体上也分为:分类->排序->注册,这里会将之前添加的AutowiredAnnotationBeanPostProcessor实例化并注册,这个BeanPostProcessor主要用来处理@Autowired注解。

实例化Bean

实例化bean之前会调用InstantiationAwareBeanPostProcessor接口的postProcessBeforeInstantiation()方法,然后从BeanDefinition中拿到Class并实例化对象,实例化之后会调用MergedBeanDefinitionPostProcessor接口的postProcessMergedBeanDefinition()方法。AutowiredAnnotationBeanPostProcessor也实现了该接口,在这个方法中会扫描被实例化的这个bean的注解信息并包装成InjectionMetadata,里面包含所有字段和方法上的注解信息,然后以beanName为key、封装的注解元数据为value缓存到injectionMetadataCache中。

public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
    InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
    metadata.checkConfigMembers(beanDefinition);
}
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
    //...
    InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
    if (InjectionMetadata.needsRefresh(metadata, clazz)) {
        synchronized (this.injectionMetadataCache) {
            metadata = this.injectionMetadataCache.get(cacheKey);
            if (InjectionMetadata.needsRefresh(metadata, clazz)) {
                if (metadata != null) {
                    metadata.clear(pvs);
                }
                //构建自动注入元数据
                //使用反射处理所有属性和方法,将注解信息包装为InjectionMetadata
                metadata = buildAutowiringMetadata(clazz);
                //将InjectionMetadata添加至Map缓存
                this.injectionMetadataCache.put(cacheKey, metadata);
            }
        }
    }
    return metadata;
}

所有的MergedBeanDefinitionPostProcessor调用完成后,会将实例化后但没填充属性的bean保存到三级缓存中用来解决循环依赖,最后调用InstantiationAwareBeanPostProcessor接口的postProcessAfterInstantiation()方法。

接着在填充属性之前会调用所有InstantiationAwareBeanPostProcessor接口实现类的postProcessProperties()方法,在这里会调用AutowiredAnnotationBeanPostProcessorpostProcessProperties()方法。

在这个方法中,首先会依据beanName为key从之前构建的injectionMetadataCache中找到该bean对应的注解元数据InjectionMetadata,注解元数据中指明了哪些成员变量或方法包含了哪些注解,表示成员变量需要注入的依赖对象。拿到InjectionMetadata后会处理每一个标有@Autowired的成员变量(或方法)。这种被标注的成员变量被封装为InjectedElement,然后为每一个element调用inject()方法寻找并注入所需bean。

protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
    Field field = (Field) this.member;
    Object value;
    //缓存过则直接从缓存中拿
    if (this.cached) {
        value = resolvedCachedArgument(beanName, this.cachedFieldValue);
    }
    else {
        //...
        try {
            //解析需要注入的依赖值
            value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
        }
        //将获取的依赖缓存起来
        //...
    }
    if (value != null) {
        ReflectionUtils.makeAccessible(field);
        //使用反射直接为成员变量赋值,因此@Autowired注入不需要提供setXX()方法
        field.set(bean, value);
    }
}

inject()方法中会调用beanFactory.resolveDependency()来解析需要注入的依赖值,里面调用doResolveDependency()方法,主要解析步骤如下:
首先会使用反射查看该变量是否有@Value注解,如果有则获取注解中指定的值并返回。如果没有@Value注解则说明该变量需要注入容器中的bean,那么就会调用findAutowireCandidates()方法去容器中寻找所需类型的bean,如果容器中存在已经完全实例化过的bean则将bean实例返回,否则会从BeanDefinition中找到Class并返回。如果返回的是该bean的Class,则会在resolveCandidate()方法中调用beanFactory.getBean()方法来获取bean的实例(如果发生循环引用则会在三级缓存中得到bean的提前引用)。最后使用反射将获取到的bean注入到@Autowired标注的变量里(这里可以看出@Autowired不需要提供set(XX)方法,而xml设置属性必须提供对应的set(XX)方法,因为xml设置属性值是通过反射调用对应属性的setXX()方法实现的)。

public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
          @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
    
    try {
        //...
        Class<?> type = descriptor.getDependencyType();
        //尝试从@Value注解中获取到应被注入的值
        Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
        if (value != null) {
            //...
            //解析得到的值,判断是否需要转换
            //如果需要转换则转换成功后直接return
            //...
        }
        //判断需要注入的成员变量是否为数组、Collection、Map,查找值并做相应的转换操作
        Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
        if (multipleBeans != null) {
            return multipleBeans;
        }
        //如果以上都不是则说明需要注入一个容器中的其他bean
        //寻找符合条件的bean,返回的可能是bean实例,也可能是Class
        Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);

        //多个bean符合条件则判断应该使用哪一个
        if (matchingBeans.size() > 1) {
            //根据BeanDefinition的isPrimary属性判断应该使用哪个
            autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
            //...
            //根据符合条件的name从众多候选bean中得到符合条件的bean
            instanceCandidate = matchingBeans.get(autowiredBeanName);
        }
        else {
            //只找到唯一的一个符合条件的bean或Class
            Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
            autowiredBeanName = entry.getKey();
            instanceCandidate = entry.getValue();
        }

        //如果前面得到的是符合条件的Class,则在这里调用resolveCandidate()方法
        //里面调用了beanFactory.getBean(beanName)方法获取bean
        //如果该bean未实例化则跳转去执行bean的实例化操作(getBean()方法都能做到)
        if (instanceCandidate instanceof Class) {
            instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
        }
        Object result = instanceCandidate;
        //省略判null操作...
        return result;
    }
}

至此@Autowired注解已经处理完毕,接着会继续走bean的生命周期流程,如果在xml中指定了bean成员变量的值,则在这里会将xml中指定的值赋给bean的成员变量(如果之前通过@Value指定初始值则在这里会被xml中指定的值覆盖)。

关于xml和注解同时定义bean的优先级问题

  1. 如果xml里先定义了一个bean,之后在处理<context:component-scan/>标签时(即扫描注解指定的bean时)不能再注册同名的bean。

  2. 如果先通过注解注册了一个bean(即<context:component-scan/>标签位于<bean>标签之上,所以先被解析),那么之后在处理<bean>标签时,会先判断allowBeanDefinitionOverriding标志是否为true(默认为true),如果允许覆盖则xml里定义的bean会覆盖注解注入的bean,如果不允许覆盖则抛异常。

    总结:如果容器允许覆盖BeanDefinition则xml中定义的bean会覆盖掉注解定义的bean,反之不成立。

标签:调用,Autowired,实现,流程,beanName,bean,实例,注解,BeanDefinition
来源: https://www.cnblogs.com/callme86/p/16557702.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有