spring @Autowire property vs setter



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();
   }
}

和这个

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();
   }
}

有时您需要类A的实例,但您不将A存储在类的字段中
您只需要一个实例即可执行一次性操作。或者,您使用A实例来获得B的实例,并且您将B存储在字段中。

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

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

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

Class MyClass {
private RabbitTemplate template;
@Autowired 
void setConnectionFactory(ConnectionFactory c) {
    template=new RabbitTemplate(c);
}
}

将比直接自动连接ConnectionFactory字段更好地为您服务。

在本例中,构造函数级别的自动布线会更好,因为对象总是完全构造好的。很明显,ConnectionFactory是一个强制性依赖项,而不是可选依赖项。

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

如果您有setter,并且仍在使用xml配置,则会显式设置属性。

话虽如此,您可以使用autowired注释来注释您的构造函数和setter方法,这是我更喜欢的,因为这会给我以后离开Spring的灵活性(尽管我不会这么做)。

如果在属性上使用@Autowired annotation,spring将使用spring.xml初始化该属性。在这种情况下,不需要setter。

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

与示例一起使用:在使用JdbcTemplate使用DAO操作的情况下,需要将DataSource作为JdbcTemplate的输入,但DataSource本身不需要作为属性。因此,您可以使用DataSourceSetter通过自动连接DataSourceSetter来初始化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);
}

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

自动布线有三种类型:

  • 基于属性
@Autowired
private MyService service;
  • 基于构造函数。请注意,在Spring Boot中,在这种情况下甚至不需要@Autowired注释:
class MyController {
 private final MyService service;
 public MyController(MyService service) {
  this.service = service;
 }
}
  • 基于Setter:
private MyService service;

@Autowired
public void setService(MyService service) {
 this.service = service;
}

建议使用基于构造函数的,如果不可能,则使用基于Setter的,最后使用基于属性的。

为什么?

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

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

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

当在项目中一致使用时,自动布线效果最佳。如果通常不使用自动布线,那么使用它只连接一两个bean定义可能会让开发人员感到困惑。在字段上使用@Autowired,您不需要setter方法,这一方面使类更小、更容易阅读,但另一方面使嘲笑类变得更丑陋。

属性和构造函数arg设置中的显式依赖项始终覆盖自动连接。不能自动连接所谓的简单属性,如基元、字符串和类(以及这些简单属性的数组)。这种限制是故意的。

自动布线不如显式布线精确。Spring小心避免猜测,以防出现可能会产生意外结果的歧义,不再显式地记录Spring托管对象之间的关系。

连接信息可能不可用于从Spring容器生成文档的工具。

容器中的多个bean定义可能与要自动连接的setter方法或构造函数参数指定的类型匹配。对于数组、集合或映射,这不一定是个问题。然而,对于期望单个值的依赖项,这种模糊性不会被任意解决。如果没有唯一的bean定义可用,则抛出异常。

如果可以的话,应该避开setter。如果你不需要它,当它不存在的时候会更好,对吧?

我个人更喜欢Guice允许我写

public class TextEditor {
   private final SpellChecker spellChecker;
   @Inject public TextEditor(SpellChecker spellChecker) {
      this.spellChecker = spellChecker;
   }
   public void spellCheck(){
      spellChecker.checkSpelling();
   }
}

这更进一步:有了final字段,我知道它永远不会改变,并且我得到了多线程可见性的保证。

在一种情况下,在OPTIONAL属性上使用@Autowired将不起作用。

如果要使用该属性进行某些初始化,则在调用构造函数之前可能不会设置该属性,并且由于它是可选的,因此不能将其作为构造函数中的参数。

在这种情况下,最好使用@Autowired setter方法,这样您就可以在属性自动连线后执行初始化。

最新更新