@Autowire 和 @Resource

在面试的时候经常有面试官会问 @Autowire 和 @Resource 的区别,这篇文章我就通过源码详细的分析 @Autowire 依赖注入的过程和 @Resource 的注入过程,最后再来比较这两者的区别。

可能结果和你之前的认知不一样

@Autowire

既然要分析 @Autowire 的注入过程,首先要了解的是谁来执行注入的。这里就涉及到 Spring 的一个重要知识点BeanPostProcessor,但是本篇文章的重点不是讲解 BeanPostProcessor ,小伙伴们只需要知道实现了这个接口可以做很多事情,而 AutowiredAnnotationBeanPostProcessor 就借此实现了依赖的自动注入。

注入点

在依赖注入的过程中涉及一个重要的知识点就是注入点,什么是注入点呢,简单来说就是需要依赖注入的地方。例如下面代码所示:

public class TestAutowired {
    // 属性注入点
    @Autowired
	private User user;
    
    // 方法注入点
    @Autowired
    public TestAutowired(User user1) {
    }
}

想要依赖注入的话,我们首先要做的事情就是找到所有的注入点。

注入点的查找

注入点的查找,就需要关注 AutowiredAnnotationBeanPostProcessor 中的 postProcessMergedBeanDefinition 方法。

@Override
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) {
    String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
    // 尝试从缓存中获取已经解析好的注入点
    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);
                }
                // 重新解析构建注入点
                metadata = buildAutowiringMetadata(clazz);
                this.injectionMetadataCache.put(cacheKey, metadata);
            }
        }
    }
    return metadata;
}

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
    // 用于存放所有的注入点
    List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
    Class<?> targetClass = clazz;

    do {
        // 用于存放当前类的所有注入点
        final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
        
        // 查找当前类的属性注入点
        ReflectionUtils.doWithLocalFields(targetClass, field -> {
            AnnotationAttributes ann = findAutowiredAnnotation(field);
            if (ann != null) {
                // 忽略 static 类型的属性,如果去掉这段代码,也能成功的注入静态的属性
                // 所以并不是不能注入,只是 Spring 选择不去注入
                if (Modifier.isStatic(field.getModifiers())) {
                    if (logger.isWarnEnabled()) {
                        logger.warn("Autowired annotation is not supported on static fields: " + field);
                    }
                    return;
                }
                // 是否一定要注入,可以通过 required 参数配置
                boolean required = determineRequiredStatus(ann);
                // 添加到注入点列表中
                currElements.add(new AutowiredFieldElement(field, required));
            }
        });

        // 查找当前类的方法注入点
        ReflectionUtils.doWithLocalMethods(targetClass, method -> {
            // 找到被桥接方法或者说非桥接方法
            Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
            if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
                return;
            }
            // 得到标识自动注入的注解
            AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
            if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
                // 同样忽略静态方法,不是不能注入而是 Spring 选择不去注入
                if (Modifier.isStatic(method.getModifiers())) {
                    if (logger.isWarnEnabled()) {
                        logger.warn("Autowired annotation is not supported on static methods: " + method);
                    }
                    return;
                }
                // 如果没有请求参数,说明根本就没有参数可以注入,但是这里并没有选择忽略
                // 所以还是会调用该方法
                if (method.getParameterCount() == 0) {
                    if (logger.isWarnEnabled()) {
                        logger.warn("Autowired annotation should only be used on methods with parameters: " +
                                    method);
                    }
                }
                // 是否一定要注入,可以通过 required 参数配置
                boolean required = determineRequiredStatus(ann);
                // 得到属性描述
                PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                currElements.add(new AutowiredMethodElement(method, required, pd));
            }
        });
		
        // 添加到注入点列表中
        elements.addAll(0, currElements);
        // 递归解析,解析父类的出入点
        targetClass = targetClass.getSuperclass();
    }
    while (targetClass != null && targetClass != Object.class);
    
    // 封装到一个注入元数据,保存了一个类所有的注入点
    return new InjectionMetadata(clazz, elements);
}

依赖注入

