Spring-Context之六:基於Setter方法進行依賴注入


上文講了基於構造器進行依賴注入,這里講解基於Setter方法進行注入。在Java世界中有個約定(Convention),那就是屬性的設置和獲取的方法名一般是:set+屬性名(參數)及get+屬性名()的方式。boolean類型稍有不同,可以使用is+屬性名()方式來獲取。

以下是一個示例。

MessageHandler.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class MessageHandler {   private MessageService messageService;   public MessageService getMessageService() {  return messageService;  }   public void setMessageService(MessageService messageService) {  this.messageService = messageService;  }   public String handle() {  return messageService.sendService();  } } 

使用Setter方法注入如下所示。

1
2
3
4
<bean id="messageService" class="huangbowen.net.DependecyInjection.ConstructorInjection.SimpleMessageService"/>  <bean id="messageHandler" class="huangbowen.net.DependecyInjection.SetterInjection.MessageHandler">  <property name="messageService" ref="messageService"/>  </bean> 

如果property的name為messageService,那么必須在類中有個叫做setMessageService的方法,這樣才能完成注入。如果將MessageHandler.java中的setMessageService方法改為setMessageService1,那么注入就會失敗,失敗message如下所示。

1
2
3
4
5
6
7
... java.lang.IllegalStateException: Failed to load ApplicationContext  ... Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'messageHandler' defined in class path resource [spring-context.xml]: Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'messageService' of bean class [huangbowen.net.DependecyInjection.SetterInjection.MessageHandler]: Bean property 'messageService' is not writable or has an invalid setter method. Did you mean 'messageService1'?  ... 

當然可以同時使用構造器注入和setter方法注入。

Person.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Person {   private String name;   public Person(String name) {  this.name = name;  }   private int age;   public int getAge() {  return age;  }   public void setAge(int age) {  this.age = age;  }   public String getName() {  return name;  } } 

bean定義如下:

1
2
3
4
 <bean id="person" class="huangbowen.net.DependecyInjection.SetterInjection.Person">  <constructor-arg value="Tom"/>  <property name="age" value="20"/>  </bean> 

要實現一個bean,即可以使用構造器注入,也可以使用setter注入,甚至可以在一個bean中綜合使用這兩種方式。那么在真正開發中應該作何取舍那?一般來說,使用構造器注入的依賴必須是強制的依賴,而使用setter注入的依賴則是可選的依賴。使用構造器注入生成的對象是完全初始化了的,用戶可以直接拿來用,但是相比於setter方法而言用戶也就失去了定制化的能力。如果你發現構造器參數過多,那么很可能說明該類承擔的職責過多,應該從設計解耦的角度對類的職責進行拆分。使用setter注入的對象好處是,用戶可以按需重新注入新的屬性。

另外在進行依賴注入時,可以將某些屬性抽出來成為一個元素,或者將元素內聯成為一個屬性。比如ref這個屬性。

1
2
3
 <bean id="messageHandler" class="huangbowen.net.DependecyInjection.SetterInjection.MessageHandler">  <property name="messageService" ref="messageService" />  </bean> 

它與以下xml配置完全等價。

1
2
3
4
5
 <bean id="messageHandler" class="huangbowen.net.DependecyInjection.SetterInjection.MessageHandler">  <property name="messageService">  <ref bean="messageService"/>  </property>  </bean> 

value屬性也可以獨立為元素。

1
2
3
4
 <bean id="person" class="huangbowen.net.DependecyInjection.SetterInjection.Person">  <constructor-arg value="Tom"/>  <property name="age" value="20"/>  </bean> 

其等價於:

1
2
3
4
5
6
 <bean id="person" class="huangbowen.net.DependecyInjection.SetterInjection.Person">  <constructor-arg value="Tom"/>  <property name="age">  <value>20</value>  </property>  </bean> 

也可以顯式指定value的類型。

1
2
3
4
5
6
 <bean id="person" class="huangbowen.net.DependecyInjection.SetterInjection.Person">  <constructor-arg value="Tom"/>  <property name="age">  <value type="int">20</value>  </property>  </bean> 

比如有一個屬性是個boolean值,如果想將其注入為true的話,不指定具體類型的話,Spring可能會將其作為字符串true對待。當然Spring會嘗試將傳入的字符串轉換為setter方法希望的類型,但這種自動轉換有時候並不是你期望的,這種情況下你就需要顯式指定其類型。

本例中的源碼請在我的GitHub上自行下載。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM