1、IOC理论推导
新建一个空白的maven
项目,我们先用我们原来的方式写一段代码。
导入依赖(jar包)
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
原始方法
步骤
- 创建
UserDao
接口
public interface UserDao {
void getUser();
}
- 创建
UserDaoImpl
实现类
public class UserDaoImpl implements UserDao {
@Override
public void getUser() {
System.out.println("默认获取用户的数据");
}
}
- 创建
UserService
业务接口
public interface UserService {
void getUser();
}
- 创建
UserServiceImpl
业务实现类
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoImpl();
@Override
public void getUser() {
userDao.getUser();
}
}
- 测试
public class MyTest {
public static void main(String[] args) {
// 用户实际调用的是业务层,dao层不需要接触
UserServiceImpl userService = new UserServiceImpl();
userService.getUser();
}
}
将原来的方式进行修改
- 把
UserDao
的实现类增加一个
public class UserDaoMySqlImpl implements UserDao {
@Override
public void getUser() {
System.out.println("MySql获取用户数据");
}
}
- 紧接着我们要去使用
MySql
的话 , 我们就需要去service
实现类里面修改对应的实现
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoMySqlImpl();
@Override
public void getUser() {
userDao.getUser();
}
}
在假设, 我们再增加一个Userdao的实现类
public class UserDaoOracleImpl implements UserDao {
@Override
public void getUser() {
System.out.println("Oracle获取用户数据");
}
}
那么我们要使用Oracle , 又需要去service实现类里面修改对应的实现 . 假设我们的这种需求非常大 , 这种方式就根本不适用了, 甚至反人类 , 每次变动 , 都需要修改大量代码 . 这种设计的耦合性太高了, 牵一发而动全身 .
那我们如何去解决这个问题呢 ?
我们可以在需要用到他的地方 , 不去实现它 , 而是留出一个接口 , 利用set , 我们去代码里修改下 !!!
public class UserServiceImpl implements UserService {
private UserDao userDao;
// 利用set进行动态实现值的注入
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void getUser() {
userDao.getUser();
}
}
再次进行测试
public class MyTest {
public static void main(String[] args) {
// 用户实际调用的是业务层,dao层不需要接触
UserServiceImpl userService = new UserServiceImpl();
userService.setUserDao(new UserDaoMySqlImpl());
userService.getUser();
}
}
大家发现了区别没有 ? 可能很多人说没啥区别 . 但是同学们 , 他们已经发生了根本性的变化 , 很多地方都不一样了 . 仔细去思考一下 , 以前所有东西都是由程序去进行控制创建, 而现在是由我们自行控制创建对象 , 把主动权交给了调用者 . 程序不用去管怎么创建,怎么实现了 . 它只负责提供一个接口 。
总结:
- 之前,程序是主动创建对象!控制权在程序猿手上
- 使用了
set
注入后,程序不再具有主动性,而是变成了被动的接受对象
本质上解决了问题 , 我们程序员不再去管理对象的创建了 , 更多的去关注业务的实现 . 耦合性大大降低 . 这也就是IOC的原型
2、IOC本质
控制反转,是面向对象编程的一种设计原则,可以用来降低计算机代码之间的耦合度,其中最常见的方式叫做依赖注入。
把对象创建和对象之间的调用过程,交给Spring进行管理
使用IOC目的:为了降低耦合度
IOC是Spring框架的核心内容
,使用多种方式完美的实现了IOC
,可以使用XML
配置,也可以使用注解
,新版本的Spring也可以零配置实现IOC
。
Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从IOC容器中取出需要的对象。
IOC底层原理:xml解析,工厂模式,反射
IOC过程——进一步降低耦合度
- 第一步:编写
xml
配置文件,配置创建的对象<bean id = "dao" class = "com.study.....>
- 第二步:有
service
类和dao
类,创建工厂类class UserFactory { public stat ic UserDao get Dao(){ //xml解析 String classValue = class属性值; //通过反射创建对象 Class clazz = Class.forName(classValue); return (UserDao)clazz.newInstance(); } }
IOC接口(BeanFactory)
-
IOC
思想基于IOC
容器完成,I0C
容器底层就是对象工厂 -
Spring
提供的IOC
容器实现的两种方式:两个接口BeanFacory
:IOC
容器基本实现,是Spring
内部使用的接口,不提供给开发人员使用。特点
:加载配置文件的时候不会去创建对象,在获取对象的时候才会创建对象
-
ApplicationContext
:BeanFacory接口的子接口
,提供更多更强大的功能,一般开发人员进行使用特点
:加载配置文件的时候就会把配置文件对象进行创建
-
ApplicationContext接口有实现类
3、IOC操作Bean管理
什么是Bean管理:Bean管理指的是两个操作,1.Spring创建对象,2.Spring注入属性
创建对象:
Bean管理操作有两种方式:1.基于xml配置文件方式实现,2.基于注解方式实现
1、基于xml方式
- 在
Spring
配置文件中,使用bean
标签,标签里面添加对象属性,就可以实现对象创建 Bean
标签有很多属性,介绍常用的属性id属性
:唯一标识(起别名)class属性
:类的全路径(包类路径)
创建对象的时候,默认也是去执行无参数构造方法来完成对象构造
DI:依赖注入,就是注入属性,IOC和DI的区别:DI是IOC中的一种具体实现方式,注入属性需要在创建对象的基础之上完成
-
第一种注入方式:使用
set
方法进行注入- 创建类,定义属性和对应的
set
方法 - 在
Spring
配置文件中配置对象创建,配置属性注入
- 创建类,定义属性和对应的
-
第二种注入方式:使用有参数构造注入
- 创建类,定义属性,创建属性对应有参构造方法
- 在
Spring
配置文件中进行配置
-
p名称空间注入(了解即可):使用p名称空间注入,可以简化基于xml的配置方式
- 第一步:在配置文件(
xml约束
)中添加p
名称空间 - 进行属性注入,在
bean
标签里面进行操作
- 第一步:在配置文件(
总结:注入属性需要在创建对象的基础上完成
2、基于xml方式(xml注入其他类型属性)
1、概念:字面量(null值,属性值包含特殊符号)
-
null
值
-
属性值包含特殊符号
2、注入属性——外部bean
- 创建两个类:
server和dao类
service
类dao
类和实现类
在service中调用dao中的方法
-
原始方式
-
在
Spring
配置文件中进行配置
-
3、注入属性——内部bean和级联赋值
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。