控制反转显然是一个抽象的概念,咱们举一个鲜明的例子来讲明。java
在现实生活中,人们要用到同样东西的时候,第一反应就是去找到这件东西,好比想喝新鲜橙汁,在没有饮品店的日子里,最直观的作法就是:买果汁机、买橙子,而后准备开水。值得注意的是:这些都是你本身**“主动”创造**的过程,也就是说一杯橙汁须要你本身创造。git
然而到了今时今日,因为饮品店的盛行,当咱们想喝橙汁时,第一想法就转换成了找到饮品店的联系方式,经过电话等渠道描述你的须要、地址、联系方式等,下订单等待,过一下子就会有人送来橙汁了。github
请注意你并无“主动”去创造橙汁,橙汁是由饮品店创造的,而不是你,然而也彻底达到了你的要求,甚至比你创造的要好上那么一些。web
这就是一种控制反转的理念,上述的例子已经很好的说明了问题,咱们再来描述一下控制反转的概念:控制反转是一种经过描述(在 Java 中能够是 XML 或者注解)并经过第三方(Spring)去产生或获取特定对象的方式。spring
主动建立的模式中,责任归于开发者,而在被动的模式下,责任归于 IoC 容器,基于这样的被动形式,咱们就说对象被控制反转了。(也能够说是反转了控制)安全
Spring 会提供 IoC 容器来管理和容纳咱们所开发的各类各样的 Bean,而且咱们能够从中获取各类发布在 Spring IoC 容器里的 Bean,而且经过描述能够获得它。微信
Spring IoC 容器的设计主要是基于如下两个接口:app
其中 ApplicationContext 是 BeanFactory 的子接口之一,换句话说:BeanFactory 是 Spring IoC 容器所定义的最底层接口,而 ApplicationContext 是其最高级接口之一,并对 BeanFactory 功能作了许多的扩展,因此在绝大部分的工做场景下,都会使用 ApplicationContext 做为 Spring IoC 容器。框架
从上图中咱们能够几乎看到, BeanFactory 位于设计的最底层,它提供了 Spring IoC 最底层的设计,为此,咱们先来看看该类中提供了哪些方法:函数
因为这个接口的重要性,因此有必要在这里做一下简短的说明:
bean = (Bean) factory.getBean(Bean.class);
**注意:**要求在 Spring 中只配置了一个这种类型的实例,不然报错。(若是有多个那 Spring 就懵了,不知道该获取哪个) ② 按照 bean 的名字拿 bean: bean = (Bean) factory.getBean("beanName");
注意:这种方法不太安全,IDE 不会检查其安全性(关联性) ③ 按照名字和类型拿 bean:(推荐) bean = (Bean) factory.getBean("beanName", Bean.class);
这就是 Spring IoC 最底层的设计,全部关于 Spring IoC 的容器将会遵照它所定义的方法。
根据 ApplicationContext 的类继承关系图,能够看到 ApplicationContext 接口扩展了许许多多的接口,所以它的功能十分强大,因此在实际应用中经常会使用到的是 ApplicationContext 接口,由于 BeanFactory 的方法和功能较少,而 ApplicationContext 的方法和功能较多。
经过上一篇 IoC 的例子,咱们来认识一个 ApplicationContext 的子类——ClassPathXmlApplicationContext。
<?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"> <!-- 经过 xml 方式装配 bean --> <bean name="source" class="pojo.Source"> <property name="fruit" value="橙子"/> <property name="sugar" value="多糖"/> <property name="size" value="超大杯"/> </bean> </beans>
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); Source source = (Source) context.getBean("source", Source.class); System.out.println(source.getFruit()); System.out.println(source.getSugar()); System.out.println(source.getSize());
这样就会使用 Application 的实现类 ClassPathXmlApplicationContext 去初始化 Spring IoC 容器,而后开发者就能够经过 IoC 容器来获取资源了啦!
关于 Spring Bean 的装配以及一些细节,会在下一篇文章中讲到
1.ClassPathXmlApplicationContext: 读取classpath中的资源
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
2:FileSystemXmlApplicationContext:- 读取指定路径的资源
ApplicationContext ac = new FileSystemXmlApplicationContext("c:/applicationContext.xml");
3.XmlWebApplicationContext: 须要在Web的环境下才能够运行
XmlWebApplicationContext ac = new XmlWebApplicationContext(); // 这时并无初始化容器 ac.setServletContext(servletContext); // 须要指定ServletContext对象 ac.setConfigLocation("/WEB-INF/applicationContext.xml"); // 指定配置文件路径,开头的斜线表示Web应用的根目录 ac.refresh(); // 初始化容器
虽然 Spring IoC 容器的生成十分的复杂,可是大致了解一下 Spring IoC 初始化的过程仍是必要的。这对于理解 Spring 的一系列行为是颇有帮助的。
**注意:**Bean 的定义和初始化在 Spring IoC 容器是两大步骤,它是先定义,而后初始化和依赖注入的。
作完了以上 3 步,Bean 就在 Spring IoC 容器中被定义了,而没有被初始化,更没有完成依赖注入,也就是没有注入其配置的资源给 Bean,那么它还不能彻底使用。
对于初始化和依赖注入,Spring Bean 还有一个配置选项——【lazy-init】,其含义就是是否初始化 Spring Bean。在没有任何配置的状况下,它的默认值为 default,实际值为 false,也就是 Spring IoC 默认会自动初始化 Bean。若是将其设置为 true,那么只有当咱们使用 Spring IoC 容器的 getBean 方法获取它时,它才会进行 Bean 的初始化,完成依赖注入。
最后咱们简单说说IoC是如何实现的。想象一下若是咱们本身来实现这个依赖注入的功能,咱们怎么来作? 无外乎:
咱们发现其实本身来实现也不是很难,Spring实际也就是这么作的。这么看的话其实IoC就是一个工厂模式的升级版!固然要作一个成熟的IoC框架,仍是很是多细致的工做要作,Spring不只提供了一个已经成为业界标准的Java IoC框架,还提供了更多强大的功能,因此你们就别去造轮子啦!但愿了解IoC更多实现细节不妨经过学习Spring的源码来加深理解!
引用地址:这里 【参考资料】:《Java EE 互联网轻量级框架整合开发》、《Spring 实战(第四版)》 【好文推荐】:①Spring 的本质系列(1) -- 依赖注入、 ②Spring的IoC原理
欢迎转载,转载请注明出处! 简书ID:@我没有三颗心脏 github:wmyskxz 欢迎关注公众微信号:wmyskxz_javaweb 分享本身的Java Web学习之路以及各类Java学习资料