目录
3.Spring Framework中的IoC/DI
4.IoC的具体实现框架有哪些
5.IoC/DI的优缺点
6. IoC/DI在项目中具体应用场景
四、BeanFactory和ApplicationContext
五、第一个Spring Framework 案例
既然要学习一下Spring Framework中对IoC/DI原则的实现,我们无论怎么说都没有官方文档权威。
Spring Framework 官方文档对IoC的解释如下,网址: https://docs.spring.io/spring-framework/doc s/current/reference/html/core.html#spring-core
1、从Spring Framework官方文档对IoC 容器的解释上可以看出来,如下几点:
2、强调IoC也叫做DI。(IoC is also known as dependency injection(DI))
3、官方为了防止IoC 和 IoC Container 名称混淆。更多以DI作为第一名称。而容器叫做IoC Container(IoC容器)
4、强调IoC绝对不是由IoC容器实例化对象这一点,而是一个过程(process)。从IoC 容器实例化对象, 一直到在IoC容器内部注入对象依赖的其他对象的过程。
5、IoC容器实例化对象时有两种方式:通过构造方法和通过工厂设计模式。
6、Spring中使用BeanFactory和ApplicationContext作为IoC容器的接口类型。ApplicationContext是 BeanFactory的子接口,功能更加强大。
7、IoC容器内部管理的所有对象统称beans,其中单个对象叫做bean。
下图是官方对DI的解释,网址: https://docs.spring.io/spring-framework/docs/current/reference/ht ml/core.html#beans-factory-collaborators
从Spring Framework官方文档对DI的解释上可以看出来,如下几点:
1、强调DI也叫做IoC(hence the name,Inversion of Control)。
2、DI是一个过程(process),绝对不是把对象注入到另外一个对象就是DI。其解释和IoC一样,是从 实例化对象,到把对象注入到另外对象的过程就是DI。
3、使用DI可以实现对象解耦,让代码更加清晰。不再需要管理自己所依赖的对象,也不需要知道依赖项 的位置和类型。(第二大段英文)
4、DI有两种实现方式:构造注入(Constructor-based dependency injection)和设值注入(Setter-based dependency injection)
Java 体系对IoC做具体实现的框架:
轻量级:Spring Framework 、Guice、 Pico Container、 Avalon、 HiveMind
重量级:EJB
.Net 体现对IoC做具体实现的框架:
Spring.net、 Autofac 、Castle Windsor 、Unity
上面这些内容有一些可能十年老Java程序员都没有听说过。对于小伙伴们,我们只要掌握好Java领域, 使用最多的IoC实现框架,Spring Framework就可以了。
优点:
1、解耦。对象的实例化、组装、管理完全交给IoC容器。实现对象之间的解耦。
2、适合中大型项目。对于复杂的项目,里面对象关系可能比较复杂,IoC 容器可以很好的管理这 些对象。
缺点:
1、对象交给容器实例化和注入的过程都是反射(reflect)。反射相对硬编码实例化有一定性能损 耗。好在在一些需要频繁实例化的场景中,Spring Framework可以借助单例设计模式来减少 bean实例化的次数。
2、不适合微、小型项目。为了对象解耦,在对象关系不复杂的情况下,额外需要大量的XML配置 或注解,增加了工作量。
IoC/DI 主要作用就是管理对象的实例化和对象之间依赖关系。项目中以前需要自己实例化的层对象、需 要自己实例化框架或工具包的入口类都可以交给Spring 容器进行管理。
1、层对象:Java项目都是分层开发。通过IoC容器管理所有层对象,可以在其他被IoC容器管理的对象 随时随地的注入这些层对象。例如:PeopleMapper 接口代理对象、PeopleDaoImpl、 PeopleServiceImpl
2、整合其他技术:可以通过IoC容器管理其他技术的入类。在启动IoC容器时,管理Bean。如: MyBatis中的SqlSessionFactory和SqlSession等
下图中对应普通类PeopleMapper、PeopleServiceImpl这些不同层中普通都可以交给Spring容器进行管 理。放入到容器中的对象可以相互直接依赖。但是Servlet只能被Tomcat管理(由Tomcat帮助实例化创 建的),所以Spring容器是无法管理Servlet的。但是Servlet可以从Spring容器中取出对象。
IoC/DI 实现过程非常重要的一块就是IoC Container。必须创建出IoC容器,才能继续做后面的事情。 在Spring框架中IoC Container的类型是BeanFactory和ApplicationContext。所以必须先搞懂这两个东西是什么,然后才能去写第一个Spring框架案例。否则即使照着视频写出来了,也是照葫芦画瓢。 在上面学习IoC/DI时,就看到官方在介绍IoC时直接介绍了BeanFactory和ApplicationContext的区别。
网址: https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-int roduction
整理一下:
1. BeanFactory是Spring框架中IoC容器的顶级接口。里面提供了IoC容器的最核心功能。
2. ApplicationContext是BeanFactory的子接口,ApplicationContext具备BeanFactory的所有功 能。
3. ApplicationContext比BeanFactory多的功能
* AOP 功能
* 国际化(MessageSource)
* 访问资源,如URL和文件(ResourceLoader)
* 消息发送机制(ApplicationEventPublisher)
* Spring集成Web时功能。
除上述文档直接给出的两者区别外,使用BeanFactory时,默认所有的bean都是获取时才会被实例化。 而使用ApplicationContext时IoC 容器启动就会立即实例化所有bean。 这时有的小伙伴可能有点迷惑了,那到底用哪个接口作为IoC容器类型呢?其实这个问题官方已经给出明 确的解释了。
网址: https://docs.spring.io/spring-framework/docs/current/reference/html/core.ht ml#context-introduction-ctx-vs-beanfactory
官方已经明确说明了,推荐使用ApplicationContext,所以我们后面都是用ApplicationContext或其子 接口。 虽然不推荐使用BeanFactory,但是我们可以看看BeanFactory接口里面到底有哪些方法。
从上图看到,BeanFactory里面主要功能就是获取容器中的Bean。获取时可以按照类型获取,也可以按 照名称获取,还支持泛型,可以控制获取后Bean的类型。所以BeanFactory只提供了IoC容器的最基本 功能。即:IoC/DI功能。
BeanFactory的层次结构(Hierarchy)中相关接口和实现类比较多
所以我用一张更加清晰的图来表示下这两个接口及常用的实现类。
可以看出来,ApplicationContext要比BeanFactory多继承了6个父接口。这六个父接口就是 ApplicationContext比BeanFactory多出的功能。虽然现在看不太懂这6个接口是什么意思,也不用着 急,等学到后面再回头来看就可以了,现在只需要知道ApplicationContext比BeanFactory功能更加强大就可以了。
最后来看看ClassPathXmlApplicationContext。因为ApplicationContext是接口,是无法实例化。只能实例化这个实现类。想要实例化类,就需要调用类的构造方法。下图被选中具有一个String类型参数的 构造方法就是我们常用的,参数是Spring框架配置文件路径。
然后就可以通过从BeanFactory继承过来的getBean获取到容器中的Bean对象了。
所以,想要在Spring框架中创建IoC容器,并从容器中获取到Bean,代码也比较简单
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
People peo = applicationContext.getBean("peo", People.class);
System.out.println(peo);
最后附上BeanFactory容器创建的方式。
Spring 3.1之前BeanFactory实例化是通过XmlBeanFactory,但是XmlBeanFactory在目前的Spring Framework 6已经不存在。
FileSystemResource fsr = new
FileSystemResource("D:\\idea\\idea2022ws\\summer\\src\\main\\resources\\applicat
ionContext.xml");
XmlBeanFactory xmlBeanFactory = new XmlBeanFactory(fsr);
People peo = xmlBeanFactory.getBean("peo",People.class);
System.out.println(peo);
从Spring 3.1 版本开始,使用DefaultListableBeanFactory和XMLBeanDefinitionReader替代了上面写法。
DefaultListableBeanFactory defaultListableBeanFactory = new
DefaultListableBeanFactory();
XmlBeanDefinitionReader xmlBeanDefinitionReader = new
XmlBeanDefinitionReader(defaultListableBeanFactory);
xmlBeanDefinitionReader.loadBeanDefinitions(new
FileSystemResource("D:\\idea\\idea2022ws\\summer\\src\\main\\resources\\applicat
ionContext.xml"));
People peo = defaultListableBeanFactory.getBean("peo", People.class);
System.out.println(peo);
任何框架从建立项目到测试结果都分为下面5个步骤,这5个步骤属于公式。避免写代码没有思路。
Spring框架不依赖于Servlet容器(Tomcat),所以使用非模板的普通Maven项目就可以了。 Spring框架提供了XML、注解、Java Config三种方式进行项目配置。首先我们从XML方式开始学习。
1.创建项目,并添加依赖
创建普通Maven项目,并命名为summer(既然Spring框架叫春天,我们就叫夏天)
在项目的pom.xml中添加Spring项目的最基本依赖。
Spring项目想要运行起来必须包含:
1、spring-context.jar。spring上下文依赖,它依赖了下面的四个jar。
2、spring-core.jar。Spring 核心jar包。它依赖了spring-jcl.jar
3、spring-aop.jar。Spring AOP基本支持。(不是必须的)
4、spring-expression.jar。Spring的表达式语言支持。
5、spring-beans.jar。Spring容器的bean管理。
6、spring-jcl.jar。Spring 4版本时是common-logging.jar。从5开始Spring自己对日志进行了封装。
所以在Maven中想要使用Spring框架只需要在项目中导入spring-context就可以了,其他的jar包根据 Maven依赖传递性都可以导入进来。 在文档制作时Spring框架最新版本为6.0.6。所以下面依赖导入最新的6.0.6版本。 spring-context坐标可以去 https://mvnrepository.com/ 中搜索 spring-context
org.springframework
spring-context
6.0.6
在项目的pom.xml中添加完依赖后,需要手动更新下:
关于Spring框架版本号说明: 从Spring框架5.3.0 开始,Spring 所有子模块版本号中不再以.RELEASE结尾。 例如:之前是5.2.22.RELEASE 例如:现在是6.0.6
2.随意创建一个类
在项目下创建一个类作为测试Spring IoC/DI功能的类。
示例中叫做com.tong.pojo.People
public class People {
private int id;
private String name;
// 没有粘贴getter/setter、toString、无参构造方法、全参构造方法
}
3.创建Spring配置文件
在src/main/resources下鼠标右键-> New -> XML Configuration File -> Spring Config。 一定要注意:只有正确的添加spring-context依赖,才会有这项。
小提示: 文件名称没有强制要求。官方示例中配置文件名称叫做applicationContext.xml,所以我们也把 Spring配置文件叫做applicationContext.xml
3.1 创建Spring Config后提示项目没有这个配置文件,解决办法
当文件创建完成后在上面提示“Application context not configured for this file” 。其实这个问题不影响 程序的运行。但是如果小伙伴们非得纠结这个问题,我们也可以解决这个问题。
第一种方式:手动更改项目配置(Reload 后失效)
选择IDEA 菜单 File -> Project Structure...
按照图示,添加配置文件。 Modules -> 项目名(summer)下的Spring -> 点击 +
把配置文件勾选上后,先点Apply,再点击OK按钮
然后去修改applicationContext.xml内容,发现上面警告信息没有了。
第二种方式:快捷方式(Reload 后失效)
直接点击提示信息:Configure application context -> Create new application context
弹出框和上面手动配置时,添加配置文件的弹出框一样。只是这里自动就把配置文件选上了。直接点击 下面OK按钮就可以了。
第三种方式:创建配置文件模板(Reload 后失效)
如果不想要创建文件后有警告信息,也可以创建配置文件模板
(1)把XML文件的文档头和 标签复制。不要里面的标签
(2)点击IDEA菜单中第一个 File -> Settings...
(3)按图填写模板
Name:是模板名。以后通过这个名称来找到模板内容。
Extension:文件扩展名。创建文件时可以以.xml结尾,如果没有.xml结尾,IDEA会帮助添加上。
彻底解决方案(reload后依然生效)
直接点击警告信息,右侧的小螺丝图标,在弹出框中点击第一个“Edit inspection profile setting”
在弹出框中,取消"Incorrect XML application context"勾选,然后点击OK。这时无论是修改XML文件 内容。还是Reload项目,都不在弹出警告信息
因为没有警告信息了,所以无法再次点击警告的螺丝图标。 想要找到上图界面,需要通过:IDEA菜单 File -> Editor -> Inspections -> Spring -> Spring Core -> Setup找到
4.创建测试类
创建测试类,测试Spring功能。
package com.tong.test;
import com.tong.pojo.People;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
// IoC: 对象实例化和给对象注入依赖内容的过程都交给IoC容器完成的过程。
// 拆分讲解:先讲解如果让IoC容器对类实例化。
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
/*
getBean():
第一个参数:IoC容器中Bean的ID
第二个参数:返回值类型。没有第二个参数返回值为Object类型
*/
People peo = ac.getBean("peo", People.class);
System.out.println(peo);
}
}
5.观察结果
发现People对象可以成功创建,但是对象中的所有属性没有赋值