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方法,这样您就可以在属性自动连线后执行初始化。