Spring注解装配:@Autowired和@Resource使用及原理详解

简介: `@Resource`和`@Autowired`都是实现bean的注入,在日常开发中使用非常频繁,但是使用体验不太一样,笔者喜欢用`@Resource`,因为在使用`@Autowired`时IDEA会出现一些警告爆红提示

1.背景

@Resource@Autowired都是实现bean的注入,在日常开发中使用非常频繁,但是使用体验不太一样,笔者喜欢用@Resource,因为在使用@Autowired时IDEA会出现一些警告爆红提示:

Field injection is not recommended (字段注入是不被推荐的)

Spring团队不推荐属性字段注入的方式(ps:日常开发中我们一般都是字段注入,简单了然呀),建议使用基于构造函数的依赖项注入。

还有报红如下:IDEA提示找不到该类型的bean,这并不是错误。。。项目启动时mapper bean会被注入到Spring上下文容器中

综上情况和个人有强迫症看到警告和爆红就认为代码写得有问题,所以我选择了@Resource。但是这里要申明一下@Autowied本身是没问题的,可以尽情使用,出现以上报红是IDEA工具的问题。

项目推荐:基于SpringBoot2.x、SpringCloud和SpringCloudAlibaba企业级系统架构底层框架封装,解决业务开发时常见的非功能性需求,防止重复造轮子,方便业务快速开发和企业技术栈框架统一管理。引入组件化的思想实现高内聚低耦合并且高度可配置化,做到可插拔。严格控制包依赖和统一版本管理,做到最少化依赖。注重代码规范和注释,非常适合个人学习和企业使用

Github地址https://github.com/plasticene/plasticene-boot-starter-parent

Gitee地址https://gitee.com/plasticene3/plasticene-boot-starter-parent

微信公众号Shepherd进阶笔记

2.概述

Spring 支持使用@Autowired, @Resource注解进行依赖注入

2.1 @Autowired和@Resource定义

@Autowired

@Autowired为Spring 框架提供的注解,需要导入包org.springframework.beans.factory.annotation.Autowired。源码如下

/**
 * @since 2.5
 * @see AutowiredAnnotationBeanPostProcessor
 * @see Qualifier
 * @see Value
 */
@Target({
   
   ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
   
   

    /**
     * Declares whether the annotated dependency is required.
     * <p>Defaults to {@code true}.
     */
    boolean required() default true;

}

① 按照type在上下文中查找匹配的bean,查找type为Svc的bean

② 如果有多个bean,则按照name进行匹配

  • 如果有@Qualifier注解,则按照@Qualifier指定的name进行匹配,查找name为svcA的bean
  • 如果没有,则按照变量名进行匹配,查找name为svcA的bean

③ 匹配不到,则报错。(@Autowired(required=false),如果设置requiredfalse(默认为true),则注入失败时不会抛出异常

@Resource

@Resource 是JDK1.6支持的注解,由J2EE提供,需要导入包javax.annotation.Resource。源码如下:

@Target({
   
   TYPE, FIELD, METHOD})
@Retention(RUNTIME)
public @interface Resource {
   
   

    String name() default "";
    String lookup() default "";
    Class<?> type() default java.lang.Object.class;
    enum AuthenticationType {
   
   
            CONTAINER,
            APPLICATION
    }
    AuthenticationType authenticationType() default AuthenticationType.CONTAINER;
    boolean shareable() default true;
    String mappedName() default "";
    String description() default "";
}

默认按照名称进行装配,名称可以通过name属性进行指定。也提供按照byType 注入。

@Resource有两个重要的属性:name 和 type,而Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型

如果没有指定name属性,当注解写在字段上时,默认取字段名,按照名称查找。

当注解标注在属性的setter方法上,即默认取属性名作为bean名称寻找依赖对象。

当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。

@Resource的作用相当于@Autowired,只不过@Autowired按照byType自动注入

2.2 @Autowired和@Resource区别

依赖识别方式:@Autowired默认是byType可以使用@Qualifier指定Name,@Resource默认ByName如果找不到则ByType

适用对象:@Autowired可以对构造器、方法、参数、字段使用,@Resource只能对方法、字段使用

提供方:@Autowired是Spring提供的,@Resource是JSR-250提供的

3.实现原理

3.1 @Autowired实现原理

Spring中通过AutowiredAnnotationBeanPostProcessor来解析注入注解为目标注入值。该class继承InstantiationAwareBeanPostProcessorAdapter,实现了MergedBeanDefinitionPostProcessor,PriorityOrdered, BeanFactoryAware等接口,重写的方法将在IOC创建bean的时候被调用。

public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter
        implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware{
   
   
    /**
     * Create a new {@code AutowiredAnnotationBeanPostProcessor} for Spring's
     * standard {@link Autowired @Autowired} and {@link Value @Value} annotations.
     * <p>Also supports JSR-330's {@link javax.inject.Inject @Inject} annotation,
     * if available.
     */
    @SuppressWarnings("unchecked")
    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.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
      }
      catch (ClassNotFoundException ex) {
   
   
        // JSR-330 API not available - simply skip.
      }
    }

  ......

}

