Spring 框架编程——控制反转(IoC,Inversion of Control)和依赖注入(DI,Dependency Injection)的基本用法
文章目录
- Spring 框架编程——控制反转(IoC,Inversion of Control)和依赖注入(DI,Dependency Injection)的基本用法
- 前言
- 简单例子理解控制反转和依赖注入
- 代码编写步骤
- 1、编写一个实体对象User。写好getter,setter,toString方法。
- 2、在resource目录下新建配置文件:applicationContext.xml
- 3、创建UserDao接口和实现类UserDaoImpl,编写save方法,模拟持久层保存用户信息。
- 4、applicationContext.xml中增加配置 userDao 对象的信息
- 5、编写 UserService 接口和他的实现类 UserServiceImpl
- 6、applicationContext.xml中增加配置 userService 对象
- 7、编写 UserController 模拟发起用户信息的保存请求
- 8、applicationContext.xml中增加配置 userController 对象
- 9、测试代码。
- 10、小结
前言
上一节,简单 介绍了 springboot 框架编写web应用程序,可见在sprinboot框架写编写web应用程序时多么便利。但要理解其编程方法还需要进一步学习。这一节 通过一个简单的例子理解spring框架的核心概念 :控制反转(IoC,Inversion of Control)和依赖注入(DI,Dependency Injection)
简单例子理解控制反转和依赖注入
新建一个maven工程,pom文件中引入spring框架:
<?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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zhc</groupId>
<artifactId>spring-1</artifactId>
<version>1.0-SNAPSHOT</version>
<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.2.0.RELEASE</version>
</dependency>
</dependencies>
</project>
工程目录结构如下:
代码编写步骤
1、编写一个实体对象User。写好getter,setter,toString方法。
package com.zhc.domain;
/**
* 第1步,编写一个实体对象。写好getter,setter,toString方法。
*/
public class User {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
2、在resource目录下新建配置文件:applicationContext.xml
配置User对象 2个 到spring的容器中,scope="prototype" 告诉spring容器,User对象在需要时创建且可存在多个User对象的实列
代码中使用id来获取spring容器中的对象,因此id不能重复。
将创建的对象的任务交给spring框架来执行,而不是像平时通过new来执行。
这种编程的思路可理解为:控制反转(IoC,Inversion of Control)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 第2步,配置User对象 2个 到spring的容器中,scope="prototype" 告诉spring容器,User对象在需要时创建且可存在多个User对象的实列
代码中使用id来获取spring容器中的对象,因此id不能重复。
将创建的对象的任务交给spring框架来执行,而不是像平时通过new来执行。
这种编程的思路可理解为:控制反转(IoC,Inversion of Control)-->
<bean id="user1" class="com.zhc.domain.User" scope="prototype">
<property name="name" value="alis"></property>
<property name="age" value="20"></property>
</bean>
</beans>
3、创建UserDao接口和实现类UserDaoImpl,编写save方法,模拟持久层保存用户信息。
package com.zhc.dao.impl;
import com.zhc.dao.UserDao;
import com.zhc.domain.User;
/**
* 第3步,创建UserDao接口和实现类UserDaoImpl,编写save方法,模拟保存用户信息。
*/
public class UserDaoImpl implements UserDao {
public String save(User user){
System.out.println("保存完毕:"+user.toString());
return "保存成功";
}
}
4、applicationContext.xml中增加配置 userDao 对象的信息
<!-- 第4步,配置 userDao 对象的信息到spring的容器中,scope="singleton" 告诉spring容器,userDao 在加载配置文件时就创建好,且只能存在1个。-->
<bean id="userDao" class="com.zhc.dao.impl.UserDaoImpl" scope="singleton"></bean>
5、编写 UserService 接口和他的实现类 UserServiceImpl
package com.zhc.service.impl;
import com.zhc.dao.UserDao;
import com.zhc.domain.User;
import com.zhc.service.UserService;
/**
* 第 5 步,编写 UserService 接口和他的实现类 UserServiceImpl
* 增加 UserDao 对象作为 UserServiceImpl 的属性用于操作保存用户信息;
* save 是否能成功的业务代码逻辑应写在这里。
* 这个 userDao对象,则是 UserService 的依赖。通常我们的写法是 UserDao userDao = new UserDao() 来创建对象。
* 而现在使用spring框架,userDao对象不用自己new,而是从spring容器中根据id去取。
* 下一步是在spring配置文件中配置bean,让spring根据配置文件自动创建 UserDao 对象。
* 由于 UserDao 对象也配置,因此 UserService 在配置时,要把属性 userDao 也配置为从容器中获取对象实例。
* 这个编程模式,可理解为:依赖注入(DI,Dependency Injection)
*/
public class UserServiceImpl implements UserService {
private UserDao userDao;
@Override
public String save(User user) {
// 写业务逻辑
if(user.getName() == null){
return "用户名不能为空";
}
if(user.getAge() < 0 || user.getAge() > 150){
return "年龄输入不符合业务要求,应该输入 0-150之间的值。";
}
System.out.println("调用DAO层的userDao的save方法保存user对象。");
return userDao.save(user);
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
6、applicationContext.xml中增加配置 userService 对象
<!-- 第6步,配置 userService 对象的信息到spring的容器中,scope="singleton" 告诉spring容器,userService 在加载配置文件时就创建好,且只能存在1个。
由于 userService 需要用到 userDao 来操作user的进行保存,即 userService依赖 userDao 。
因此将 userService 的属性 userDao 配置为从spring容器中获取:ref="userDao",这就是依赖注入的配置方法。-->
<bean id="userService" class="com.zhc.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao" ></property>
</bean>
7、编写 UserController 模拟发起用户信息的保存请求
package com.zhc.controller;
import com.zhc.domain.User;
import com.zhc.service.UserService;
/**
* 第7步,编写 UserController 模拟发起用户信息的保存请求
*/
public class UserController {
private UserService userService;
public String save(User user){
if(user == null){
return "保存的user对象不能为空";
}
return userService.save(user);
}
public void setUserService(UserService userService) {
this.userService = userService;
}
}
8、applicationContext.xml中增加配置 userController 对象
<!-- 第8步,配置 userController 对象的信息到spring的容器中,scope="singleton" 告诉spring容器,userController 在加载配置文件时就创建好,且只能存在1个。
同样,userController 用到了userService ,因此也需要配置依赖-->
<bean id="userController" class="com.zhc.controller.UserController">
<property name="userService" ref="userService"></property>
</bean>
9、测试代码。
package com.zhc;
import com.zhc.controller.UserController;
import com.zhc.domain.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
public static void main(String[] args) {
/**
* 第9步,测试。
*/
// 加载spring配置文件,读取配置文件,将配置中的scope="singleton"(单例)bean标签,根据配置信息创建对象并放入spring容器中。
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
// 调用 app 的 getBean( id )方法,通过id从spring容器中获取对象,得到的对象是Object,需要强制转换一下。
UserController controller = (UserController) app.getBean("userController");
// 从spring容器中获取 User 对象 user1,由于 User对象配置的是多例模式,scope="prototype",spring框架会在getBean()方法调用时创建User对象。
User user = (User)app.getBean("user1");
//调用 controller 的保存用户方法。
String result = controller.save(user);
System.out.println("用户:"+user + "的保存结果为:" + result );
// 从spring容器中获取User对象 user2,由于 User对象配置的是多例模式,scope="prototype",spring框架会在getBean()方法调用时创建User对象。
User user2 = (User)app.getBean("user2");
//调用 controller 的保存用户方法。
String result2 = controller.save(user);
System.out.println("用户:"+user + "的保存结果为:" + result2 );
}
}
10、小结
整个工程只有一个new关键字,那就是通过配置文件创建spring容器的上下文,
new ClassPathXmlApplicationContext(“applicationContext.xml”);
其他的对象创建工作全部交给了spring框架来管理。
这样做的好处是解耦合,比如 UserDao的实现修改了,变成NewUserDaoImpl.java,只需要改下配置文件,将 UserDaoImpl 改为 NewUserDaoImpl 即可。不需要修改 UserService 中的代码。
工程示例代码:
链接:https://pan.baidu.com/s/1A9QURA1FjxQXuKZf2nsiDQ
提取码:z26a