依赖注入(DI)是一个过程,在这个过程中,对象仅通过构造函数参数、工厂方法的参数或在对象被实例化后通过属性设置来定义它们的依赖项(即与该对象一起工作的其他对象)。然后,容器在创建 bean 时注入这些依赖项。这个过程基本上是与对象直接通过构造类或等机制来控制其依赖项的实例化或位置是相反的,因此得名控制反转。// 对象不直接创建自己,而是通过 Spring 容器创建,那么 Spring 容器是如何创建对象的?
使用 DI 原则,代码会更简洁,当对象具有依赖关系时,也能更有效的解耦。对象不检索它的依赖项,也不知道依赖项的具体类或者位置。因此,你的类将变得更容易测试,特别是当依赖关系建立在接口或者抽象基类上时,他们的子类或者模拟实现将允许在单元测试中被使用。// 依赖注入最大的好处,就是代码可以解耦合变得更加简洁
DI 主要有两种变体:基于构造函数的依赖注入和基于 Setter 方法的依赖注入
基础环境
1.创建Module
2.引入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring</artifactId>
<groupId>com.biem</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>DI</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
</dependencies>
</project>
3. 创建实体类com.biem.spring.pojo.User.java
package com.biem.spring.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* ClassName: User
* Package: com.biem.spring.pojo
* Description:
*
* @Create 2023/5/25 18:07
* @Version 1.0
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private int id;
private String name;
private String password;
}
4. 创建applicationContext.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
4. 测试com.biem.spring.test.UserTest.java文件
package com.biem.spring.test;
import com.biem.spring.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* ClassName: UserTest
* Package: com.biem.spring.test
* Description:
*
* @Create 2023/5/25 18:13
* @Version 1.0
*/
public class UserTest {
}
基于构造函数的依赖注入
<constructor-arg>元素用于构造方法的注入,且定义时不分顺序,只需要通过name属性指定值即可。<constructor-arg>还提供了type属性用于指定参数类型,以避免字符串和基本类型的混淆。
实例
1.applicationContext.xml添加
<bean id="user1" class="com.biem.spring.pojo.User">
<constructor-arg name="id" value="1"></constructor-arg>
<constructor-arg name="name" value="张三"></constructor-arg>
<constructor-arg name="password" value="123456"></constructor-arg>
</bean>
2. com.biem.spring.test.UserTest.java添加
@Test
public void testConstructorDI(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = context.getBean("user1", User.class);
System.out.println("user = " + user);
}
3.输出结果
基于 Setter 方法的依赖注入
setter方法注入是通过<property>元素,<property>元素过name属性指定值。
实例
1.applicationContext.xml添加
<bean id="user2" class="com.biem.spring.pojo.User">
<property name="id" value="2"></property>
<property name="name" value="李四"></property>
</bean>
2. com.biem.spring.test.UserTest.java添加
@Test
public void testSetterDI(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = context.getBean("user2", User.class);
System.out.println("user = " + user);
}
3.输出结果
Null值处理
<property name="name">
<null />
</property>
name的值是null
<property name="name" value="null"></property>
name的值是字符串null
应用:简单登录系统
1.com.biem.spring.dao.UserDao.java
package com.biem.spring.dao;
/**
* ClassName: UserDao
* Package: com.biem.spring.dao
* Description:
*
* @Create 2023/5/25 19:45
* @Version 1.0
*/
public interface UserDao {
public boolean login(String name, String password);
}
2.com.biem.spring.dao.impl.UserDaoImpl.java
package com.biem.spring.dao.impl;
import com.biem.spring.dao.UserDao;
/**
* ClassName: UserDaoImpl
* Package: com.biem.spring.dao.imp
* Description:
*
* @Create 2023/5/25 19:46
* @Version 1.0
*/
public class UserDaoImpl implements UserDao {
@Override
public boolean login(String name, String password) {
if(name.equals("张三") && password.equals("123")){
return true;
}
return false;
}
}
3.com.biem.spring.service.UserService.java
package com.biem.spring.service;
/**
* ClassName: UserService
* Package: com.biem.spring.service
* Description:
*
* @Create 2023/5/25 21:29
* @Version 1.0
*/
public interface UserService {
public boolean login(String username, String password);
}
4.com.biem.spring.service.impl.UserServiceImpl.java
package com.biem.spring.service.impl;
import com.biem.spring.dao.UserDao;
import com.biem.spring.service.UserService;
/**
* ClassName: UserServiceImpl
* Package: com.biem.spring.service.impl
* Description:
*
* @Create 2023/5/25 21:31
* @Version 1.0
*/
public class UserServiceImpl implements UserService {
UserDao userDao;
public void setUserDao(UserDao userDao){
this.userDao = userDao;
}
@Override
public boolean login(String username, String password) {
return userDao.login(username, password);
}
}
5.编写applicationContext.xml配置文件
<bean id="userDao" class="com.biem.spring.dao.impl.UserDaoImpl"></bean>
<bean id="userService" class="com.biem.spring.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"/>
</bean>
6.编写测试方法
@Test
public void login(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService user = context.getBean("userService", UserService.class);
boolean flag = user.login("张三","123");
if(flag){
System.out.println("登录成功");
} else {
System.out.println("登录失败");
}
}
@Test
public void login(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService user = context.getBean("userService", UserService.class);
boolean flag = user.login("张三","1234");
if(flag){
System.out.println("登录成功");
} else {
System.out.println("登录失败");
}
}