传统实例化对象存在的为题:传统开发可以使用new对父接口进行实例化,这样就造成了代码的极大耦合性,为了解决这种耦合性,可以引入工厂设计模式,来负责创建子类对象,这样,工厂类帮助开发者隐藏了所有实现子类,但是静态工厂类不能为所有的接口服务,而且每增加一个子类就要修改工厂类,这样太麻烦,可以采用反射机制的动态工厂类来解决,但是动态工厂类还是需要知道对象的类型才可以,而且需要考虑到多线程的问题。
对于以上开发存在的问题,Spring采用IOC&DI来实现
Spring开发需要引入下列依赖包:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
IOC指的是控制反转,将对象的管理交给Spring进行管理:“控制”就是指对 对象的创建、维护、销毁等生命周期的控制,这个过程一般是由我们的程序去主动控制的,如使用new关键字去创建一个对象(创建),在使用过程中保持引用(维护),在失去全部引用后由GC去回收对象(销毁)。
“反转”就是指对 对象的创建、维护、销毁等生命周期的控制由程序控制改为由IOC容器控制,需要某个对象时就直接通过名字去IOC容器中获取。
在src/main/resources/spring目录下创建Bean配置文件spring-base.xml,并且打开命名空间,里面定义所有的Bean,交由Spring管理:<bean id="messageImpl(别名)" class="cn.lt.service.MessageImpl(子类)"/>
对<bean>元素的解释:1、每个Bean可以有一个id属性,并可以根据该id在IoC容器中查找该Bean,该id属性值必须在IoC容器中唯一,一般以对象类首字母小写来定义;
2、用来表示类的全名,通常为package.classname;
在Spring中所有的容器都由ApplicationContext接口来描述(子类ClassPathXmlApplicationContext是spring读取xml最常用的类。而我们一般操作的是她的接口ApplicationContext。),
ApplicationContext context = new ClassPathXmlApplicationContext("spring/spring-base.xml") ;
//Spring加载源文件夹目录下的.xml文件
Message msg = context.getBean("messageImpl",IMessage.class) ;
//通过getBean("id",接口.class)方法从ApplicationContext容器中获取装配好的Bean实例以供使用。
Spring测试:
需要引入的依赖库:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.7.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-annotations-api</artifactId>
<version>9.0.8</version>
</dependency>
引入测试依赖库后,就不需要使用ApplicationContext中的getBean()方法来获得bean对象了,而是使用ContextConfiguration(locations = {"classpath:spring/spring-base.xml"})来加载配置文件并装载实例。并且使用@Resource注解进行接口对象注入,替代了getBean()方法;
【问题】ClassPathXmlApplicationContext("spring/spring-base.xml") 最后是被什么替代的
【面试题】ApplicationContext容器和BeanFactory容器有什么联系和区别?
BeanFacotry是spring中比较原始的Factory。如XMLBeanFactory就是一种典型的BeanFactory。原始的BeanFactory无法支持spring的许多插件,如AOP功能、Web应用等
ApplicationContext接口,它由BeanFactory接口派生而来,因而提供BeanFactory所有的功能。还具有:
• MessageSource, 提供国际化的消息访问
• 资源访问,如URL和文件
• 事件传播
• 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层
1.利用MessageSource进行国际化
BeanFactory是不支持国际化功能的,因为BeanFactory没有扩展Spring中MessageResource接口。相反,由于ApplicationContext扩展了MessageResource接口,因而具有消息处理的能力(i18N),具体spring如何使用国际化,以后章节会详细描述
2.强大的事件机制(Event)
基本上牵涉到事件(Event)方面的设计,就离不开观察者模式。不明白观察者模式的朋友,最好上网了解下。因为,这种模式在java开发中是比较常用的,又是比较重要的。
ApplicationContext的事件机制主要通过ApplicationEvent和ApplicationListener这两个接口来提供的,和java swing中的事件机制一样。即当ApplicationContext中发布一个事件的时,所有扩展了ApplicationListener的Bean都将会接受到这个事件,并进行相应的处理
3.底层资源的访问
ApplicationContext扩展了ResourceLoader(资源加载器)接口,从而可以用来加载多个Resource,而BeanFactory是没有扩展ResourceLoader
4.对Web应用的支持
与BeanFactory通常以编程的方式被创建不同的是,ApplicationContext能以声明的方式创建,如使用ContextLoader。
ContextLoader有两个实现:ContextLoaderListener和ContextLoaderServlet。它们两个有着同样的功能。
5.其它区别
BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化,这样,我们就不能发现一些存在的Spring的配置问题。而ApplicationContext则相反,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误
【备注】耦合性:也称块间联系。指软件系统结构中各模块间相互联系紧密程度的一种度量。模块之间联系越紧密,其耦合性就越强,模块的独立性则越差。模块间耦合高低取决于模块间接口的复杂性、调用的方式及传递的信息
ApplicationContext是BeanFactory的子类,与BeanFactory不同的是,ApplicationContext容器实例化后会自动对所有的单实例Bean进行实例化与依赖关系的装配,使之处于待用状态。而BeanFactory容器实例化后并不会自动实例化Bean,只有当Bean被使用时BeanFactory容器才会对该Bean进行实例化与依赖关系的装配
ApplicationContext有四个常用子类:1.ClassPathXmlApplicationContext(从类路径ClassPath中寻找指定的XML配置文件,找到并装载完成ApplicationContext的实例化工作)、2.FileSystemXmlApplicationContext(从指定的文件系统路径中寻找指定的XML配置文件,找到并装载完成ApplicationContext的实例化工作)、3.XmlWebApplicationContext(从Web应用中寻找指定的XML配置文件,找到并装载完成ApplicationContext的实例化工作)。