Spring中注解的@Autowired和@Resource该用哪个

88 阅读2分钟

Spring中注解的@Autowired和@Resource该用哪个

有一次出现了一个比较奇怪的现象

Field injection is not recommended

1-1.jpg

环境背景

环境背景

  • • JDK 8
  • • spring-boot-starter-parent 2.6.0

Spring 注入的三种方式

字段注入

public class TestService {    
    @Autowired    
    private DependA dependA;    
    @Autowired    
    private DependB dependB;
}

方法注入

public class TestDepen {
    private DependA dependA;
    private DependB dependB;
​
    @Autowired
    public void setDependA(DependA dependA) {
        this.dependA = depenA;
    }
​
    @Autowired
    public void setDepenB(DepenB depenB) {
        this.depenB = depenB;
    }
}

构造器注入

public class TestService {
    private final DependA depenA;
    private final DependB dependB;
    public TestService(DependA dependA, DependB dependB) {
        this.dependA = dependA;
        this.dependB = dependB;
    }
}

为什么不推荐 @Autowired 字段注入

@Autowired VS @Resource

  • @Autowired 是Spring定义的,而 @Resource 是JSR-250定义。
  • 依赖识别方式:@Autowired默认是byType,可以使用@Qualifier指定Name,@Resource默认使用ByName,如果找不到则使用ByType。
  • 适用对象:@Autowired可以对构造器、方法、字段使用,@Resource只能对方法、字段使用。

@Resource 为什么没有不推荐

其实这是因为 @Autowired 是 Spring 提供的特定注解,和 Spring 框架绑定,而 @Resource 是JSR-250提供的,它是Java标准,作为 IOC 容器框架都是需要实现的,所以不存在上面的第一点问题。

一些最佳实践

Since you can mix constructor-based and setter-based DI, it is a good rule of thumb to use constructors for mandatory dependencies and setter methods or configuration methods for optional dependencies. Note that use of the @Required annotation on a setter method can be used to make the property a required depen.

翻译:由于可以混合使用基于构造函数和基于setter的DI,因此使用构造函数作为强制依赖项,使用setter方法或配置方法作为可选依赖项是一条很好的经验法则。请注意,在setter方法上使用@Required注释可以使属性成为必需的依赖项。

public class TestService {
    /**
     * 必须依赖
     */
    private final DepenA depenA;
    /**
     * 非必须依赖
     */
    private DepenB depenB;
​
    public TestService(DepenA depenA) {
        this.depenA = depenA;
    }
​
    @Autowired(required = false)
    public void setDepenB(DepenB depenB) {
        this.depenB = depenB;
    }
}

使用构造器注入带来的循环依赖问题

如果我们使用构造器注入,那么可能会出现无法解析循环依赖的问题。这里提供两个解决方案:

使用方法注入(官网推荐)

One possible solution is to edit the source code of some classes to be configured by setters rather than constructors. Alternatively, avoid constructor injection and use setter injection only. In other words, although it is not recommended, you can configure circular dependencies with setter injection.

翻译:一种可能的解决方案是编辑一些类的源代码,由setter而不是构造函数进行配置。或者,避免构造函数注入,只使用setter注入。换句话说,尽管不建议这样做,但您可以使用setter注入来配置循环依赖关系。

小编没用过 使用 Lazy 注解

一些场景下会导致初次请求处理变慢。

@Servicepublic
class DepenA {
    private final TestService testService;
​
    public DepenA(@Lazy TestService testService) {
        this.testService = testService;
    }
}
​
@Servicepublic
class TestService {
    private final DepenA depenA;
​
    public TestService(DepenA depenA) {
        this.depenA = depenA;
    }
}