[源码系列:手写spring] IOC第九节:应用上下文ApplicationContext

内容介绍

在Spring中应用上下文ApplicationContext是相较于BeanFacotry更为先进的IOC容器,BeanFacotry是Spring实现IOC最基础最核心的接口,使得Spring管理不同Java对象成为可能。而ApplicationContext是建立在ApplicationContext的基础上,提供了更多面向应用的功能。除了拥有BeanFactory的所有功能外,还支持特殊类型bean,如上一节中讲到的BeanFactoryPostProcessor和BeanPostProcessor两者的自动识别、资源加载、容器事件和监听器、国际化支持、单例bean自动初始化等

BeanFactory是spring的底层基础设施,面向spring本身;而ApplicationContext面向spring的使用者,在开发中应该使用ApplicationContext。

我们一般称BeanFactory为Ioc容器,称ApplicationContext为应用上下文,通常ApplicationContext也被为Spring容器。

ApplicationContext添加了BeanFactoryPostProcessor和BeanPostProcessor的自动识别,不在需要我们像上一篇文章中一样手动添加了,只需要在xml中配置两者即可。

目前bean 的生命周期如下:

当前bean生命周期

当前ApplicationContext的继承体系

当前ApplicationContext的继承体系
当前ApplicationContext的继承体系

代码分支

GitHub - yihuiaa/little-spring at application-context剖析Spring源码,包括常见特性IOC、AOP、三级缓存等... Contribute to yihuiaa/little-spring development by creating an account on GitHub.https://github.com/yihuiaa/little-spring/tree/application-context

核心代码

ConfigurableApplicationContext

添加刷新容器的方法

public interface ConfigurableApplicationContext extends ApplicationContext {

	/**
	 * 刷新容器
	 *
	 * @throws BeansException
	 */
	void refresh() throws BeansException;
}

AbstractRefreshableApplicationContext

/**
 * ● @author: YiHui
 * ● @date: Created in 23:40  2023/4/26
 */
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext{
    private DefaultListableBeanFactory beanFactory;

    /**
     * 创建beanFactory并加载BeanDefinition
     * @throws BeansException
     */
    @Override protected void refreshBeanFactory() throws BeansException {
        DefaultListableBeanFactory factory = createBeanFactory();
        loadBeanDefinitions(factory);
        this.beanFactory = factory;
    }
    /**
     * 加载BeanDefinition
     *
     * @param beanFactory
     * @throws BeansException
     */
    protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException;
    /**
     * 创建bean工厂
     *
     * @return
     */
    protected DefaultListableBeanFactory createBeanFactory() {
        return new DefaultListableBeanFactory();
    }
    public DefaultListableBeanFactory getBeanFactory() {
        return beanFactory;
    }
}

AbstractXmlApplicationContext

/**
 * ● @author: YiHui
 * ● @date: Created in 21:07  2023/6/12
 */
public abstract class AbstractXmlApplicationContext extends AbstractRefreshableApplicationContext{

    @Override protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException {
        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory, this);
        String[] configLocations = getConfigLocations();
        if(configLocations!=null){
            xmlBeanDefinitionReader.loadBeanDefinitions(configLocations);
        }
    }

    protected abstract String[] getConfigLocations();
}

AbstractApplicationContext

refresh()方法是AbstractApplicationContext类中一个重要的方法。它的主要作用是刷新应用程序上下文,即重新加载或更新上下文中的所有bean定义和配置。当调用refresh()方法时,Spring框架会执行以下关键步骤:

  1. 关闭旧的应用程序上下文(如果存在):首先,如果已经存在一个旧的应用程序上下文,refresh()方法会关闭它。这确保在刷新之前释放旧的资源,并清理任何可能的旧状态。

  2. 加载bean定义和配置:refresh()方法会重新加载上下文中的bean定义和配置。它会解析XML文件、注解或其他配置方式,并将这些定义转化为内部的数据结构,以便Spring能够了解和管理这些bean。

  3. 创建和初始化bean:refresh()方法会实例化和初始化所有定义的bean。它会根据bean定义的配置信息,使用适当的构造函数或工厂方法创建bean实例,并将其装配(注入)所需的依赖关系。

  4. 注册bean实例:已创建和初始化的bean实例将在应用程序上下文中注册,以便其他部分可以访问它们。这样,其他组件或类可以通过依赖注入或查找方式获取所需的bean。

  5. 完成刷新过程:在完成上述步骤后,refresh()方法会触发一些后续操作,如事件发布、AOP代理的创建等。这些步骤将上下文准备好,使其可以在应用程序中使用。

