返回
Featured image of post Spring - 依赖注入注解的区分

Spring - 依赖注入注解的区分

Redis基于C语言实现了自己的数据类型,主要包括五种:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合).

Spring 支持的依赖注入有 @Autowired @Resource @Inject 三种

@Autowired

来自 org.springframwork.beans.factory.annotation.Autowired ,装配顺序为:

  • type 在上下文中查找匹配的 bean
  • 如果有多个 bean,则按照 name 进行匹配
    • 如有 @Qualifier ,则按指定的 name 进行匹配
    • 如没有,则按变量名进行匹配
  • 匹配不到就报错

@Autowired(required=false) 则注入失败不抛异常

@Inject

Spring 环境下和 @Autowired 相同,都依赖 AutowiredAnnotationBeanPostProcess 进行处理,但不能 (required=false)@Inject 由 JSR-330 定义,可以切换到谷歌的 DI 框架——Guice。

@Inject 在 Java EE 包内,SE 环境需要单独引入。

@Resource

JSR-250 定义。在 CommonAnnotationBeanPostProcessor 实现处理。同样有 nametype。装配顺序:

  • 如同时指定 nametype ,从上下文找到唯一匹配 bean 进行装配,找不到抛异常
  • 如指定 name ,则到上下文找 id 匹配的 bean 进行装配,找不到抛异常
  • 如指定 type ,则到上下文找类型匹配的唯一 bean 进行装配,找不到或找到不唯一都会抛异常
  • 如果都没有指定,则默认按 byName 方式装配,找不到再按 byType 进行装配

IDEA 使用 @Autowired 时很常见警告 Field injection is not recommended。

Spring 团队建议永远使用构造方法,也就是 c-args 进行依赖注入。IDEA 对这一警告的默认修改方式也是——创建一个构造器进行依赖注入。并且,跟据 Spring 团队建议,对必须的依赖,应当使用断言进行确认

Assert.notNull(svc, "svc must not be null");

为什么不能用成员依赖注入呢?

field 注入虽然简洁,但存在问题:

  1. 由于添加依赖过于简单(加个注释),我们很容易无意识地向一个类注入大量依赖,这违反了单一职责原理,因为我们过去通过构造器进行注入,而要是你的构造器出现大量入参,那很容易意识到自己的代码结构不对劲。打个比方——原本要数着钞票买东西的,一下子变成移动支付,点一下付钱了,就容易到了月底为账单发愁,因为我们金钱意识变薄弱了。解决方法就是——继续用构造器注入,因此对于强制依赖,Spring推荐用 c-args 注入。
  2. 依赖注入与容器本身耦合了,即——类唯一的正常工作方式就是通过容器反射进行实例化,这就像是集成测试一样,不像个健康的类,就像一个人原本你把饭给他就能自己吃,现在非要注射进去一样。为了让类能在容器外使用,自然还是要用 c-argss-args
  3. 属性注入不能用来注入 final 变量。

因此 Spring 给出建议:constructor-basedsetter-based DI 可以混用,

  • 强制依赖就用 constructor-based

    很好理解,类离开强制依赖就无法工作,这和构造方法职能相吻合,也能注入 final 变量。构造器可以保证这些变量的值不会是 null 。

  • 可选、可变依赖用 setter-based

    setter 值应被用于注入非必须依赖,这些依赖可以很方便地被改变或重新注入,否则会需要大量的 null 检查。

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus