现在的项目中所遇到的问题
业务层需要调用数据层的方法,就需要在业务层new数据层的对象。如果数据层的实现类发生变化,那么业务层的代码也需要跟着改变,发生变更后,都需要进行编译打包和重部署:
所以,现在代码在编写的过程中存在的问题是:耦合度偏高
针对这个问题,该如何解决呢?
我们就想,如果能把框中的内容给去掉,不就可以降低依赖了么,但是又会引入新的问题,去掉以后程序能运行么?
答案肯定是不行,因为bookDao没有赋值为Null,强行运行就会出空指针异常。
所以现在的问题就是,业务层不想new对象,运行的时候又需要这个对象,该咋办呢?
针对这个问题,Spring就提出了一个解决方案:
- 使用对象时,在程序中不要主动使用new产生对象,转换为由外部提供对象
这种思想其实就是ioc
这种实现思想就是Spring的一个核心概念
IOC
IOC(Inversion of Control)控制反转
使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到外部,此思想称为控制反转。
业务层要用数据层的类对象,以前是自己
new
的, 现在自己不new了,交给别人[外部]
来创建对象,别人[外部]
就反转控制了数据层对象的创建权,这种思想就是控制反转
我们可以说IOC存在的意义就是解耦
那么Spring技术跟IOC有什么关系呢?
Spring对IOC这个思想进行了实现!Spring提供了一个容器,称为IOC容器,用来充当IOC思想中的"外部"。IOC思想中的别人[外部]
指的就是Spring的IOC容器。
这个IOC容器有人也称为Spring容器,它其实就对应着下图中的core container:
也就是说先前我们的代码中创建对象全靠new:
而现在创建对象我们不用管了,全部交给IOC容器:
IOC容器的作用:负责对象的创建、初始化等一系列工作,其中包含了数据层和业务层的类对象。
但是现在如果我们的程序运行的话时会报错的!加入现在它为我们在业务层创建了一个Service对象,但是Service对象依赖着Dao对象,否则根本无法运行。IOC容器中虽然有service和dao对象,但是service对象和dao对象没有任何关系,需要把dao对象交给service,也就是说要绑定service和dao对象之间的关系:
DI
DI(Dependency Injection)依赖注入:在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入
像这种在容器中建立对象与对象之间的绑定关系就要用到DI
业务层要用数据层的类对象,以前是自己
new
的,现在自己不new了,靠别人[外部其实指的就是IOC容器]
来给注入进来,这种思想就是依赖注入
介绍完Spring的IOC和DI的概念后,我们会发现这两个概念的最终目标就是:充分解耦,具体实现靠:
- 使用IOC容器管理bean(IOC)
- 在IOC容器内将有依赖关系的bean进行关系绑定(DI)
- 最终结果为:使用对象时不仅可以直接从IOC容器中获取,并且获取到的bean已经绑定了所有的依赖关系.
Bean
被创建或被管理的对象在IOC容器中统称为Bean
也就是说IOC容器中放的就是一个个的Bean对象
IOC初次使用(XML版)
步骤①:创建maven项目
步骤②:添加Spring的依赖jar包
在pom.xml文件中(也就是项目配置文件中)将下面的代码粘进去:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
步骤③:添加案例中需要的类
创建BookService,BookServiceImpl,BookDao和BookDaoImpl四个类。(两个接口,两个实现类)
public interface BookDao {
public void save();
}
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
}
public interface BookService {
public void save();
}
public class BookServiceImpl implements BookService {
private BookDao bookDao = new BookDaoImpl();
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
添加完后我的项目结构:
步骤④:添加spring配置文件并在配置文件中完成bean的配置
resources下添加spring配置文件applicationContext.xml,并完成bean的配置:
在Spring的配置文件中,使用bean标签标示配置bean,其中id属性标示给bean起名字,class属性表示给bean定义类型(这里的类型使用全类名)
<?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">
<!--bean标签标示配置bean
id属性标示给bean起名字
class属性表示给bean定义类型
-->
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"/>
</beans>
注意事项:bean定义时id属性在同一个上下文中(配置文件)不能重复
步骤⑤:获取IOC容器
使用Spring提供的接口完成IOC容器的创建
记得传入Spring的配置文件
public class App {
public static void main(String[] args) {
//获取IOC容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
}
}
步骤⑥:从容器中获取对象进行方法调用
在容器中拿出来的对象均为Object类型,需要我们进行强转
public class App {
public static void main(String[] args) {
//获取IOC容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// BookDao bookDao = (BookDao) ctx.getBean("bookDao");
// bookDao.save();
BookService bookService = (BookService) ctx.getBean("bookService");
bookService.save();
}
}
总结:
(1)Spring是使用容器来管理bean对象的,那么管什么?
- 主要管理项目中所使用到的类对象,比如(Service和Dao)
(2)如何将被管理的对象告知IOC容器?
- 使用配置文件
(3)被管理的对象交给IOC容器,要想从容器中获取对象,就先得思考如何获取到IOC容器?
- Spring框架提供相应的接口
(4)IOC容器得到后,如何从容器中获取bean?
- 调用Spring框架提供对应接口中的方法