IOC与AOP的理解
IOC与AOP的理解
IOC
IOC控制反转概述
控制反转是一种设计思想,将原本在程序中手动创建对象的控制权,交由Spring框架来管理。
IOC的思想最核心的地方在于,资源不由使用资源的双方管理,而由不使用资源的第三方管理
。这可以带来很多好处:
- 资源集中管理,实现资源的可配置和易管理
降低了使用资源双方的耦合度
理解依赖倒置原则
依赖倒置原则是设计模式的六大原则之一。其核心思想是面向接口编程
,其定义如下:
- 高层模块不应该依赖低层模块,两者都应该依赖其抽象
- 抽象不应该依赖细节
- 细节应该依赖抽象
这一原则在Java语言中的表现:
模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系通过接口或抽象类产生
- 接口或抽象类不依赖于实现类
- 实现类依赖接口或抽象类
通过一个简单的例子理解依赖倒置原则。
高层
—— 司机
package com.youzikeji.dr;
/**
* 司机
* 司机只会开奔驰车
*/
public class Driver {
public void drive (Benz benz) {
benz.run();
}
}
低层
—— 汽车
package com.youzikeji.dr;
/**
* 奔驰车
*/
public class Benz {
public void run (){
System.out.println("Benz车跑起了");
}
}
高低层紧耦合
package com.youzikeji.dr;
/**
* 司机和车紧耦合,系统可维护性大大降低
*/
public class Client {
public static void main(String[] args) {
Benz benz = new Benz();
Driver driver = new Driver();
driver.drive(benz);
}
}
依赖倒置——面向接口编程
接口回调:指的是可以把实现某一接口的类创建的对象的引用赋值给该接口声明的接口变量,那么该接口变量就可以调用被类实现的接口方法(当接口变量在调用被类实现的接口方法时,就是在通知相应的对象调用这个方法)。
package com.youzikeji.dr;
// 司机接口
public interface IDriver {
// 抽象方法 —— 开车
public void drive(ICar Car);
}
------------------------------------
package com.youzikeji.dr;
// 车的接口
public interface ICar {
// 抽象方法 —— 车子运转
public void run();
}
------------------------------------
package com.youzikeji.dr;
public class MyDriver implements IDriver{
@Override
public void drive(ICar car) {
car.run();
}
}
------------------------------------
package com.youzikeji.dr;
public class MyBenz implements ICar{
@Override
public void run() {
System.out.println("Benz车跑起来了");
}
}
------------------------------------
package com.youzikeji.dr;
public class MyBmw implements ICar{
@Override
public void run() {
System.out.println("bmw车跑起来了");
}
}
------------------------------------
package com.youzikeji.dr;
/**
* 依赖倒置后再测试
*/
public class DrClient {
public static void main(String[] args) {
IDriver driver = new MyDriver();
ICar bmw = new MyBmw();
driver.drive(bmw);
}
}
使用依赖倒置的好处
- 减少类间的耦合性,提高系统的稳定性,实现了团队协作、并行开发
- 提高代码的可读性和可维护性
依赖传递(注入)的三种方式
所谓依赖注入就是把底层类作为参数传入上层类,实现上层类对下层类的“控制”
-
构造函数传递
package com.youzikeji.dr; // 司机接口 public interface IDriver { // 抽象方法 —— 开车 public void drive(); } ------------------------------------ package com.youzikeji.dr; public class MyDriver implements IDriver{ private ICar car; // 构造函数注入 public MyDriver(ICar _car) { this.car = _car; } public void drive() { this.car.run(); } }
-
Setter方法传递
package com.youzikeji.dr; // 司机接口 public interface IDriver { // 设置车辆型号 public void setCar(ICar car); // 抽象方法 —— 开车 public void drive(); } ------------------------------------ package com.youzikeji.dr; public class MyDriver implements IDriver{ private ICar car; // setter方式注入 public void setCar(ICar car) { this.car = car; } public void drive() { this.car.run(); } }
-
接口声明依赖对象 —— 上一节的方式
IOC Container
IOC 容器是 Spring 用来实现IOC 的载体,实际上就是个Map(key,value),Map 中存放的是各种对象。
因为采用了依赖注入,IOC容器在进行上层类的初始化时,不可避免地会大量地new对象
,IOC容器可以自动对代码进行初始化,程序员只需要维护一个Configuration(可以是xml可以是一段代码),而不用每次初始化实例对象都要去写大段的初始化代码。
IOC容器在创建一个实例对象时,先从最上层开始往下找依赖关系,到最底层后再一步一步new对象
。
以建造汽车为例,汽车需要车的骨架,车的骨架需要底盘,底盘需要轮胎。在创建汽车实例时,IOC容器需要进行如下操作:
- 根据xml文件或者configuration类,查对象之间的依赖,根据依赖关系,找到最底层的对象,然后往上进行创建。
IOC容器可以直接隐藏具体的创建实例的细节,在我们来看它就像一个工厂,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可
,完全不用考虑对象是如何被创建出来的。
参考书籍:《设计模式之禅》 秦小波
AOP
AOP概述
Aspect-Oriented Programming,面向切面编程。能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。
Spring AOP的实现方式
Spring AOP的实现方式根据要代理的对象有没有实现接口的情况进行选择:
- 要代理的对象实现了某个接口 —— 使用JDK Proxy
- 对于没有实现接口的对象 —— 无法使用JDK Proxy,使用Cglib生成一个被代理对象的子类来作为代理
使用AOP的好处
使用AOP可以把一些通用功能抽象出来,在需要用到的地方直接使用即可,这样大大简化了代码量。我们需要增加新功能时也方便,这样也提高了系统扩展性。日志功能、事务管理等场景都用到了AOP。
利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低
,提高程序的可重用性,同时提高了开发效率。