spring @Autowire property vs setter

lus*_*uso 31 java spring dependency-injection

anotate @Autowired与某个属性或在setter中执行此操作有什么区别?

据我所知他们都有相同的结果,但有没有理由使用一个而不是另一个?

更新(更简洁)

这有什么区别

package com.tutorialspoint;

import org.springframework.beans.factory.annotation.Autowired;

public class TextEditor {
   private SpellChecker spellChecker;

   @Autowired
   public void setSpellChecker( SpellChecker spellChecker ){
      this.spellChecker = spellChecker;
   }

   public void spellCheck() {
      spellChecker.checkSpelling();
   }
}
Run Code Online (Sandbox Code Playgroud)

还有这个

package com.tutorialspoint;

import org.springframework.beans.factory.annotation.Autowired;

public class TextEditor {
   @Autowired
   private SpellChecker spellChecker;

   public TextEditor() {
      System.out.println("Inside TextEditor constructor." );
   }

   public void spellCheck(){
      spellChecker.checkSpelling();
   }
}
Run Code Online (Sandbox Code Playgroud)

SMA*_*SMA 20

使用@Autowired注释,您不需要setter方法.一旦你的bean的构造函数完成了分配/创建对象,Spring将扫描这个注释并注入你注释的对象实例.

如果您有setter,如果您仍在使用xml配置,则应明确设置属性.

话虽如此,你可以使用autowired注释来注释你的构造函数和setter方法,我更喜欢这样,因为这会让我有灵活性以后离开Spring(虽然我不会这样做).

  • 也许这可以让这个问题更加清晰。[Spring 中的 Setter DI 与构造函数 DI?](/sf/ask/544565661/) (2认同)

Bar*_*cki 18

有时您需要A类的实例,但不要在类的字段中存储A. 你只需要A来执行一次性操作.或者,使用A获取B的实例,并在字段中存储B.

在这些情况下,setter(或构造函数)autowire将更适合您.您将没有未使用的类级别字段.

具体示例:您需要构造RabbitTemplate(一个向RabbitMQ发送消息的对象)要构造它,您需要ConnectionFactory http://docs.spring.io/spring-amqp/docs/latest_ga/api/org/springframework/amqp/兔/型芯/ RabbitTemplate.html#RabbitTemplate-org.springframework.amqp.rabbit.connection.ConnectionFactory-

您不需要存储ConnectionFactory.在这种情况下,代码看起来像这样:

Class MyClass {
private RabbitTemplate template;

@Autowired 
void setConnectionFactory(ConnectionFactory c) {
    template=new RabbitTemplate(c);
}
}
Run Code Online (Sandbox Code Playgroud)

...比直接自动装配ConnectionFactory字段更能为您服务.

在此示例中,构造函数级别的自动装配会更好,因为您的对象将始终完全构造.很明显,ConnectionFactory是一个强制依赖,而不是一个可选的依赖.


ACV*_*ACV 10

自动装配有 3 种类型:

  • 基于财产
@Autowired
private MyService service;
Run Code Online (Sandbox Code Playgroud)
  • 基于构造函数。请注意,在 Spring Boot 中,在这种情况下您甚至不需要@Autowired注释:
class MyController {
 private final MyService service;

 public MyController(MyService service) {
  this.service = service;
 }
}
Run Code Online (Sandbox Code Playgroud)
  • 基于设置者:
private MyService service;


@Autowired
public void setService(MyService service) {
 this.service = service;
}
Run Code Online (Sandbox Code Playgroud)

建议使用基于构造函数,如果不可能的话,使用基于设置器,最后基于属性。

为什么?

  • 首先,因为在基于构造函数中,您甚至不使用任何 Spring 注释。这可以帮助您过渡到不同的框架。

  • 其次,基于构造函数或设置器,使单元测试变得更加容易。您不需要使用任何 Spring 特定的测试工具,只需使用 Junit 和 Mockito。

  • 第三,基于构造函数很好,因为您可以将属性声明为final而不公开设置器,这有助于类的不变性和线程安全性。


Sah*_*bra 7

如果属性使用@Autowired注解,spring 将使用 spring.xml 启动该属性。在这种情况下,您不需要 setter。

如果setter使用@Autowired注解,则指定 spring 它应该使用此 setter 方法启动此属性,您可以在其中添加自定义代码,例如使用此属性初始化其他一些属性

示例用法: 在使用 JdbcTemplate 进行 DAO 操作的情况下,需要 DataSource 作为 JdbcTemplate 的输入,但 DataSource 本身不需要作为属性。所以你可以使用 DataSource Setter 通过自动连接 DataSource Setter 来初始化 JdbcTempate。请看下面的代码:

class DaoDemo{
   //@Autowired
   //private DataSource dataSource;
   private JdbcTemplate jdbcTemplate;

   @Autowired
   public void setDataSource(DataSource dataSource){
     //this.dataSource = dataSource;  
     this.jdbcTemplate = new JdbcTemplate(dataSource);
   }

   public int getTableRowCount(){
      String sql = "SELECT COUNT(*) FROM DEMOTABLE";
      //jdbcTemplate.setDataSource(dataSource);    //No need to do this as its done in DataSource Setter now.
      return jdbcTemplate.queryForObject(sql,Integer.class);

}
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,dataSource 的唯一用途是在 JdbcTemplate 中传递。因此,在这里创建 dataSource 的属性没有意义。因此,只需在 DataSource bean 的 setter 方法上使用 @Autowired 从 spring.xml 获取其条目并在特定时间使用它。