Spring组件解析


一、重要的类和接口

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,再在其基础之上附加了其他的功能。

BeanFactoryApplicationContext 就是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定义,若有则返回true
  • Object 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的子上下文。

其接口主要子类(接口)包括:ConfigurableApplicationContextWebApplicationContext

(1)加载创建bean

ConfigurableApplicationContext:该接口提供了根据配置创建、获取bean的一些方法,其中主要常用的实现包括:ClassPathXmlApplicationContextFileSystemXmlApplicationContext等。提供了通过各种途径去加载实例化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 的继承关系

image-20211219161333474

(2)WebApplicationContext

先说ServletContextjavaee 标准规定了,servlet 容器需要在应用项目启动时,给应用项目初始化一个 ServletContext 作为公共环境容器存放公共信息。ServletContext 中的信息都是由容器提供的。

WebApplicationContext 是专门为web应用准备的,他允许从相对于web根目录的路劲中装载配置文件完成初始化工作,从WebApplicationContext中可以获得ServletContext的引用,整个Web应用上下文对象将作为属性放置在ServletContext中,以便web应用可以访问spring上下文

spring中提供WebApplicationContextUtilsgetWebApplicationContext(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 中找不到,而又存在父工厂,则会去父工厂中查找。


  目录