当前位置: 首页 > news >正文

java @Autowired @Resource @Inject 三个注解的区别

javax.annotation.Resource

jdk 内置的,JSR-250 中的注解。

依赖注入通过 org.springframework.context.annotation.CommonAnnotationBeanPostProcessor 来处理。

org.springframework.beans.factory.annotation.Autowired
org.springframework.beans.factory.annotation.Value

javax.inject.Inject

JSR-330 中的注解,作用同 @Autowired

依赖注入通过 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor 来处理。

org.springframework.beans.factory.annotation.Qualifier
javax.inject.Qualifier

依赖注入通过 org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver 来处理。

@Autowired

spring 自带的注解。

注入顺序

  1. 按照 type 在 上下文中查找匹配的 bean

  1. 如果有多个 bean,按照 name 进行匹配

  • 如果有 @Qualifier 注解,按照 @Qualifier 指定的 name 进行匹配

  • 如果没有,按照变量名进行匹配

  1. 匹配不到,报错。因为 required 默认为 true,不想注入设置此 bean @Autowired(required=false)。

@Inject

在 spring 中,@Inject 和 @Autowired 相同。

@Inject 和 @Autowired 区别

  • @Inject 是 javaee 6 及以上版本包里的。

  • @Autowired 可以设置 required=false 而 @Inject 没有这个属性。

@Resource

有两个重要的属性,name 和 type,spring 将 name 属性解析为 bean 的名字,type 解析为 bean 的类型。如果未指定 name,取变量名给 name 赋值。

CommonAnnotationBeanPostProcessor 中Resource 赋值源码

/*** Class representing injection information about an annotated field* or setter method, supporting the @Resource annotation.*/private class ResourceElement extends LookupElement {private final boolean lazyLookup;public ResourceElement(Member member, AnnotatedElement ae, @Nullable PropertyDescriptor pd) {super(member, pd);Resource resource = ae.getAnnotation(Resource.class);String resourceName = resource.name();Class<?> resourceType = resource.type();this.isDefaultName = !StringUtils.hasLength(resourceName);if (this.isDefaultName) {resourceName = this.member.getName();if (this.member instanceof Method && resourceName.startsWith("set") && resourceName.length() > 3) {resourceName = Introspector.decapitalize(resourceName.substring(3));}}else if (embeddedValueResolver != null) {resourceName = embeddedValueResolver.resolveStringValue(resourceName);}if (Object.class != resourceType) {checkResourceType(resourceType);}else {// No resource type specified... check field/method.resourceType = getResourceType();}this.name = (resourceName != null ? resourceName : "");this.lookupType = resourceType;String lookupValue = resource.lookup();this.mappedName = (StringUtils.hasLength(lookupValue) ? lookupValue : resource.mappedName());Lazy lazy = ae.getAnnotation(Lazy.class);this.lazyLookup = (lazy != null && lazy.value());}@Overrideprotected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) :getResource(this, requestingBeanName));}}

在变量名相同的情况下报错

The bean could not be injected as a because it is a JDK dynamic proxy that implements:

指定了不同type无法解决问题,跟进源码发现是 spring boot 把异常给处理了

org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'productInit': 
Injection of resource dependencies failed; 
nested exception is org.springframework.beans.factory.BeanNotOfRequiredTypeException: 
Bean named 'example2ProductMapper' is expected to be of type 'com.alibaba.cloud.youxia.manager.ProductManager' but was actually of type 'com.sun.proxy.$Proxy47'

想到在 DefaultListableBeanFactory 中 beanDefinitionMap 按照名称和 BeanDefinition 键值对的问题,名称和注入的对象一一对应,不然就会出现不对应的问题

注入规则

  1. 如果未指定 name,取变量名从上下文中查找名称匹配的 bean 进行注入,找不到或者注入的变量名与类型无法对应抛出异常。

  1. 如果指定了 name,则从上下文中查找名称匹配的 bean 进行注入,找不到抛出异常。

  1. 如果指定了 type,有两种情况

  • 通过变量名从上下文中查找不到对应的 bean,则通过 type则从上下文中查找类型匹配的 bean 进行注入,找不到抛出异常。

  • 通过变量名从上下文中找到对应的 bean但是注入的类型与无法与DefaultListableBeanFactory 中 beanDefinitionMap中通过变量名得到的 BeanDefinition 类型一致,抛出异常。

  1. 既没有指定 name,又没有指定 type,默认按照变量名进行注入

  1. 如果同时指定了 name 和 type,从上下文中找到唯一匹配的 bean 进行注入,找不到抛出异常。

匹配顺序为

变量名 → 指定的 name → 指定的 type

如果注入的 bean 变量名相同,但是类型不同,通过 name 指定是修改代码量最小的办法。

http://www.lryc.cn/news/28836.html

相关文章:

  • 「媒体分流直播」媒体直播和传统直播的区别,以及媒体直播的特点
  • 数据是如何在计算机中存储的
  • Day907.分区表 -MySQL实战
  • C++概览:工具链、基础知识、进阶及总结
  • 目标检测中回归损失函数(L1Loss,L2Loss,Smooth L1Loss,IOU,GIOU,DIOU,CIOU,EIOU,αIOU ,SIOU)
  • JOSN数据转换和解析
  • 浅析Linux内核中进程完全公平CFS调度
  • 安装 RustDesk 服务器 (适用 Rocky Linux, CentOS, RHEL 系列发行版)
  • 23种设计模式-策略模式
  • C#开发的OpenRA的游戏主界面怎么样创建
  • 考研还是工作?两战失败老道有话说
  • 引用是否有地址的讨论的
  • 1、JAVA 开发环境搭建 - JDK 的安装配置
  • 【Storm】【六】Storm 集成 Redis 详解
  • 算法代码题——模板
  • CentOS 7.9汇编语言版Hello World
  • CoreData数据库探索
  • FreeRTOS入门
  • JVM运行时数据区划分
  • 重装系统一半电脑蓝屏如何解决
  • SpringBoot(tedu)——day01——环境搭建
  • springboot整合redis
  • 【Java】Spring Boot下的MVC
  • 【项目精选】 塞北村镇旅游网站设计(视频+论文+源码)
  • 十、Spring IoC注解式开发
  • Linux系统GPIO应用编程
  • 手敲Mybatis-反射工具天花板
  • Java -数据结构,【优先级队列 / 堆】
  • Python+Qt指纹录入识别考勤系统
  • K_A14_004 基于STM32等单片机驱动旋转角度传感器模块 串口与OLED0.96双显示