IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Spring Ioc 容器的设计 -> 正文阅读

[Java知识库]Spring Ioc 容器的设计

1.Spring IOC容器的设计

  • 实现BeanFactory接口的简单容器
  • 实现ApplicationContext接口的高级容器

在这里插入图片描述
ApplicationContext是BeanFactory的子接口。BeanFactory是Spring IoC容器的最底层接口, 只提供了IOC容器的基本功能, 给具体的IOC 容器的实现提供了规范, 主要负责配置, 生产和管理Bean。内部定义了对单个bean的获取,对bean的作用域判断,获取bean类型,获取bean别名等功能。

而ApplicationContext继承了MessageSource、ListableBeanFactory、ResourceLoader、ApplicationEventPublisher等接口。是高级的BeanFactory。高级容器

上面两个重要的类都是接口,既然是接口那总得有具体的实现类。DefaultListableBeanFactory. 实现了包含所有Spring IOC 容器的基本功能。真正可以作为一个可以独立使用的IOC容器还是DefaultListableBeanFactory, 而不是BeanFactory。所有DefaultListenerBeanFactory是Ioc容器的始祖。

2.BeanFactory和ApplicationContext的区别

BeanFactory和ApplicationContext是Spring IOC容器的两大核心接口。ApplicationContext是BeanFactory的子接口。

①、提供的功能不同:

BeanFactory提供了Bean的定义,读取bean配置文档,管理bean的加载、实例化,控制bean的生命周期,维护bean之间的依赖关系等。

public interface ApplicationContext extends 
                            EnvironmentCapable,
                            ListableBeanFactory,
                            HierarchicalBeanFactory,
                            MessageSource,
                            ApplicationEventPublisher,
                            ResourcePatternResolver {

}
  • 支持国际化(MessageSource)
  • 统一的资源文件访问方式(ResourcePatternResolver)
  • 提供在监听器中注册bean的事件(ApplicationEventPublisher)
  • 同时加载多个配置文件
  • 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层(HierarchicalBeanFactory)

②、 启动时的状态不同:

BeanFactroy采用的是延迟加载形式来注入Bean的,使用的时候对Bean实例化, 不存在Spring的配置问题, 如果一个Bean的属性未注入, BeanFactory加载后, 直到第一次调用getBean()的时候才会抛出异常。

ApplicationContext:启动的时候, 创所有的Bean, 这样, 容器启动的时候, 发现配置错误的话, 有利于检查依赖是否注入。相对于基本的BeanFactory,ApplicationContext 唯一的不足是占用内存空间。当应用程序配置Bean较多时,程序启动较慢。

③、BeanFactory通常以编程的方式被创建,ApplicationContext还能以声明的方式创建,如使用ContextLoader。

④、BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册。

3.BeanFactory容器的设计原理

在这里插入图片描述

  • HierarchicalBeanFactory:提供父容器的访问功能,它内部定义了两个方法。
  • ListableBeanFactory:提供了列出工厂中所有的Bean的方法 定义了容器内Bean的枚举功能(枚举出来的Bean不会包含父容器)。
  • AutowireCapableBeanFactory:在BeanFactory基础上实现对已存在实例的管理,主要定义了集成其它框架的功能。一般应用开发者不会使用这个接口,所以像ApplicationContext这样的外观实现类不会实现这个接口,如果真想用可以通过ApplicationContext的getAutowireCapableBeanFactory接口获取。
  • ConfigurableBeanFactory:定义了BeanFactory的配置功能。
  • ConfigurableListableBeanFactory:继承了上述的所有接口,增加了其他功能:比如类加载器、类型转化、属性编。
  • BeanPostProcessor、作用域、bean定义、处理bean依赖关系、bean如何销毁等功能。
  • DefaultListableBeanFactory:实现上述BeanFactory接口中所有功能。它还可以注册BeanDefinition。
  • XmlBeanFactory :在Spring3.1之前使用,后面被标记为Deprecated,继承自DefaultListableBeanFactory,增加了对Xml文件解析的支持。

XmlBeanFactory是BeanFactory体系中的最底层的实现类。XmlBeanFactory在父类的基础上增加了对XML文件解析的支持,也就是说它是一个可以读取XML文件方式定义BeanDefinition的IOC容器。