package org.springframework.context.support;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.io.DefaultResourceLoader;

import java.util.Map;

/**
 * ● @author: YiHui
 * ● @date: Created in 21:43  2023/4/26
 * ● @notes: 抽象应用上下文
 */
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
    @Override public void refresh() throws BeansException {
        //创建BeanFactory,并加载BeanDefinition
        refreshBeanFactory();
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        //执行BeanFactoryPostProcessor
        invokeBeanFactoryPostProcessors(beanFactory);
        //BeanPostProcessor的实例化提前与其他bean
        registerBeanPostProcessors(beanFactory);

        //提前实例化单例Bean
        beanFactory.preInstantiateSingletons();
    }

    /**
     * 注册BeanPostProcessor
     * @param beanFactory
     */
    private void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        Map<String, BeanPostProcessor> beanPostProcessorMap = beanFactory.getBeansOfType(BeanPostProcessor.class);
        for(BeanPostProcessor beanPostProcessor : beanPostProcessorMap.values()) {
            beanFactory.addBeanPostProcessor(beanPostProcessor);
        }
    }

    private void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        Map<String, BeanFactoryPostProcessor> beanFactoryPostProcessorMap = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
        for(BeanFactoryPostProcessor beanFactoryPostProcessor : beanFactoryPostProcessorMap.values()){
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        }
    }

    /**
     * 创建BeanFactory,并加载BeanDefinition
     * @throws BeansException
     */
    protected abstract void refreshBeanFactory() throws BeansException;
    public abstract ConfigurableListableBeanFactory getBeanFactory();

    @Override public Object getBean(String name) throws BeansException {
        return getBeanFactory().getBean(name);
    }

    @Override public Object getBean(String name, Object[] args) {
        return getBeanFactory().getBean(name, args);
    }

    @Override public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
        return getBeanFactory().getBeansOfType(type);
    }

    @Override public String[] getBeanDefinitionNames() {
        return new String[0];
    }

    @Override public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
        return getBeanFactory().getBean(name, requiredType);
    }
}

测试

spring.xml

配置BeanFactoryPostProcessor和BeanPostProcessor的实现。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
	         http://www.springframework.org/schema/beans/spring-beans.xsd
		 http://www.springframework.org/schema/context
		 http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <bean id="person" class="bean.Person">
        <property name="name" value="yiHui"/>
        <property name="car" ref="car"/>
    </bean>

    <bean id="car" class="bean.Car">
        <property name="name" value="Rolls-Royce"/>
    </bean>

    <bean class="common.CustomBeanFactoryPostProcessor"/>
    <bean class="common.CustomerBeanPostProcessor"/>

</beans>

ApplicationContextTest

    @Test
    public void testApplicationContext(){
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");
        Person person = applicationContext.getBean("person", Person.class);
        //name属性在CustomBeanFactoryPostProcessor中被修改为YiHuiComeOn
        System.out.println(person);

        Car car = applicationContext.getBean("car", Car.class);
        //brand属性在CustomerBeanPostProcessor中被修改为Maserati
        System.out.println(car);
    }

ClassPathXmlApplicationContext初始化的时序图

ClassPathXmlApplicationContext初始化的时序图

 

测试结果

processor执行成功

执行bean[customBeanFactoryPostProcessor]的初始化方法
执行bean[customerBeanPostProcessor]的初始化方法
CustomerBeanPostProcessor#postProcessBeforeInitialization
执行bean[car]的初始化方法
CustomerBeanPostProcessor#postProcessAfterInitialization
CustomerBeanPostProcessor#postProcessBeforeInitialization
执行bean[person]的初始化方法
CustomerBeanPostProcessor#postProcessAfterInitialization
Person{name='YiHuiComeOn', age='null', car=Car{name='Maserati'}}
Car{name='Maserati'}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值