其他分享
首页 > 其他分享> > @Autowired实现流程

@Autowired实现流程

作者:互联网

@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