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差不多,这里就不再赘述。

目录
相关文章
|
16天前
|
缓存 Java Sentinel
Springboot 中使用 Redisson+AOP+自定义注解 实现访问限流与黑名单拦截
Springboot 中使用 Redisson+AOP+自定义注解 实现访问限流与黑名单拦截
|
5天前
|
运维 Java 程序员
Spring5深入浅出篇:基于注解实现的AOP
# Spring5 AOP 深入理解:注解实现 本文介绍了基于注解的AOP编程步骤,包括原始对象、额外功能、切点和组装切面。步骤1-3旨在构建切面,与传统AOP相似。示例代码展示了如何使用`@Around`定义切面和执行逻辑。配置中,通过`@Aspect`和`@Around`注解定义切点,并在Spring配置中启用AOP自动代理。 进一步讨论了切点复用,避免重复代码以提高代码维护性。通过`@Pointcut`定义通用切点表达式,然后在多个通知中引用。此外,解释了AOP底层实现的两种动态代理方式:JDK动态代理和Cglib字节码增强,默认使用JDK,可通过配置切换到Cglib
|
1天前
|
监控 安全 Java
Spring cloud原理详解
Spring cloud原理详解
10 0
|
1天前
|
JSON 前端开发 Java
【JAVA进阶篇教学】第七篇:Spring中常用注解
【JAVA进阶篇教学】第七篇:Spring中常用注解
|
4天前
|
JavaScript Java 开发者
Spring Boot中的@Lazy注解:概念及实战应用
【4月更文挑战第7天】在Spring Framework中,@Lazy注解是一个非常有用的特性,它允许开发者控制Spring容器的bean初始化时机。本文将详细介绍@Lazy注解的概念,并通过一个实际的例子展示如何在Spring Boot应用中使用它。
17 2
|
5天前
|
前端开发 Java
SpringBoot之自定义注解参数校验
SpringBoot之自定义注解参数校验
15 2
|
7天前
|
Java 开发者 微服务
Spring Cloud原理详解
【5月更文挑战第4天】Spring Cloud是Spring生态系统中的微服务框架,包含配置管理、服务发现、断路器、API网关等工具,简化分布式系统开发。核心组件如Eureka(服务发现)、Config Server(配置中心)、Ribbon(负载均衡)、Hystrix(断路器)、Zuul(API网关)等。本文讨论了Spring Cloud的基本概念、核心组件、常见问题及解决策略,并提供代码示例,帮助开发者更好地理解和实践微服务架构。此外,还涵盖了服务通信方式、安全性、性能优化、自动化部署、服务网格和无服务器架构的融合等话题,揭示了微服务架构的未来趋势。
31 6
|
11天前
|
Java Spring
springboot自带的@Scheduled注解开启定时任务
springboot自带的@Scheduled注解开启定时任务
|
11天前
|
负载均衡 Java 开发者
Spring Cloud:一文读懂其原理与架构
Spring Cloud 是一套微服务解决方案,它整合了Netflix公司的多个开源框架,简化了分布式系统开发。Spring Cloud 提供了服务注册与发现、配置中心、消息总线、负载均衡、熔断机制等工具,让开发者可以快速地构建一些常见的微服务架构。
|
14天前
|
XML JSON Java
【SpringBoot】springboot常用注解
【SpringBoot】springboot常用注解