BeanDefination: 它是对 IOC容器中管理的对象依赖关系的数据抽象。控制反转功能都是围绕对这个BeanDefinition的处理来完成的。
BeanDefinition在Spring中是用来描述Bean对象的,它本身并不是一个Bean实例,而是包含了Bean实例的所有信息,比如类名、属性值、构造器参数、scope、依赖的bean、是否是单例类、是否是懒加载以及其它信息。其实就是将Bean实例定义的信息存储到这个BeanDefinition相应的属性中,后面Bean对象的创建是根据BeanDefinition中描述的信息来创建的,例如拿到这个BeanDefinition后,可以根据里面的类名、构造函数、构造函数参数,使用反射进行对象创建。也就是说 IOC容器可以有多个BeanDefinition,并且一个BeanDefinition对象对应一个标签中的信息。
当然BeanDefinition的最终目的不只是用来存储Bean实例的所有信息,而是为了可以方便的进行修改属性值和其他元信息,比如通过BeanFactoryPostProcessor进行修改一些信息,然后在创建Bean对象的时候就可以结合原始信息和修改后的信息创建对象了。

XmlBeanFactory:

@Deprecated
public class XmlBeanFactory extends DefaultListableBeanFactory {

    private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
    
    public XmlBeanFactory(Resource resource) throws BeansException {
        this(resource, null);
    }   
    public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
        super(parentBeanFactory);
        this.reader.loadBeanDefinitions(resource);
    }
}

初始化了一个 XmlBeanDefinitionReader对象, 目的是读取xml文件, 将Bean的xml配置文件转化为多个BeanDefinition工具类, 一个BeanDefination对象对应一个标签的信息。

执行loadBeanDefinition()方法: 加载BeanDefination的操作,

4.BeanFactory的详细介绍

在这里插入图片描述

5个获取实例的方法(getBean的重载方法);2个获取Bean的提供者;4个判断的方法(判断是否存在,是否为单例、原型,名称类型是否匹配);2个获取类型的方法和1个获取别名的方法。

public interface BeanFactory {

    //用户使用容器时,可以使用转义符“&”来得到FactoryBean本身
    String FACTORY_BEAN_PREFIX = "&";

    //获取Bean
    Object getBean(String name) throws BeansException;
    <T> T getBean(String name, Class<T> requiredType) throws BeansException;
    Object getBean(String name, Object... args) throws BeansException;
    <T> T getBean(Class<T> requiredType) throws BeansException;
    <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

    //获取bean的提供者(对象工厂)
    <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
    <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);

    //判断是否包含指定名字的bean
    boolean containsBean(String name); 
    //获取指定名字的Bean是否是Singleton类型的Bean,对于Singleton属性,用户可以在BeanDefinition中指定
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
    //获取指定名字的Bean是否是Prototype类型的,与Singleton属性一样也可以在BeanDefinition中指定
    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

    //指定名字的bean是否和指定的类型匹配
    boolean isTypeMatch(String name, ResolvableType typeToMatch);
    boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

    //获取指定名字的Bean的Class类型
    Class<?> getType(String name) throws NoSuchBeanDefinitionException; 

    //获取指定名字的Bean的所有别名,这些别名是用户在BeanDefinition中定义的
    String[] getAliases(String name); 
}
  1. getBean部分(重要):该方法表示获取bean实例
    ①、根据名字获取bean:getBean(String name)
    ②、根据类型获取bean:getBean(Class requiredType)
    ③、根据名字和类型获取bean(推荐):getBean(String name, Class requiredType)
    ④、根据名称、类型和给定的构造函数参数或者工厂方法参数构造对象获取bean

  2. getBeanProvider部分:该方法表示获取bean的提供者(对象工厂)

  3. containsBean(String name):通过名字判断是否包含指定bean的定义 。
    isSingleton(String name) isPrototype(String name):判断是单例和原型(多例)的方法。
    isTypeMatch:判断给定bean的名字是否和类型匹配 。
    getType(String name):根据bean的名字来获取其类型的方法 (按 Java 类型匹配的方式 )。
    getAliases(String name):根据bean的名字来获取其别名的方法。

  4. ResolvableType参数介绍
    ResolvableType是对Java java.lang.reflect.Type的封装,并且提供了一些访问该类型的其他信息的方法(例如父类, 泛型参数,该类)。从成员变量、方法参数、方法返回类型、类来构建ResolvableType的实例。

5.ApplicationContext容器的设计原理