依赖注入的入口是 InjectedElement 中的 inject 方法,@Autowired 要注入的 Bean 的选择逻辑在 DefaultListableBeanFactory 中的 doResolveDependency 方法中。所以我们只需要关注这个方法即可。

// DefaultListableBeanFactory
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
                                  @Nullable Set<String> autowiredBeanNames, @Nullable 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);
        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()));
        }
        
        
    	// 处理需要注入的是一个集合的情况,例如 private List<UerService> list;
        Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
        if (multipleBeans != null) {
            return multipleBeans;
        }
        
        // 这里会处理 Qualifier 注解,并得到所有类型和名称匹配的 bean 对象
        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) {
            /*
                1. 处理 @Primary 注解,如果有且仅有一个则返回,如果超过一个抛出异常
                2. 处理 @Priority 注解,找到序号最小的,有多个一样的则抛出异常
                3. 找到 bean 名称和属性名称相等的 bean 对象
            */
            autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
            if (autowiredBeanName == null) {
                if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
                    return descriptor.resolveNotUnique(type, matchingBeans);
                }
                else {
                    return null;
                }
            }
            instanceCandidate = matchingBeans.get(autowiredBeanName);
        }
        else {
            // 如果只有一个匹配的就不需要再进行选择了
            Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
            autowiredBeanName = entry.getKey();
            instanceCandidate = entry.getValue();
        }

        if (autowiredBeanNames != null) {
            autowiredBeanNames.add(autowiredBeanName);
        }
        if (instanceCandidate instanceof Class) {
            instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
        }
        Object result = instanceCandidate;
        if (result instanceof NullBean) {
            if (isRequired(descriptor)) {
                raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
            }
            result = null;
        }
        if (!ClassUtils.isAssignableValue(type, result)) {
            throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
        }
        return result;
    }
    finally {
        ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
    }
}

@Resource

@Resource@Autowired 同样有着注入点的概念。

注入点的查找

@Resource 的注入点查找同样也是在 BeanPostProcessor 中完成的,不过是在 CommonAnnotationBeanPostProcessor 中,但是具体的查找过程和 @Autowired 的查找过程是类似的。由于是通用的,所以除了会处理 @Resource 还会处理其他的注解,不过大家只需要关注我写注释的地方就好了。

// CommonAnnotationBeanPostProcessor
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
    super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
    // 查找类的所有注入点
    InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
    metadata.checkConfigMembers(beanDefinition);
}

private InjectionMetadata findResourceMetadata(String beanName, final Class<?> clazz, @Nullable PropertyValues pvs) {
    String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
    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);
                }
                // 解析并构建类的注入点
                metadata = buildResourceMetadata(clazz);
                this.injectionMetadataCache.put(cacheKey, metadata);
            }
        }
    }
    return metadata;
}