前面已经提到了是Spring创建bean的时候调用,即当使用DefaultListableBeanFactory来获取想要的bean的时候会调用AutowiredAnnotationBeanPostProcessor,经过调用AbstractBeanFactory中的getBean方法,继续追踪源码最后在AbstractAutowireCapableBeanFactory类中的createBean方法中找到了调用解析@autowired的方法:doCreateBean()

    protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
            throws BeanCreationException {
   
   

    ......

        // Allow post-processors to modify the merged bean definition.
        // 判断是否有后置处理
        // 如果有后置处理,则允许后置处理修改 BeanDefinition
        synchronized (mbd.postProcessingLock) {
   
   
            if (!mbd.postProcessed) {
   
   
                try {
   
   
          // 重点  重点  重点
          // 这里会调用AutowiredAnnotationBeanPostProcessor查找解析注入的元信息
                    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); 
                }
                catch (Throwable ex) {
   
   
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                            "Post-processing of merged bean definition failed", ex);
                }
                mbd.postProcessed = true;
            }
        }

        ......

        // Initialize the bean instance.
        // 开始初始化 bean 实例对象
        Object exposedObject = bean;
        try {
   
   
            // 对 bean 进行填充,将各个属性值注入,其中,可能存在依赖于其他 bean 的属性
            // 则会递归初始依赖 bean
            populateBean(beanName, mbd, instanceWrapper);
            // 调用初始化方法
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
        catch (Throwable ex) {
   
   
            if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
   
   
                throw (BeanCreationException) ex;
            }
            else {
   
   
                throw new BeanCreationException(
                        mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
            }
        }

      .......

        return exposedObject;
    }

执行到applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName)时会调用AutowiredAnnotationBeanPostProcessorpostProcessMergedBeanDefinition()完成注入元信息的查找解析。

进入populateBean()方法:会调用AutowiredAnnotationBeanPostProcessor方法postProcessPropertyValues()方法完成属性值注入,因为AutowiredAnnotationBeanPostProcessor是继承了InstantiationAwareBeanPostProcessorAdapter,是一个后置处理器。

接下来基于这两个核心入口分别讲述一下:

查找解析元信息

实现了接口类MergedBeanDefinitionPostProcessor的方法postProcessMergedBeanDefinition,这个方法是合并我们定义类的信息,比如:一个类继承了其它类,这个方法会把父类属性和信息合并到子类中

@Override
    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
   
   
    // 根据bean的名称、类型查找注入的元信息
        InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
        metadata.checkConfigMembers(beanDefinition);

findAutowiringMetadata()代码如下:

 private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
   
   
        // Fall back to class name as cache key, for backwards compatibility with custom callers.
    //先读缓存
        String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
        // Quick check on the concurrent map first, with minimal locking.
        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;
    }

构建注解元信息 buildAutowiringMetadata()


