spring @Autowire 属性与设置器
Posted
技术标签:
【中文标题】spring @Autowire 属性与设置器【英文标题】:spring @Autowire property vs setter 【发布时间】:2016-02-07 08:38:56 【问题描述】:将@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();
【问题讨论】:
我不知道为什么这个问题的答案会是固执己见。我想知道在 setter 中或直接在属性中使用 @Autowired 是否有实际区别。不问哪个好,只要有区别就行了 【参考方案1】:有时您需要一个类 A 的实例,但您不将 A 存储在类的字段中。 您只需要一个实例来执行一次性操作。或者,您使用 A 实例获取 B 的实例,并将 B 存储在字段中。
在这些情况下,设置器(或构造器)自动装配会更适合您。 您不会有未使用的类级字段。
具体例子: 您需要构造 RabbitTemplate(向 RabbitMQ 发送消息的对象) 要构建它,您需要 ConnectionFactoryhttp://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 是强制依赖,而不是可选依赖。
【讨论】:
【参考方案2】:有了@Autowired
注解,你就不需要setter方法了。一旦您的 bean 的构造函数完成分配/创建对象,Spring 将扫描此注解并注入您注解的对象实例。
如果您有 setter 并且仍在使用 xml 配置,您将显式设置属性。
话虽如此,您可以使用自动装配注解来注解您的构造函数和 setter 方法,这是我更喜欢的,因为这会给我以后离开 Spring 的灵活性(尽管我不会这样做)。
【讨论】:
在我用来更新帖子的 Spring 示例中,DI 术语有什么不同吗? 没有区别,你仍然在注入依赖。这只是构造函数或设置器的选择,例如 也许这可以让我们更清楚地了解这个问题。 Setter DI vs. Constructor DI in Spring? @SMA - 如何通过 setter 注入远离 Spring?设置器上方是否还会有一个 Autowired 注释,即“spring”? 知道了,感谢@veritas 的澄清。在这种情况下,您可以使用JDK 提供的Inject
注释。关于相同的细节已经结束here【参考方案3】:
如果您在 property 上使用@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);
在上面的代码中,dataSource 的唯一用途是在 JdbcTemplate 中传递。因此,在这里创建 dataSource 的属性没有意义。因此,只需使用 DataSource bean 的 setter 方法上的 @Autowired 从 spring.xml 获取其条目并在该特定时间本身使用它。
【讨论】:
【参考方案4】:自动装配有 3 种类型:
基于属性@Autowired
private MyService service;
基于构造函数。请注意,在这种情况下,在 Spring Boot 中您甚至不需要 @Autowired
注释:
class MyController
private final MyService service;
public MyController(MyService service)
this.service = service;
基于二传手:
private MyService service;
@Autowired
public void setService(MyService service)
this.service = service;
建议使用基于构造器的,如果不可能的话,使用基于Setter,最后基于Property。
为什么?
首先,因为在基于构造函数的情况下,您甚至不使用任何 Spring 注释。这有助于您过渡到不同的框架。
其次,基于构造函数或设置器,使单元测试更容易。您不需要使用任何 Spring 特定的测试工具,您只能使用 Junit 和 Mockito。
第三,基于构造函数很好,因为您可以将属性声明为final
,并且不公开有助于类的不变性和线程安全的设置器。
【讨论】:
【参考方案5】:自动装配在项目中一致使用时效果最佳。如果一般不使用自动装配,开发人员可能会混淆使用它来只装配一个或两个 bean 定义。在字段上使用 @Autowired 时,您不需要 setter 方法,它一方面使类更小且更易于阅读,但另一方面使模拟类有点难看。
属性和构造函数参数设置中的显式依赖项始终覆盖自动装配。您不能自动装配所谓的简单属性,例如基元、字符串和类(以及此类简单属性的数组)。此限制是设计使然。
自动连线不如显式连线精确。 Spring 会小心避免猜测可能会产生意外结果的歧义,Spring 管理的对象之间的关系不再明确记录。
可能无法从 Spring 容器生成文档的工具使用接线信息。
容器中的多个 bean 定义可能与要自动装配的 setter 方法或构造函数参数指定的类型匹配。对于数组、集合或 Map,这不一定是问题。然而,对于期望单个值的依赖项,这种歧义不会被任意解决。如果没有唯一的 bean 定义可用,则抛出异常。
【讨论】:
【参考方案6】:如果可以的话,你应该避免使用 setter。如果你不需要它,最好它不存在,对吧?
我个人更喜欢 Guice 允许我写作
public class TextEditor
private final SpellChecker spellChecker;
@Inject public TextEditor(SpellChecker spellChecker)
this.spellChecker = spellChecker;
public void spellCheck()
spellChecker.checkSpelling();
这更进一步:有了final
字段,我知道它永远不会改变,我得到了multithreading visibility guarantee。
【讨论】:
【参考方案7】:在一种情况下,对 OPTIONAL 属性使用 @Autowired 不起作用。
如果您想使用该属性进行一些初始化,它可能不会在调用构造函数之前设置,并且由于它是可选的,因此您不能将其作为参数放入构造函数中。
在这种情况下,最好使用@Autowired setter 方法,这样您就可以在属性自动装配后执行初始化。
【讨论】:
以上是关于spring @Autowire 属性与设置器的主要内容,如果未能解决你的问题,请参考以下文章
从头认识Spring-2.5 @Autowire @Inject @Qualifier @Named的相同与不同
Spring4学习笔记 - 配置Bean - 自动装配 关系 作用域 引用外部属性文件