上文讲了基于构造器进行依赖注入,这里讲解基于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 上自行下载。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· SQL Server 2025 AI相关能力初探
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库