一、重要的类和接口
1、IOC
(1)IOC 思想基于 IOC 容器完成,IOC 容器底层就是对象工厂
(2)Spring 提供 ioc 容器两种实现方式:– 两个接口
BeanFactory
:ioc 容器的基本实现,是 Spring 内部使用的接口,不提供给开发人员进行使用,加载配置文件时不会创建对象,在获取对象(使用)时才会创建对象(惰性加载)ApplicationContext
:该接口继承自BeanFactory
接口,提供更多更 强大的功能,一般由开发人员进行使用,加载配置文件时,就会创建配置文件中的对象。
2、BeanFactory
BeanFactory
,以Factory结尾,表示它是一个工厂类(接口), 它负责生产和管理bean的一个工厂。在Spring中,BeanFactory是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。BeanFactory只是个接口,并不是IOC容器的具体实现,但是Spring容器给出了很多种实现,如 DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等,其中XmlBeanFactory就是常用的一个,该实现将以XML方式描述组成应用的对象及对象间的依赖关系。XmlBeanFactory类将持有此XML配置元数据,并用它来构建一个完全可配置的系统或应用。
都是附加了某种功能的实现。 它为其他具体的IOC容器提供了最基本的规范,例如DefaultListableBeanFactory,XmlBeanFactory,ApplicationContext 等具体的容器都是实现了BeanFactory,再在其基础之上附加了其他的功能。
BeanFactory
和 ApplicationContext
就是spring框架的两个IOC容器,现在一般使用ApplicationnContext
,其不但包含了BeanFactory的作用,同时还进行更多的扩展。
BeanFacotry是spring中比较原始的Factory。如XMLBeanFactory就是一种典型的BeanFactory。
原始的BeanFactory无法支持spring的许多插件,如AOP功能、Web应用等。ApplicationContext接口,它由BeanFactory接口派生而来,
基本就是这些了,接着使用 getBean(String beanName)
方法就可以取得bean的实例;BeanFactory提供的方法及其简单,仅提供了六种方法供客户调用:
boolean containsBean(String beanName)
判断工厂中是否包含给定名称的bean定义,若有则返回trueObject getBean(String)
返回给定名称注册的bean实例。根据bean的配置情况,如果是singleton模式将返回一个共享实例,否则将返回一个新建的实例,如果没有找到指定bean,该方法可能会抛出异常Object getBean(String, Class)
返回以给定名称注册的bean实例,并转换为给定class类型Class getType(String name)
返回给定名称的bean的Class,如果没有找到指定的bean实例,则排除NoSuchBeanDefinitionException异常boolean isSingleton(String)
判断给定名称的bean定义是否为单例模式String[] getAliases(String name)
返回给定bean名称的所有别名
3、ApplicationContext
ApplicationContext
:是spring继BeanFactory
(间接继承自BeanFactory
)之外的另一个核心接口或容器(可理解为IOC),允许容器通过应用程序上下文环境创建、获取、管理bean。为应用程序提供配置的中央接口。在应用程序运行时这是只读的,但如果实现支持这一点,则可以重新加载。
public interface ApplicationContext
extends
EnvironmentCapable, // 继承环境对象容器接口
ListableBeanFactory, // 继承beanFactory
HierarchicalBeanFactory, // 继承beanFactory
MessageSource, // 集成消息解析器
ApplicationEventPublisher, // 继承应用事件发布器
ResourcePatternResolver // 继承模式资源解析器
{}
一个 ApplicationContext
提供:
访问应用程序组件的Bean工厂方法。从
org.springframework.beans.factory.ListableBeanFactory
继承。以通用方式加载文件资源的能力。继承自
org.springframe .core.io.ResourceLoader
接口。—beanXML向注册侦听器发布事件的能力。继承自
ApplicationEventPublisher
接口。解析消息的能力,支持国际化。继承自
MessageSource
接口。从父上下文继承。后代上下文中的定义总是优先级。例如,这意味着单个父上下文可以被整个web应用程序使用,而每个servlet都有自己独立于任何其他servlet的子上下文。
其接口主要子类(接口)包括:ConfigurableApplicationContext
、WebApplicationContext
(1)加载创建bean
ConfigurableApplicationContext
:该接口提供了根据配置创建、获取bean的一些方法,其中主要常用的实现包括:ClassPathXmlApplicationContext
、FileSystemXmlApplicationContext
等。提供了通过各种途径去加载实例化bean的手段。
ClassPathXmlApplicationContext
:它从XML文档获取配置,默认情况下,配置将取自“/WEB-INF/applicationContext”。自定义配置路径是在resource
目录下的。FileSystemXmlApplicationContext:
:路径为系统绝对路径
// 通过resource下的路径查找配置文件,并创建 ioc 容器,以及初始化配置文件中的bean到容器中
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
// 通过系统绝对路径查找配置文件,并创建 ioc 容器,以及初始化配置文件中的bean到容器中
//ApplicationContext applicationContext = new FileSystemXmlApplicationContext("G:\\bean.xml");
// 从容器中获取对象
PersonEntity person = applicationContext.getBean("personEntity",PersonEntity.class);
System.out.println(person);
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">
<bean id="personEntity" class="com.rewind.springtest.my_ioc.PersonEntity"></bean>
</beans>
下图是 ClassPathXmlApplicationContext 的继承关系
(2)WebApplicationContext
先说ServletContext
,javaee
标准规定了,servlet
容器需要在应用项目启动时,给应用项目初始化一个 ServletContext
作为公共环境容器存放公共信息。ServletContext
中的信息都是由容器提供的。
WebApplicationContext
是专门为web应用准备的,他允许从相对于web根目录的路劲中装载配置文件完成初始化工作,从WebApplicationContext
中可以获得ServletContext
的引用,整个Web应用上下文对象将作为属性放置在ServletContext
中,以便web应用可以访问spring上下文
spring中提供WebApplicationContextUtils
的getWebApplicationContext(ServletContext src)
方法来获得WebApplicationContext
对象
WebApplicationContext
扩展了 ApplicationContext
。在 WebApplicationContext
中定义了一个常量 ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
,在上下文启动时,
WebApplicationContext
以此为键放置在 ServletContext
属性列表中,
public static WebApplicationContext getWebApplicationContext(ServletContext sc) {
return getWebApplicationContext(sc, WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
}
ConfigurableWebApplicationContext
扩展了 WebApplicationContext
,它允许通过配置的方式实例化,同时设置两个重要方法
setServletContext(ServletContext context)
为spring设置web应用上下文,以便两者整合setConfigLocations(String[]locations)
设置Spring配置的文件地址
webApplicationContext初始化需要ServletContext,也就是说需要web容器前提下才能·完成启动工作 可以通过在web.xml中配置自启动Servlet或Web容器监听来实现web容器的启动
Spring分别提供启动WebApplicationContext的servlet和Web容器监听器
org.springframework.web.context.ContextLoaderListener
\org.springframework.web.context.ContexLoaderServlet 此方法目前以废弃**
(3)获取ApplicationContext
一、直接使用@Autowired注入
@Component
public class Book1 {
@Autowired
private ApplicationContext applicationContext;
public void show (){
System.out.println(applicationContext.getClass());
}
}
二、利用 spring4.3 的新特性
使用spring4.3新特性但是存在一定的局限性,必须满足以下两点:
- 构造函数只能有一个,如果有多个,就必须有一个无参数的构造函数,此时,spring会调用无参的构造函数
- 构造函数的参数,必须在spring容器中存在
@Component
public class Book2 {
private ApplicationContext applicationContext;
public Book2(ApplicationContext applicationContext){
System.out.println(applicationContext.getClass());
this.applicationContext=applicationContext;
}
public void show (){
System.out.println(applicationContext.getClass());
}
}
三、实现spring提供的接口 ApplicationContextAware
spring 在bean 初始化后会判断是不是ApplicationContextAware
的子类,调用setApplicationContext()
方法, 会将容器中ApplicationContext
传入进去
@Component
public class Book3 implements ApplicationContextAware {
private ApplicationContext applicationContext;
public void show (){
System.out.println(applicationContext.getClass());
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
4、FactoryBean
一般情况下,Spring通过反射机制利用<bean>
的class属性指定实现类实例化Bean,在某些情况下,实例化Bean过程比较复杂,如果按照传统的方式,则需要在<bean>
中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。Spring为此提供了一个org.springframework.bean.factory.FactoryBean
的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑。FactoryBean接口对于Spring框架来说占用重要的地位,Spring自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些复杂Bean的细节,给上层应用带来了便利。从Spring3.0开始,FactoryBean开始支持泛型,即接口声明改为FactoryBean<T>
的形式
FactoryBean
是一个接口,当在IOC容器中的Bean实现了 FactoryBean
后,不同于普通Bean的是:通过getBean(String BeanName)
获取到的Bean对象并不是FactoryBean
的实现类对象,而是这个实现类中的getObject()
方法返回的对象。要想获取FactoryBean
的实现类,就要getBean(&BeanName)
,在BeanName之前加上&。
BeanFactory和FactoryBean的区别
BeanFactory
是接口,提供了IOC容器最基本的形式,给具体的IOC容器的实现提供了规范,
FactoryBean也是接口,为IOC容器中Bean的实现提供了更加灵活的方式,FactoryBean
在IOC容器的基础上给Bean的实现加上了一个简单工厂模式和装饰模式(如果想了解装饰模式参考:修饰者模式(装饰者模式,Decoration) 我们可以在getObject()
方法中灵活配置。其实在Spring源码中有很多FactoryBean
的实现类.
区别:BeanFactory是个Factory,也就是IOC容器或对象工厂,FactoryBean是个Bean。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。但对FactoryBean而言,这个Bean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似
5、BeanDefinition
上面说了,Spring是个容器,里面的元素是bean,我们需要的时候直接从spring中获取。
那你会说,bean不就是某个类的对象或者实例么?对,但又不完全对!
这里要说到spring中的bean和普通Java类的实例的区别:
那就是spring中的bean,在Java类的基础上增加了很多概念属性,比如scope(作用域),isLazyInit(是否延迟初始化),isSingleton(是否单例)等属性特征。
也就是说,普通的Java类是不能完整描述上面的属性的,那Spring就通过BeanDefinition这个类来描述普通的Java类的属性以及额外的cope(作用域),isLazyInit(是否延迟初始化),isSingleton(是否单例)等属性特征。
spring就是根据BeanDefinition来实例化对应的bean。
这就是BeanDefinition的由来。
6、BeanDefinitionReader
上面说了BeanDefinition类是用来描述普通的Java类的属性以及额外的cope(作用域),isLazyInit(是否延迟初始化),isSingleton(是否单例)等属性特征。
那总要有个能从我们配置的bean的地方获取这些属性的类吧,这个类就是BeanDefinitionReader。BeanDefinitionReader会将配置的bean解析成为BeanDefinition。
Spring Bean的配置方式有很多种,如XML,properties,groovy,注解(可能通过properties,groovy的方式你不常用,但Spring确实支持这种方式),所以BeanDefinitionReader的实现类也很多
7、BeanDefinitionRegistry
BeanDefinitionReader将配置的bean解析成为BeanDefinition,需要将BeanDefinition保存到BeanDefinitionRegistry。类似工厂把原料保存到仓库中,登记一下,供后续生产产品使用。
8、BeanPostProcessor
BeanFactory根据BeanDefinition生成Bean的过程是一个标准化的流程,就像一个流水线一样,当然你可以在这个流水线上做一些自定义的操作。
在Spring中你可以通过实现BeanPostProcessor来干预Bean的生产过程,所以这个BeanPostProcessor很重要,比如AOP等都是利用这个进行实现的。
BeanPostProcessor 可以在bean的初始化前后进行自定义的处理。
9、BeanFactoryPostProcessor
Spring作为一个强大的容器,不仅能让你干预Bean的生产过程,还可以让你干预BeanFactory,例如你可以通过BeanFactoryPostProcessor将Bean的作用域都该成原型,默认是单例。
10、父 BeanFactory —— ParentBeanFactory
在 Spring 中可能存在多个 BeanFactory,多个 BeanFactory 可能存在 “父工厂” 与 “子工厂” 的关系。最常见的例子就是:Spring MVC 的 BeanFactory 和 Spring 的 BeanFactory,通常情况下,Spring 的 BeanFactory 是 “父工厂”,Spring MVC 的 BeanFactory 是 “子工厂”。
在 Spring 中,子工厂可以使用父工厂的 BeanDefinition,因而,如果在当前 BeanFactory 中找不到,而又存在父工厂,则会去父工厂中查找。