在讲spring的IOC之前,我们先看一个示例
- 三层视图的示例
package bean1;
// service层
public class CallService {
private static CallDao callDao = new CallDao();
public void call() {
System.out.println("这是CallService");
callDao.save();
}
}
// dao层
class CallDao {
public void save() {
System.out.println("开始保存Call...");
}
}
// vo层
class CallVo {
private static CallService callService = new CallService();
public void voCall() {
System.out.println("这是VoCall...");
callService.call();
}
}
// 测试类
class TestCall {
public static void main(String[] args) {
CallVo callVo = new CallVo();
callVo.voCall();
}
}
从示例中,我们看到,每当需要调用某个类的时候,总是需要先new一个对象出来。
试想一下,如果我们有很多的类,那么我们需要反复不断的声明。
并且,过多的对象,也会造成系统性能的下降。
那么,是否可将这些new的操作,交给一个工厂来操作呢?
-
工厂创建对象
工厂创建的时候,如果直接根据名称创建,那么我们需要不断去修改代码完善,违反OCP(开闭)原则。
那么此时,我们是否可以考虑一下,将名称与类的对应关系,用一个配置文件描述?- 定义bean1.properties配置文件:
# bean1.properties文件 CallService=bean1.CallService CallDao=bean1.CallDao
- 声明工厂类-静态代码块Properties加载配置文件
class BeanFactory { private static Properties properties = new Properties(); static { InputStream ras = BeanFactory.class.getClassLoader().getResourceAsStream("bean1.properties"); try { properties.load(ras); } catch (IOException e) { e.printStackTrace(); throw new ExceptionInInitializerError("初始化BeanFactory失败"); } } public static Object getBean(String name) { String property = properties.getProperty(name); try { return Class.forName(property).newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } return null; } }
- 测试
class TestCall { public static void main(String[] args) { for (int i = 0; i < 5; i++) { Object callService = BeanFactory.getBean("CallService"); System.out.println(callService); } } }
- 结果
bean1.CallService@4b1210ee bean1.CallService@4d7e1886 bean1.CallService@3cd1a2f1 bean1.CallService@2f0e140b bean1.CallService@7440e464
可以看到,可以正常的获取到类对象
但同时,我们发现,每次getBean的时候,都会生成新的对象,这个并不是我们想要的,因为,频繁的创建对象会造成性能损失、内存消耗。
这种场景下,单例模式的可能会更适合我们
因此,我们需要有一个 “容器” 来保存实例化的对象,从而引出了容器的概念
- 容器保存功能的工厂模式:
class BeanFactory {
private static Properties properties = new Properties();
// 存储一个map保存beans---相当于一个容器的概念:类比IOC容器
private static Map<String, Object> beans = new HashMap<>();
static {
InputStream ras = BeanFactory.class.getClassLoader().getResourceAsStream("bean1.properties");
try {
properties.load(ras);
for (String pro:properties.stringPropertyNames()) {
beans.put(pro, Class.forName(properties.getProperty(pro)).newInstance());
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
throw new ExceptionInInitializerError("初始化BeanFactory失败");
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
public static Object getBean(String name) {
return beans.getOrDefault(name, null);
}
}
此时,测试的结果,每个实例的地址都是一样的了:
bean1.CallService@75828a0f
bean1.CallService@75828a0f
bean1.CallService@75828a0f
bean1.CallService@75828a0f
bean1.CallService@75828a0f
- IOC容器
从上面的示例,我们引出了工厂模式+“容器”,实现单例对象的创建。
从而我们引出了IOC的概念:Inversion Of Controller,控制反转。
我们可以这么理解:当我们想要一个类的时候,可以new对象,也可以从一个BeanFactory中获取一个。而IOC呢,是将我们new的操作,交给了spring容器统一管理,也就是将控制权交给spring统一处理
意义:IOC容器的引入,一定程度上简化了我们对对象的操作,降低了耦合性
IOC包括:DI(依赖注入Dependency Injection) 和依赖查找Dependency Lookup,后续我们逐步分解
参考:
- IT黑马spring教程