@autowire、@resource原理

@autowire、@resource、@value是我们项目开发中最常用的注解。

对于初学者来说

@value注入配置属性

@autowire根据类型注入

@resource根据名字注入

其实这种理解不是很透彻

今天我们来探索下@autowire的原理。

一、准备测试代码

一个接口类有多个实现类

public interface UserService {

}

--

@Service("userService1")
public class UserService1Impl implements UserService {

}

--
@Service("userService2")
public class UserService2Impl implements UserService {

}

需要注入的类

public interface UniqueService {

    void a();

}

--
@Service
public class UniqueServiceImpl implements UniqueService {

    @Autowired
    private UserService userService1;

    @Value("${test.a}")
    private String a;

    @Override
    public void a() {
        System.out.println(a);
    }
}

xml配置

<context:property-placeholder location="classpath:application.properties"/>
<context:component-scan base-package="com.csy.discuss.core.autowire"/>

二、源码分析

1.AutowiredAnnotationBeanPostProcessor初始化

注:这一点其实大部分知识点都与Spring容器的初始化和Spring命名空间有关。

当spring解析<context:component-scan>标签的时候找到对应的ComponentScanBeanDefinitionParser命名空间解析器

//ComponentScanBeanDefinitionParser#registerComponents

protected void registerComponents(
            XmlReaderContext readerContext, Set<BeanDefinitionHolder> beanDefinitions, Element element) {

    ...

    // Register annotation config processors, if necessary.
    boolean annotationConfig = true;
    if (element.hasAttribute(ANNOTATION_CONFIG_ATTRIBUTE)) {
        annotationConfig = Boolean.valueOf(element.getAttribute(ANNOTATION_CONFIG_ATTRIBUTE));
    }
    if (annotationConfig) {
        Set<BeanDefinitionHolder> processorDefinitions =
                AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);
        for (BeanDefinitionHolder processorDefinition : processorDefinitions) {
            compositeDef.addNestedComponent(new BeanComponentDefinition(processorDefinition));
        }
    }

    readerContext.fireComponentRegistered(compositeDef);
}

因为<context:component-scan>标签annotation-config属性默认为true。所以
调用AnnotationConfigUtils.registerAnnotationConfigProcessors。
里面手动注册了AutowiredAnnotationBeanPostProcessor这个bean。

Spring创建AutowiredAnnotationBeanPostProcessor这个bean的时候调用其构造方法

public AutowiredAnnotationBeanPostProcessor() {
    this.autowiredAnnotationTypes.add(Autowired.class);
    this.autowiredAnnotationTypes.add(Value.class);
    try {
        this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
                ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
        logger.info("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
    }
    catch (ClassNotFoundException ex) {
        // JSR-330 API not available - simply skip.
    }
}

我们可以看到。它初始化了Autowired、Value、Inject三个注解。也就是说这三个注解都是由AutowiredAnnotationBeanPostProcessor来实现的。

2.组装InjectionMetadata

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
    LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();
    Class<?> targetClass = clazz;

    do {
        final LinkedList<InjectionMetadata.InjectedElement> currElements =
                new LinkedList<InjectionMetadata.InjectedElement>();

        ReflectionUtils.doWithLocalFields(targetClass, new ReflectionUtils.FieldCallback() {
            @Override
            public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
                AnnotationAttributes ann = findAutowiredAnnotation(field);
                if (ann != null) {
                    if (Modifier.isStatic(field.getModifiers())) {
                        if (logger.isWarnEnabled()) {
                            logger.warn("Autowired annotation is not supported on static fields: " + field);
                        }
                        return;
                    }
                    boolean required = determineRequiredStatus(ann);
                    currElements.add(new AutowiredFieldElement(field, required));
                }
            }
        });

        ReflectionUtils.doWithLocalMethods(targetClass, new ReflectionUtils.MethodCallback() {
            @Override
            public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
                ...
            }
        });

        elements.addAll(0, currElements);
        targetClass = targetClass.getSuperclass();
    }
    while (targetClass != null && targetClass != Object.class);

    return new InjectionMetadata(clazz, elements);
}

我们可以看两个主方法:doWithLocalFields和doWithLocalMethods。顾名思义,处理属性和方法上的@autowire类注解。也就是说@autowire不仅可以打在类的属性上,还能打在类的方法上。打在方法上我们不做分析,因为基本不用。
然后遍历这个类上所有的属性。筛选出带有@Autowire或@Value或@Inject的属性。最终组装成InjectionMetadata。

3.注入

doCreateBean -> populateBean -> InstantiationAwareBeanPostProcessor#postProcessPropertyValues