private InjectionMetadata buildResourceMetadata(final Class<?> clazz) {
    // 用于存放所有的注入点
    List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
    Class<?> targetClass = clazz;

    do {
        final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
        
        // 查找当前类的属性注入点
        ReflectionUtils.doWithLocalFields(targetClass, field -> {
            if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {
                if (Modifier.isStatic(field.getModifiers())) {
                    throw new IllegalStateException("@WebServiceRef annotation is not supported on static fields");
                }
                currElements.add(new WebServiceRefElement(field, field, null));
            }
            else if (ejbRefClass != null && field.isAnnotationPresent(ejbRefClass)) {
                if (Modifier.isStatic(field.getModifiers())) {
                    throw new IllegalStateException("@EJB annotation is not supported on static fields");
                }
                currElements.add(new EjbRefElement(field, field, null));
            }
            // 如果属性上修饰了 @Resource 注解
            else if (field.isAnnotationPresent(Resource.class)) {
                // 忽略静态属性
                if (Modifier.isStatic(field.getModifiers())) {
                    throw new IllegalStateException("@Resource annotation is not supported on static fields");
                }
                if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
                    currElements.add(new ResourceElement(field, field, null));
                }
            }
        });
        
        // 查找当前类的方法注入点
        ReflectionUtils.doWithLocalMethods(targetClass, method -> {
            Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
            if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
                return;
            }
            if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
                if (webServiceRefClass != null && bridgedMethod.isAnnotationPresent(webServiceRefClass)) {
                    if (Modifier.isStatic(method.getModifiers())) {
                        throw new IllegalStateException("@WebServiceRef annotation is not supported on static methods");
                    }
                    if (method.getParameterCount() != 1) {
                        throw new IllegalStateException("@WebServiceRef annotation requires a single-arg method: " + method);
                    }
                    PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                    currElements.add(new WebServiceRefElement(method, bridgedMethod, pd));
                }
                else if (ejbRefClass != null && bridgedMethod.isAnnotationPresent(ejbRefClass)) {
                    if (Modifier.isStatic(method.getModifiers())) {
                        throw new IllegalStateException("@EJB annotation is not supported on static methods");
                    }
                    if (method.getParameterCount() != 1) {
                        throw new IllegalStateException("@EJB annotation requires a single-arg method: " + method);
                    }
                    PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                    currElements.add(new EjbRefElement(method, bridgedMethod, pd));
                }
                // 如果方法上修饰 @Resource 注解
                else if (bridgedMethod.isAnnotationPresent(Resource.class)) {
                    // 忽略静态方法
                    if (Modifier.isStatic(method.getModifiers())) {
                        throw new IllegalStateException("@Resource annotation is not supported on static methods");
                    }
                    Class<?>[] paramTypes = method.getParameterTypes();
                    if (paramTypes.length != 1) {
                        throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method);
                    }
                    if (!this.ignoredResourceTypes.contains(paramTypes[0].getName())) {
                        PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                        currElements.add(new ResourceElement(method, bridgedMethod, pd));
                    }
                }
            }
        });

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

    return new InjectionMetadata(clazz, elements);
}

依赖注入

我们只关注 Bean 的选择过程。

// CommonAnnotationBeanPostProcessor
protected Object autowireResource(BeanFactory factory, LookupElement element, @Nullable String requestingBeanName)
    throws NoSuchBeanDefinitionException {

    Object resource;
    Set<String> autowiredBeanNames;
    String name = element.name;
    
    // 如果通过 name 找不到对应的 Bean,则通过类型匹配
    // 最关键的判断条件就是 !factory.containsBean(name)
    if (this.fallbackToDefaultTypeMatch && element.isDefaultName &&
        factory instanceof AutowireCapableBeanFactory && !factory.containsBean(name)) {
        autowiredBeanNames = new LinkedHashSet<>();
        // 下面的 resolveDependency 在讲 @Autowired 的依赖注入的时候已经讲到了
        resource = ((AutowireCapableBeanFactory) factory).resolveDependency(
            element.getDependencyDescriptor(), requestingBeanName, autowiredBeanNames, null);
        if (resource == null) {
            throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object");
        }
    }
    else {// 通过名称找到对应的 Bean
        resource = factory.getBean(name, element.lookupType);
        autowiredBeanNames = Collections.singleton(name);
    }

    if (factory instanceof ConfigurableBeanFactory) {
        ConfigurableBeanFactory beanFactory = (ConfigurableBeanFactory) factory;
        for (String autowiredBeanName : autowiredBeanNames) {
            if (requestingBeanName != null && beanFactory.containsBean(autowiredBeanName)) {
                beanFactory.registerDependentBean(autowiredBeanName, requestingBeanName);
            }
        }
    }

    return resource;
}

@Autowired 和 @Resource 的区别

  1. @Autowired 是 Spring 自己定义的,而 @Resource 是 JDK 规范中定义的,Spring 支持这个规范。
  2. @Autowired 的 Bean 的选择过程是 @Qualifier -> @Primary -> @Priority -> 属性名称。@Resource 的选择过程是 @Resource name属性或被修饰属性名称 -> @Qualifier -> @Primary -> @Priority
  3. @Autowired 能被修饰在 CONSTRUCTORMETHODPARAMETERFIELDANNOTATION_TYPE 上。@Resource 只能被修饰在 TYPEFIELDMETHOD 上。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值