在这里插入图片描述
ClassPathXmlApplicationContext:

ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
    public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
        this(new String[] {configLocation}, true, null);
    }

configLocation表示的是Spring配置文件的路径

    public ClassPathXmlApplicationContext(
            String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
            throws BeansException {
        // 1.初始化父类
        super(parent);
        // 2.设置本地的配置信息
        setConfigLocations(configLocations);
        // 3.完成Spring IOC容器的初始化
        if (refresh) {
            refresh();
        }
    }

首先初始化了父类,就是一直到父类AbstractApplicationContext中,将ApplicationContext的环境属性设置给本类的环境属性,包括一些profile,系统属性等。

然后设置本地的配置文件信息,这里调用其父类AbstractRefreshableConfigApplicationContext 的 setConfigLocations 方法,该方法主要处理ClassPathXmlApplicationContext传入的字符串中的占位符,即解析给定的路径数组(这里就一个),setConfigLocations 方法源码如下:

    public void setConfigLocations(@Nullable String... locations) {
        if (locations != null) {
            Assert.noNullElements(locations, "Config locations must not be null");
            this.configLocations = new String[locations.length];
            for (int i = 0; i < locations.length; i++) {
                //循环取出每一个path参数,在此处就一个applicationContext.xml
                this.configLocations[i] = resolvePath(locations[i]).trim();
            }
        }
        else {
            this.configLocations = null;
        }
    }

setConfigLocations方法除了处理ClassPathXmlApplicationContext传入的字符串中的占位符之外,其实还有一个作用:创建环境对象ConfigurableEnvironment。

refresh():
高级容器的所有功能(包括 IoC)

//AbstractApplicationContext.refresh()方法
public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            //刷新上下文环境
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            //这里是在子类中启动 refreshBeanFactory() 的地方,获得新的BeanFactory,解析XML、Java类,并加载BeanDefinition
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            //准备bean工厂,以便在此上下文中使用
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                //设置 beanFactory 的后置处理
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                //调用 BeanFactory 的后处理器,这些处理器是在Bean 定义中向容器注册的
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                //注册Bean的后处理器,在Bean创建过程中调用
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                //对上下文中的消息源进行初始化
                initMessageSource();

                // Initialize event multicaster for this context.
                //初始化上下文中的事件机制
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                //初始化其他特殊的Bean
                onRefresh();

                // Check for listener beans and register them.
                //检查监听Bean并且将这些监听Bean向容器注册
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                //实例化所有的(non-lazy-init)单件
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                //发布容器事件,结束Refresh过程
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

                // Reset 'active' flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }

            finally {
                // Reset common introspection caches in Spring's core, since we
                // might not ever need metadata for singleton beans anymore...
                //重置Spring公共的缓存
                resetCommonCaches();
            }
        }
    }
  • prepareRefresh() :为刷新准备上下文,主要设置状态量(是否关闭,是否激活),记录启动时间,初始化属性资源占位符、校验必填属性是否配置及初始化用于存储早期应用事件的容器。
  • obtainFreshBeanFactory():主要用于获取一个新的BeanFactory,如果BeanFactory已存在,则将其销毁并重建,默认重建的BeanFactory为AbstractRefreshableApplicationContext;此外此方法委托其子类从XML中或基于注解的类中加载BeanDefinition。
  • prepareBeanFactory():配置BeanFactory使其具有一个上下文的标准特征,如上下文的类加载器、后处理程序(post-processors,如设置如总感知接口)。
  • postprocessBeanFactory():在应用上下文内部的BeanFactory初始化结束后对其进行修改,在所有的BeanDefinition已被加载但还没有实例化bean, 此刻可以注册一些特殊的BeanPostFactory,如web应用会注册ServletContextAwareProcessor等。
  • invokeBeanFactoryPostProcessors():调用注册在上下文中的BeanFactoryPostProcessor,如果有顺序则按顺序调用,并且一定再单列对象实例化之前调用。
  • registerBeanPostProcessors():实例化并注册BeanPostProcessor,如果有显式的顺序则按照顺序调用一定在所有bean实例化之前调用。
  • initMessageSource():初始化MessageSource,如果当前上下文没有定义则使用其父类的,如果BeanFactory中不能找到名称为messageSource中的bean, 则默认使用DelegatingMessageSource。
  • initApplicationEventMulticaster():初始化ApplicationEventMulticaster,如果上下文没有定义则默认使用 - SimpleApplicationEventMulticaster,此类主要用于广播ApplicationEvent。
  • onRefresh() :在一些特定的上下文子类中初始化特定的bean,如在Webapp的上下文中初始化主题资源。
  • registerListeners():添加实现了ApplicationListener的bean作为监听器,它不影响非bean的监听器;还会使用多播器发布早期的ApplicationEvent。
  • finishBeanFactoryInitialization():实例化所有非延迟加载的单例,完成BeanFactory的初始化工作。
  • finishRefresh():完成上下文的刷新工作,调用LifecycleProcessor的onFresh()及发布的ContextRefreshEvent事件。
  • resetCommonCaches():重置Spring公共的缓存,如:ReflectionUtils、ResolvableType、CachedIntrospectionResults的缓存CachedIntrospectionResults的缓存。

