1.IoC 和 DI的关系
IoC(Inversion of Control,控制反转)和DI(Dependency Injection,依赖注入)是Spring框架中紧密相关但又有所区别的两个概念。理解它们的联系,可以帮助我们更深刻地掌握Spring的核心设计理念。以下是IoC和DI的联系分析:
-
IoC是目标,DI是手段
IoC是一种设计思想,核心是将对象的创建、依赖管理和生命周期控制权从代码本身“反转”给外部容器(比如Spring容器)。它解决的是“谁来控制”的问题,强调控制权的转移。
DI是实现IoC的具体方式之一。通过依赖注入,容器主动将对象所需的依赖(其他对象或资源)提供给目标对象,而不是由对象自己去创建或查找依赖。换句话说,DI是IoC的一种“落地实践”。联系:IoC是宏观理念,描述了“反转”的思想,而DI是微观操作,回答了“怎么反转”的问题。在Spring中,IoC通常通过DI来实现,二者相辅相成。
举例:想象你是个导演(程序),传统方式是你亲自挑选演员(依赖)。IoC让你把选角权交给经纪公司(容器),而DI就是经纪公司把演员送到你面前的具体行动。
-
共同目标:解耦
IoC和DI的最终目的都是降低代码之间的耦合度。在没有IoC/DI时,对象A如果需要对象B,会直接new B(),导致A和B紧耦合。一旦B变了,A也要改。
IoC将B的创建交给容器,A只需要声明“我需要一个B”。DI则通过构造器、Setter等方式把B注入到A中,A不再关心B的来源。
联系:IoC提供了“解耦”的思想框架,DI是实现这一框架的具体工具,二者共同让代码更灵活、更易维护。
2.IoC & DI的使用
2.1示例1
在Spring中,IoC和DI是密不可分的搭档。IoC负责反转控制权,DI则是实现这一反转的具体手段。让我们通过一个简单的例子,看看它们如何在Spring中工作。
假设我们要开发一个“用户服务”,需要依赖一个“用户数据访问对象(DAO)”来查询数据库。传统方式是这样的:
public class UserService {
private UserDao userDao = new UserDaoImpl(); // 自己创建依赖
public void getUser() {
userDao.findUser();
}
}
这种方式耦合度高,如果UserDaoImpl
改了,UserService
也得跟着改。现在我们用Spring的IoC和DI重写:
-
定义Bean和依赖关系(通过Java配置类):
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class AppConfig { @Bean public UserDao userDao() { return new UserDaoImpl(); } @Bean public UserService userService(UserDao userDao) { // DI注入 return new UserService(userDao); } }
-
UserService接受注入:
public class UserService { private UserDao userDao; public UserService(UserDao userDao) { // 通过构造器注入 this.userDao = userDao; } public void getUser() { userDao.findUser(); } }
-
启动Spring容器并使用
import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class Main { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); UserService userService = context.getBean(UserService.class); userService.getUser(); } }
这里,Spring容器通过IoC接管了UserService
和UserDao
的创建,而DI则通过构造器将UserDao
注入到UserService
中。如果需要换成另一个UserDao
实现(比如UserDaoMock
),只需改配置类,UserService
完全不用动。
2.2示例2
2.3 示例3
BookController:
import org.example.booksmanagementsystem.book.service.BookService;
import org.example.booksmanagementsystem.book.model.BookInfo;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("book")
public class BookController {
// 加载数据
private BookService bookService=new BookService();
@RequestMapping("getBookList")
public List<BookInfo> getBookList(){
// 获取图书数据
List<BookInfo> bookInfos = bookService.getBookList(); ;
//返回图书列表
return bookInfos;
}
}
BookService:
import org.example.booksmanagementsystem.book.dao.BookDao;
import org.example.booksmanagementsystem.book.model.BookInfo;
import java.util.List;
public class BookService {
//加载数据
private BookDao bookDao = new BookDao();
//创建虚拟的数据
public List<BookInfo> getBookList(){
// 获取图书数据
List<BookInfo> bookInfos = bookDao.getBookList();
// 对图书进行处理
//设置书的状态
for(BookInfo bookInfo:bookInfos){
if(bookInfo.getStatus()==1){
bookInfo.setStatusCN("可借阅");
}else{
bookInfo.setStatusCN("不可借阅");
}
}
return bookInfos;
}
}
BookDao:
import org.example.booksmanagementsystem.book.model.BookInfo;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class BookDao {
//创建虚拟的数据
public List<BookInfo> getBookList(){
//创建15条数据
List<BookInfo> bookInfos = new ArrayList<>(15);
for (int i=0; i<15; i++){
BookInfo bookInfo = new BookInfo();
bookInfo.setId(i);
bookInfo.setBookName("图书"+i);
bookInfo.setAuthor("作者"+i);
bookInfo.setCount(new Random().nextInt(200));//生成200以下随机数
bookInfo.setPrice(new BigDecimal(new Random().nextInt(100)));
bookInfo.setPublish("出版社"+1);
bookInfo.setStatus(i%5==0?2:1);
//添加到列表
bookInfos.add(bookInfo);
}
return bookInfos;
}
}
⽬标: 把BookDao, BookService 交给Spring管理, 完成Controller层, Service层, Dao层的解耦步骤:
1.Service层及Dao层的实现类,交给Spring管理: 使⽤@Component
注解;
2.在Controller层 和Service层 注⼊运⾏时依赖的对象: 使⽤@Autowired
注解实现;
实现:
1.把BookDao 交给Spring管理, 由Spring来管理对象
@Component //把BookDao交给Spring管理
public class BookDao {
//创建虚拟的数据
public List<BookInfo> getBookList(){
//创建15条数据
List<BookInfo> bookInfos = new ArrayList<>(15);
for (int i=0; i<15; i++){
BookInfo bookInfo = new BookInfo();
bookInfo.setId(i);
bookInfo.setBookName("图书"+i);
bookInfo.setAuthor("作者"+i);
bookInfo.setCount(new Random().nextInt(200));//生成200以下随机数
bookInfo.setPrice(new BigDecimal(new Random().nextInt(100)));
bookInfo.setPublish("出版社"+1);
bookInfo.setStatus(i%5==0?2:1);
//添加到列表
bookInfos.add(bookInfo);
}
return bookInfos;
}
}
2.把BookService 交给Spring管理, 由Spring来管理对象
@Component //把BookService 交给Spring管理
public class BookService {
//加载数据
private BookDao bookDao = new BookDao();
//创建虚拟的数据
public List<BookInfo> getBookList(){
// 获取图书数据
List<BookInfo> bookInfos = bookDao.getBookList();
// 对图书进行处理
//设置书的状态
for(BookInfo bookInfo:bookInfos){
if(bookInfo.getStatus()==1){
bookInfo.setStatusCN("可借阅");
}else{
bookInfo.setStatusCN("不可借阅");
}
}
return bookInfos;
}
}
3.删除创建BookDao
的代码, 从Spring中获取对象
@Component
public class BookService {
//加载数据
// private BookDao bookDao = new BookDao();
@Autowired //从容器中注入
private BookDao bookDao;
//创建虚拟的数据
public List<BookInfo> getBookList(){
// 获取图书数据
List<BookInfo> bookInfos = bookDao.getBookList();
// 对图书进行处理
//设置书的状态
for(BookInfo bookInfo:bookInfos){
if(bookInfo.getStatus()==1){
bookInfo.setStatusCN("可借阅");
}else{
bookInfo.setStatusCN("不可借阅");
}
}
return bookInfos;
}
}
4.删除创建BookService的代码, 从Spring中获取对象
@RestController
@RequestMapping("book")
public class BookController {
// 加载数据
// private BookService bookService=new BookService();
@Autowired //从容器中注入
private BookService bookService;
@RequestMapping("getBookList")
public List<BookInfo> getBookList(){
// 获取图书数据
List<BookInfo> bookInfos = bookService.getBookList(); ;
//返回图书列表
return bookInfos;
}
}