依赖注入
-
Setter 注入
-
简单类型
-
引用类型
-
-
构造器注入
-
简单类型
-
引用类型
-
setter 注入
-
首先,定义一个接口和实现类:
public interface DataService {
void saveData(String data);
}
public class DataServiceImpl implements DataService {
private String data;
public void saveData(String data) {
this.data = data;
System.out.println("Data saved: " + data);
}
// Setter 方法
public void setData(String data) {
this.data = data;
}
}
-
在 Spring 配置文件(例如 applicationContext.xml)中配置 Bean 并进行 Setter 注入:
<bean id="dataService" class="com.example.DataServiceImpl">
<property name="data" value="Hello, Spring!" />
</bean>
在上面的配置中,我们指定了 dataService
这个 Bean 的 data
属性将会被注入为 "Hello, Spring!"。
-
使用 Spring 容器获取 Bean 并调用方法:
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
DataService dataService = (DataService) context.getBean("dataService");
dataService.saveData("Example data");
}
}
在运行时,Spring 容器会实例化 DataServiceImpl
对象,并自动调用 setData
方法将值注入到 data
属性中。然后我们可以调用 saveData
方法来保存数据。
通过 Setter 注入,我们可以灵活地配置 Bean 的属性值,实现解耦合,方便单元测试和维护。
构造器注入
特点:
-
在实例化 Bean 时注入依赖:构造器注入是在创建 Bean 实例的过程中完成的,确保了 Bean 在使用之前已经具备了所需的依赖。
-
适用于强制依赖项:对于某些必须的依赖项,使用构造器注入可以确保这些依赖项不会被遗漏,提高了代码的健壮性。
-
可读性强:构造器注入将依赖项明确地传递给 Bean,使得代码更易于理解和维护。
示例:
假设有一个 UserService
类需要依赖 UserDao
类来进行数据库操作,可以通过构造器注入方式将 UserDao
注入到 UserService
中:
-
定义 Bean 的类:
package com.example; public class UserService { private final UserDao userDao; public UserService(UserDao userDao) { this.userDao = userDao; } // other methods }
-
Spring 配置文件中进行构造器注入:
<bean id="userDao" class="com.example.UserDao"/> <bean id="userService" class="com.example.UserService"> <constructor-arg ref="userDao"/> </bean>
在上面的示例中,通过 <constructor-arg>
元素将 userDao
Bean 注入到了 userService
Bean 中的构造函数中,实现了构造器注入的功能。
构造器注入是一种常用的依赖注入方式,在某些情况下特别适合用来传递必要的依赖关系。
区别比较与选择
Setter 注入:
-
方式:Setter 注入是通过调用 Bean 的 Setter 方法来设置依赖项。
-
使用场景:适用于可选或可变的依赖项,可以根据需要随时更改依赖项。
-
灵活性:由于可以随时调用 Setter 方法设置依赖项,因此具有更大的灵活性。
-
可读性:Setter 注入可能会导致类中出现大量的 Setter 方法,降低了代码的可读性。
构造器注入:
-
方式:构造器注入是通过 Bean 的构造函数来传递依赖项。
-
使用场景:适用于必需的依赖项,确保对象在实例化时就具备了所有必要的依赖。
-
安全性:构造器注入确保在对象实例化时就传递了所有必需的依赖项,提高了程序的健壮性。
-
不变性:一旦对象实例化完成,依赖项通常不会再改变,保持了对象的不变性。
如何选择:
-
如果一个依赖项是必需的,最好使用构造器注入,因为它能够保证对象实例化时就具备必要的依赖。
-
如果依赖项是可选的或者可能会变动,可以考虑使用 Setter 注入,因为它提供了更大的灵活性。
-
Spring 框架倡导使用构造器,第三方框架内部大多数采用构造器注入的方式进行数据初始化,相对严谨
-
自己开发的模块推荐使用setter注入
<property>
和与<constructor-arg>
-
在 Spring 配置文件中,
<property>
和<constructor-arg>
是用来设置 Bean 的属性或构造函数参数的元素,它们分别表示不同的含义:
-
<property>
元素:用于设置 Bean 的属性值,通常用于进行依赖注入或配置属性的取值。具体含义如下:-
作用:
<property>
元素用于为一个 Bean 的属性赋值,可以通过 Spring 容器来自动注入这些属性值,从而实现松耦合的依赖注入。 -
使用场景:适用于需要在 Bean 实例化之后为其成员变量赋值的情况,例如设置数据库连接、调整日志级别等。
-
示例:
<bean id="exampleBean" class="com.example.ExampleBean"> <property name="message" value="Hello, Spring!"/> </bean>
-
-
<constructor-arg>
元素:用于设置 Bean 的构造函数参数值,用来传递参数给 Bean 的构造函数。具体含义如下:-
作用:
<constructor-arg>
元素用于为一个 Bean 的构造函数参数赋值,通过指定构造函数参数的值来创建 Bean 实例。 -
使用场景:适用于需要在 Bean 实例化时提供构造函数参数的情况,例如传递依赖对象或配置初始化参数。
-
示例:
<bean id="exampleBean" class="com.example.ExampleBean"> <constructor-arg value="Hello, Spring!"/> </bean>
-
总的来说,<property>
用于设置 Bean 的属性值,而 <constructor-arg>
用于设置 Bean 的构造函数参数值。通过这两个元素,我们可以在 Spring 配置文件中灵活地配置 Bean 的属性和构造函数参数,实现依赖注入和对象实例化的定制化。
依赖自动装配
-
根据类型自动装配(byType): Spring 根据 Bean 的类型自动装配依赖项,如果容器中有且仅有一个与目标类型匹配的 Bean,则自动装配成功;如果找到多个匹配的 Bean,则会抛出异常。
示例:
<bean id="userDao" class="com.example.UserDao"/> <bean id="userService" class="com.example.UserService" autowire="byType"/>
-
根据名称自动装配(byName): Spring 根据 Bean 的名称自动装配依赖项,容器会查找与目标名称匹配的 Bean,并将其注入到对应的属性中。
示例:
<bean id="userDao" class="com.example.UserDao"/> <bean id="userService" class="com.example.UserService" autowire="byName"/>
-
构造器自动装配: Spring 会根据构造函数参数的类型或名称来自动装配 Bean。
示例:
<bean id="userDao" class="com.example.UserDao"/> <bean id="userService" class="com.example.UserService" autowire="constructor"/>
-
自动装配注解: 除了在配置文件中使用自动装配外,Spring 还提供了基于注解的自动装配方式,如
@Autowired
、@Resource
和@Inject
等注解,可以直接在类的字段、Setter 方法或构造函数上使用,简化了配置工作。示例:
public class UserService { @Autowired private UserDao userDao; }