一、简介
概念:控制反转是一种通过描述(在 Java 中可以是 XML 或者注解)并通过第三方(Spring)去产生或获取特定对象的方式。(被动创建)
优势:
① 降低对象之间的耦合
② 我们不需要理解一个类的具体实现,只需要知道它有什么用就好了(直接向 IoC 容器拿)
小结:主动创建的模式中,责任归于开发者,而在被动的模式下,责任归于 IoC 容器,基于这样的被动形式,我们就说对象被控制反转了。(也可以说是反转了控制)
二、IOC容器
Spring 会提供IoC 容器来管理和容纳我们所开发的各种各样的 Bean,并且我们可以从中获取各种发布在 Spring IoC 容器里的 Bean,并且通过描述可以得到它。
三、容器设计
主要基于BeanFactory和ApplicationContext 两个接口。
BeanFactory 是 Spring IoC 容器所定义的最底层接口,而 ApplicationContext 是其最高级接口之一,并对 BeanFactory 功能做了许多的扩展,所以在绝大部分的工作场景下,都会使用 ApplicationContext 作为 Spring IoC 容器。
ApplicationContext的常用扩展类:
ClassPathXmlApplicationContext:从类路径下加载配置文件
FileSystemXmlApplication:从硬盘的绝对路径下加载配置文件
BeanFactory
常用方法
【getBean】对应了多个方法来获取配置给 Spring IoC 容器的 Bean。
① 按照类型拿 bean:
bean = (Bean) factory.getBean(Bean.class);
PS:要求在 Spring 中只配置了一个这种类型的实例,否则报错。(如果有多个那 Spring 就懵了,不知道该获取哪一个)
② 按照 bean 的名字拿 bean:
bean = (Bean) factory.getBean("beanName");
PS:这种方法不太安全,IDE 不会检查其安全性(关联性)
③ 按照名字和类型拿 bean:(推荐)
bean = (Bean) factory.getBean("beanName", Bean.class);
【isSingleton】用于判断是否单例,如果判断为真,其意思是该 Bean 在容器中是作为一个唯一单例存在的。
【isPrototype】则相反,如果判断为真,意思是当你从容器中获取 Bean,容器就为你生成一个新的实例。
PS:在默认情况下,【isSingleton】为 ture,而【isPrototype】为 false
【getAliases】方法是获取别名的方法
ApplicationContext
1、先在【src】目录下创建一个 【bean.xml】 文件:
<?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>
PS:这里定义了一个 bean ,这样 Spring IoC 容器在初始化的时候就能找到它们,然后使用 ClassPathXmlApplicationContext 容器就可以将其初始化
2、使用 ClassPathXmlApplicationContext 容器将其初始化:
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());
四、ApplicationContext的常见实现类
ClassPathXmlApplicationCntext
读取classpath中的资源
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
FileSystemXmlApplicationContext
读取指定路径的资源
ApplicationContext ac = new FileSystemXmlApplicationContext("c:/applicationContext.xml");
XmlWebApplicationContext
需要在Web的环境下才可以运行
XmlWebApplicationContext ac = new XmlWebApplicationContext(); // 这时并没有初始化容器 ac.setServletContext(servletContext); // 需要指定ServletContext对象 ac.setConfigLocation("/WEB-INF/applicationContext.xml"); // 指定配置文件路径,开头的斜线表示Web应用的根目录 ac.refresh(); // 初始化容器
五、IOC初始化、注入的实现原理
Bean的定义
1、资源定位
Spring IoC 容器先根据开发者的配置,进行资源的定位,在 Spring 的开发中,通过 XML 或者注解都是十分常见的方式,定位的内容是由开发者提供的。
2、获取Bean
这个时候只是将定位到的资源信息,保存到 Bean 定义(BeanDefinition)中,此时并不会创建 Bean 的实例。
3、注册Bean到IOC容器中
将定义好的Bean的信息发布到 Spring IoC 容器中
PS:做完了以上 3 步,Bean 就在 Spring IoC 容器中被定义了,但是没有被初始化,更没有完成依赖注入,此时它还不能完全使用。
Bean的初始化和注入
Spring IoC 默认会自动初始化 Bean。
Spring Bean 还有一个配置选项——【lazy-init】,其含义就是是否初始化 Spring Bean。
如果将其设置为 true,那么只有当我们使用 Spring IoC 容器的 getBean 方法获取它时,它才会进行 Bean 的初始化,完成依赖注入。