private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
   
   
    //判断是否符合条件注解类型(@AutoWired和@Value)
        if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
   
   
            return InjectionMetadata.EMPTY;
        }

        List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
        Class<?> targetClass = clazz;

        do {
   
   
            final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
      //先处理注解字段
            ReflectionUtils.doWithLocalFields(targetClass, field -> {
   
   
        //是不是要找的字段
                MergedAnnotation<?> ann = findAutowiredAnnotation(field);
                if (ann != null) {
   
   
          //静态字段不支持@Autowired
                    if (Modifier.isStatic(field.getModifiers())) {
   
   
                        if (logger.isInfoEnabled()) {
   
   
                            logger.info("Autowired annotation is not supported on static fields: " + field);
                        }
                        return;
                    }
                    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;
                }
                MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
                if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
   
   
          //@Autowired不支持静态方法
                    if (Modifier.isStatic(method.getModifiers())) {
   
   
                        if (logger.isInfoEnabled()) {
   
   
                            logger.info("Autowired annotation is not supported on static methods: " + method);
                        }
                        return;
                    }
                    if (method.getParameterCount() == 0) {
   
   
                        if (logger.isInfoEnabled()) {
   
   
                            logger.info("Autowired annotation should only be used on methods with parameters: " +
                                    method);
                        }
                    }
                    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 InjectionMetadata.forElements(elements, clazz);
    }

基于上面方法找到了所有需要注入的元信息并进行解析,这个过程也是一个依赖查找过程。

属性值注入

属性注入的通过AutowiredAnnotationBeanPostProcessor方法postProcessPropertyValues()方法完成的


    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
   
   
        //元信息查找、解析,在上一步已经分析过了
        InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
        try {
   
   
            //进行注入
            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;
    }


public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
   
   
        Collection<InjectedElement> checkedElements = this.checkedElements;
        Collection<InjectedElement> elementsToIterate =
                (checkedElements != null ? checkedElements : this.injectedElements);
        if (!elementsToIterate.isEmpty()) {
   
   
            for (InjectedElement element : elementsToIterate) {
   
   
                if (logger.isTraceEnabled()) {
   
   
                    logger.trace("Processing injected element of bean '" + beanName + "': " + element);
                }
        //注入
                element.inject(target, beanName, pvs);
            }
        }
    }

       /**
         * Either this or {@link #getResourceToInject} needs to be overridden.
         */
        protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
                throws Throwable {
   
   
      //字段注入
            if (this.isField) {
   
   
                Field field = (Field) this.member;
        //设置字段权限为可以访问权限
                ReflectionUtils.makeAccessible(field);
                field.set(target, getResourceToInject(target, requestingBeanName));
            }
            else {
   
   
        //方法注入    
                if (checkPropertySkipping(pvs)) {
   
   
                    return;
                }
                try {
   
   
                    Method method = (Method) this.member;
          //设置方法权限为可以访问权限
                    ReflectionUtils.makeAccessible(method);
                    method.invoke(target, getResourceToInject(target, requestingBeanName));
                }
                catch (InvocationTargetException ex) {
   
   
                    throw ex.getTargetException();
                }
            }
        }

自此基于@Autowired依赖注入核心逻辑就实现了。

3.2 @Resource实现原理

@Resource@Autowired的实现逻辑和流程基本是一样的,只是@Resource是通过CommonAnnotationBeanPostProcessor实现的,这里由于具体逻辑和实现细节和上面的@Autowired差不多,这里就不再赘述。

目录
相关文章
|
19小时前
|
XML Java 数据格式
Spring Boot自动配置是通过`@EnableAutoConfiguration`注解启用的
【6月更文挑战第18天】Spring Boot的`@EnableAutoConfiguration`启动自动配置,基于类路径扫描和条件注解(如@ConditionalOnClass)选择性应用配置。当检测到特定依赖时,自动配置模块会将对应的bean添加到应用上下文,简化了XML或Java配置。只需添加依赖,即可自动配置功能。
10 4
|
1天前
|
设计模式 网络安全 开发工具
|
2天前
|
安全 Java 数据安全/隐私保护
Spring Security 6.x 一文快速搞懂配置原理
本文主要对整个Spring Security配置过程做一定的剖析,希望可以对学习Spring Sercurity框架的同学所有帮助。
24 5
|
2天前
|
XML 安全 Java
Spring高手之路19——Spring AOP注解指南
在本文中,我们将深入探索Spring AOP(面向切面编程)的核心概念及其在现代Spring应用中的实际应用。从基本的注解使用到复杂的切面配置,本文将一步步指导你如何利用Spring AOP提升代码的模块化,帮助你在Spring开发路上更进一步。
15 3
Spring高手之路19——Spring AOP注解指南
|
4天前
|
前端开发 Java 开发者
深入理解 Spring Boot 注解:核心功能与高级用法详解
深入理解 Spring Boot 注解:核心功能与高级用法详解
10 1
|
9天前
|
Java 调度 Spring
SpringBoot多个@Scheduled注解的方法,会阻塞吗
【6月更文挑战第9天】SpringBoot多个@Scheduled注解的方法,会阻塞吗
18 5
|
分布式计算 Java 大数据
[Spring实战系列](9)装配集合
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/SunnyYoona/article/details/50634498 前两篇文章中,我们已经了解了如何使用Spring 配置简单属性值(使用value 属性)和引用其他Bean 的属性(使用ref 属性)。
990 0
|
5天前
|
Java Linux Shell
docker 打包 springboot 项目快速入门
docker 打包 springboot 项目快速入门
13 0
|
1月前
|
Java Nacos 开发者
Java从入门到精通:4.2.1学习新技术与框架——以Spring Boot和Spring Cloud Alibaba为例
Java从入门到精通:4.2.1学习新技术与框架——以Spring Boot和Spring Cloud Alibaba为例
|
1月前
|
安全 Java 应用服务中间件
江帅帅:Spring Boot 底层级探索系列 03 - 简单配置
江帅帅:Spring Boot 底层级探索系列 03 - 简单配置
38 0
江帅帅:Spring Boot 底层级探索系列 03 - 简单配置