返回介绍

1. IOC 控制反转

发布于 2025-02-23 12:20:58 字数 5499 浏览 0 评论 0 收藏 0

1.1 什么是 IOC

IoC (Inversion of Control),意为控制反转,不是什么技术,而是一种设计思想。Ioc 意味着 将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制

如何理解好 Ioc 呢?理解好 Ioc 的关键是要明确 谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了,那我们来深入分析一下:

  • 谁控制谁,控制什么 :传统 Java SE 程序设计,我们直接在对象内部通过 new 进行创建对象,是程序主动去创建依赖对象;而 IoC 是有专门一个容器来创建这些对象,即由 Ioc 容器来控制对 象的创建;谁控制谁?当然是 IoC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。
  • 为何是反转,哪些方面反转了 :有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。

简单来说

正转:比如有一个类,在类里面有方法(不是静态的方法),调用类里面的方法,创建类的对象,使用对象调用方法,创建类对象的过程,需要 new 出来对象

反转:把对象的创建不是通过 new 方式实现,而是交给 Spring 配置创建类对象

1.2 IoC 能做什么

IoC 不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合、更优良的程序。传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;有了 IoC 容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。

其实 IoC 对编程带来的最大改变不是从代码上,而是从思想上,发生了“主从换位”的变化。应用程序原本是老大,要获取什么资源都是主动出击,但是在 IoC/DI 思想中,应用程序就变成被动的了,被动的等待 IoC 容器来创建并注入它所需要的资源了。

IoC 很好的体现了面向对象设计法则之一—— 好莱坞法则:“别找我们,我们找你”;即由 IoC 容器帮对象找相应的依赖对象并注入,而不是由对象主动去找。

1.3 IoC 和 DI

DI—Dependency Injection,即“依赖注入” :组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。

理解 DI 的关键是:“ 谁依赖谁,为什么需要依赖,谁注入谁,注入了什么 ”,那我们来深入分析一下:

  • 谁依赖于谁: 当然是应用程序依赖于 IoC 容器;
  • 为什么需要依赖: 应用程序需要 IoC 容器来提供对象需要的外部资源;
  • 谁注入谁: 很明显是 IoC 容器注入应用程序某个对象,应用程序依赖的对象;
  • 注入了什么: 就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)。

IoC 和 DI 由什么关系呢?其实它们是同一个概念的不同角度描述,由于控制反转概念比较含糊(可能只是理解为容器控制对象这一个层面,很难让人想到谁来维护对象关系),所以 2004 年大师级人物 Martin Fowler 又给出了一个新的名字:“依赖注入”,相对 IoC 而言, “依赖注入” 明确描述了 “被注入对象依赖 IoC 容器配置依赖对象”

对于 Spring Ioc 这个核心概念,我相信每一个学习 Spring 的人都会有自己的理解。这种概念上的理解没有绝对的标准答案,仁者见仁智者见智。 理解了 IoC 和 DI 的概念后,一切都将变得简单明了,剩下的工作只是在框架中堆积木而已,下一节来看看 Spring 是怎么用的

1.4 IOC 底层原理 (降低类之间的耦合度)

  • 底层原理使用技术
    • xml 配置文件
    • dom4j 解决 xml
    • 工厂设计模式
    • 反射
  • 原理
//伪代码
//需要实例化的类
public class UserService{
}

public class UserServlet{
    //得到 UserService 的对象
    //原始的做法:new 对象();  来创建
    
    //经过 spring 后
    UserFactory.getService();   //(下面两步的代码调用的)
}

第一步:创建 xml 配置文件,配置要创建的对象类

<bean id="userService" class="cn.blinkit.UserService"/>

第二步:创建工厂类,使用 dom4j 解析配置文件+反射

public class Factory {
    //返回 UserService 对象的方法
    public static UserService getService() {
        //1.使用 dom4j 来解析 xml 文件  
        //根据 id 值 userService,得到 id 值对应的 class 属性值
        String classValue = "class 属性值";
        //2.使用反射来创建类对象
        Class clazz = Class.forName(classValue);
        //创建类的对象
        UserService service = clazz.newInstance();
        return service;
    }
}

超详细原理讲解: java-bible/4.principle.md at master · biezhi/java-bible

1.5 Spring 中怎么用

(1)配置文件方式

我们在 Spring 中是这样获取对象的:

public static void main(String[] args) {   
	ApplicationContext context = new FileSystemXmlApplicationContext("applicationContext.xml");   
	Lol lol = (Lol) context.getBean("lol");   
	lol.gank(); 
}

一起看看 Spring 如何让它生效呢,在 applicationContext.xml 配置文件中是酱紫的:

<bean id="lol" class="com.biezhi.test.Lol">
	<property name="name" value="剑圣" />   
</bean>  

Lol 类是这样的:

public class Lol {

	private String name;
	
	public Lol() {
	}
	
	public void gank(){
		System.out.println(this.name + "在 gank!!");
	}
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

上面的代码运行结果自然是 剑圣在 gank!!

(2)注解方式

Spring 更高级的用法,在 3.0 版本之后有了基于 Annotation 的注入实现,为毛每次都要配置 Xml 看到都蛋疼。。

首先还是要在 xml 中配置启用注解方式

<context:annotation-config/>  

这样就能使用注解驱动依赖注入了,下面是一个使用场景

public class Lol {

	@Autowired
	private DuangService duangService ;
	
	public void buyDuang(String name, int money) {
		duangService.buy(name, money);
	}
}
@Service("duangService")
public class DuangService {
	
	public void buy(String name, int money){
		if(money > 0){
			System.out.println(name + "买了" + money + "毛钱的特效,装逼成功!");
		} else{
			System.out.println(name + "没钱还想装逼,真是匪夷所思");
		}
	}
}

这只是一个简单的例子,剑圣打野的时候想要买 5 毛钱的三杀特效,嗯。。虽然不符合逻辑

此时 DuangService 已经注入到 Lol 对象中,运行代码的结果(这里是例子,代码不能运行的)就是:

德玛买了 5 毛钱的特效,装逼成功!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文