14个方法

6.ApplicationContext的详细介绍

在这里插入图片描述
(1)、ClassPathXmlApplicationContext:从系统类路径classpath下加载一个或多个xml配置文件,找到并装载完成ApplicationContext的实例化工作。例如:

ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

(2)、FileSystemXmlApplicationContext:从系统磁盘下加载一个或多个xml配置文件(必须有访问权限)。也就是读取系统磁盘指定路径的xml文件。例如:

ApplicationContext ac = new FileSystemXmlApplicationContext("c:/applicationContext.xml");

它与ClassPathXmlApplicationContext的区别在于读取Spring配置文件的方式,FileSystemXmlApplicationContext不在从类路径下读取配置文件,而是通过制定参数从系统磁盘读取,前提是有访问权限。

(3)、XmlWebApplicationContext:从web应用下加载一个或多个xml配置文件,适用于web应用的xml配置方式。

在Java项目中提供ClassPathXmlApplicationContext类手工实例化ApplicationContext容器通常是不二之选,但是对于Web项目就不行了,Web项目的启动是由相应的Web服务器负责的,因此,在Web项目中ApplicationContext容器的实例化工作最好交由Web服务器来完成。Spring为此提供了以下两种方式:

  • org.springframework.web.context.ContextLoaderListener
  • org.springframework.web.context.ContexLoaderServlet(此方法目前以废弃)
    <!--从类路径下加载Spring配置文件,classpath特指类路径下加载-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath:applicationContext.xml
        </param-value>
    </context-param>
    <!--以Listener的方式启动spring容器-->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
@WebServlet("/MyServlet")
public class MyServlet {

        public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //创建XmlWebApplicationContext对象,但这时并没有初始化容器
            XmlWebApplicationContext context = new XmlWebApplicationContext();
            // 指定配置文件路径
            context.setConfigLocation("application.xml");
            // 需要指定ServletContext对象
            context.setServletContext(request.getServletContext());
            // 初始化容器
            context.refresh();
            //获取实例
            Additive additive = (Additive) context.getBean("additive");
            additive.addAdditive();

        }
}

(4)、AnnotationConfigApplicationContext:从Java注解的配置类中加载Spring的ApplicationContext容器。使用注解避免使用application.xml进行配置。相比XML配置,更加便捷。

@Configuration
public class AppConfig {

    @Bean(name = "orangeJuice")
    public OrangeJuice orangeJuice(){
        OrangeJuice orangeJuice = new OrangeJuice();
        return orangeJuice;
    }

    @Bean(name = "additive")
    public Additive additive(){
        Additive additive = new Additive();
        return additive;
    }
}

(5)、AnnotationConfigWebApplicationContext:专门为web应用准备的用于读取注解创建容器的类

    <!--通过指定context参数,让Spring使用AnnotationConfigWebApplicationContext启动容器
    而非XmlWebApplicationContext。默认没配置时是使用XmlWebApplicationContext-->
    <context-param>
        <param-name>contextClass</param-name>
        <param-value>
            org.springframework.web.context.support.AnnotationConfigWebApplicationContext
        </param-value>
    </context-param>
    <!--指定标注了@Configuration的类,多个可以用逗号分隔-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>com.thr.AppConfig</param-value>
    </context-param>
    <!--监听器将根据上面的配置使用AnnotationConfigWebApplicationContext
    根据contextConfigLocation指定的配置类启动Spring容器-->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

7.ApplicationContext容器扩展功能详解介绍

在这里插入图片描述

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-02-27 10:57:09  更:2022-02-27 10:57:36 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 11:54:11-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码