AutowiredAnnotationBeanPostProcessor就是继承InstantiationAwareBeanPostProcessor。

public PropertyValues postProcessPropertyValues(
            PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {

    InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
    try {
       // AutowiredFieldElement.inject
        metadata.inject(bean, beanName, pvs);
    }
    catch (BeanCreationException ex) {
        throw ex;
    }
    catch (Throwable ex) {
        throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
    }
    return pvs;
}

首先,就是拿到我们第二步组装好的InjectionMetadata,然后遍历里面的InjectedElement。即遍历这个bean所有带有@Autowire或@Value或@Inject的属性。

AutowiredAnnotationBeanPostProcessor有两个私有内部类AutowiredFieldElement和AutowiredMethodElement,都继承InjectionMetadata的内部类InjectedElement。显而易见,我们要跟踪的是AutowiredFieldElement。

//DefaultListableBeanFactory

public Object doResolveDependency(DependencyDescriptor descriptor, String beanName,
            Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {

    InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
    try {
        Object shortcut = descriptor.resolveShortcut(this);
        if (shortcut != null) {
            return shortcut;
        }

        Class<?> type = descriptor.getDependencyType();
        Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
        
        //@Value注解走这里
        if (value != null) {
            if (value instanceof String) {
                String strVal = resolveEmbeddedValue((String) value);
                BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
                value = evaluateBeanDefinitionString(strVal, bd);
            }
            TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
            return (descriptor.getField() != null ?
                    converter.convertIfNecessary(value, type, descriptor.getField()) :
                    converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
        }
      
        //@Autowire注解走这里
        Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
        if (multipleBeans != null) {
            return multipleBeans;
        }

        Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
        if (matchingBeans.isEmpty()) {
            if (isRequired(descriptor)) {
                raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
            }
            return null;
        }

        String autowiredBeanName;
        Object instanceCandidate;

        if (matchingBeans.size() > 1) {
            autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
            if (autowiredBeanName == null) {
                if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
                    return descriptor.resolveNotUnique(type, matchingBeans);
                }
                else {
                    // In case of an optional Collection/Map, silently ignore a non-unique case:
                    // possibly it was meant to be an empty collection of multiple regular beans
                    // (before 4.3 in particular when we didn't even look for collection beans).
                    return null;
                }
            }
            instanceCandidate = matchingBeans.get(autowiredBeanName);
        }
        else {
            // We have exactly one match.
            Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
            autowiredBeanName = entry.getKey();
            instanceCandidate = entry.getValue();
        }

        if (autowiredBeanNames != null) {
            autowiredBeanNames.add(autowiredBeanName);
        }
        return (instanceCandidate instanceof Class ?
                descriptor.resolveCandidate(autowiredBeanName, type, this) : instanceCandidate);
    }
    finally {
        ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
    }
}

3.1@Value注解链路

这个不多分析了。主要通过PropertySourcesPlaceholderConfigurer去解析

3.2@Autowire注解链路

以测试代码注入的UserService userService1为例。

Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);

candidates老朋友了,候选者的意思。

从bean工厂中捞出UserService类型的bean。以这个bean的名字为key。若bean已经创建完成,那么以这个bean的实例为value。否则以这个bean的类型为value;

对于测试代码的例子来说。有两个候选者。分别是userService1和userService2

如果matchingBeans有多个,那就根据对应属性的名字进行匹配。

return (instanceCandidate instanceof Class ?
                    descriptor.resolveCandidate(autowiredBeanName, type, this) : instanceCandidate);
                    

如果是class类型那么调用beanFactory.getBean进行bean的创建,拿到这个bean的实例。

AutowiredFieldElement#inject的最后几句代码

if (value != null) {
    ReflectionUtils.makeAccessible(field);
    field.set(bean, value);
}

通过反射将属性设置进去。

四、顺便提一下@Resource注解

由CommonAnnotationBeanPostProcessor实现

看beanDefinitionMap里是否有这个属性名称的bean。没有的话根据类型走和@autowire一样的doResolveDependency方法。有这个属性名称的bean,直接创建这个bean。

总结

1.@autowire、@resource、@value是通过调用AutowiredAnnotationBeanPostProcessor这个BeanPostProsess的postProcessPropertyValues方法进行注入的

2.@Autowire不仅可以作用在bean的属性上,还能作用在bean的方法上。

3.@Autowire通过属性的类型进行注入。若这个类型有多种(一个接口类有多个实现类),降级为根据名字来注入

4.@Resource通过属性的名字去容器里找bean的定义。有的话直接创建bean进行注入。没有的话降级为根据类型进行注入

转载于:https://www.cnblogs.com/chenshengyue/p/11453953.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值