首页 > 其他分享 >Spring IoC 原理剖析

Spring IoC 原理剖析

时间:2024-01-16 18:25:16浏览次数:24  
标签:容器 beanFactory Spring beanName 剖析 Bean BeanFactory beans IoC

目录

IoC容器系列的设计与实现:BeanFactory和ApplicationContext

IOC容器接口设计图

image

其中,BeanFactory 定义了基本的 IoC 容器的规范。

BeanFactory 容器设计原理

以 DefaultListableBeanFactory 的实现为例,来说明简单 IoC 容器的设计原理:

image

  • BeanFactory实现是IoC容器的基本形式,各种ApplicationContext的实现是IoC容器的高级表现形式

  • DefaultListableBeanFactory 作为一个默认的功能完整的IoC容器来使用

  • Resource是Spring用来封装I/O操作的类

编程式使用IOC容器

DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(new ClassPathResource("UserBean.xml"));

UserService userService = factory.getBean("userService", UserService.class);

ApplicationContext

ApplicationContext 是一个高级形态意义的 IoC 容器:

  • 支持不同的信息源:继承接口Messagesource

  • 访问资源:继承接口ResourceLoader

  • 支持应用事件

  • 在ApplicationContext中提供附加功能

设计原理

以 FileSystemXmlApplicationContext 为例,来说明 ApplicationContext 的设计原理:

image

其中,ApplicationContext 的主要功能在基类 AbstractRefreshableApplicationContext 中已经实现了。

上面的类图可以看出,ConfigurableApplicationContext 的父接口 ApplicationContext:

  • 继承了 ListableBeanFactory 用于提供访问应用组件的方法

  • 继承了 ResourceLoader 用于提供加载资源文件的方法

  • 继承了 ApplicationEventPublisher 用于提供发布事件与注册监听器的方法

  • 继承了 MessageSource 提供国际化的支持

AbstractRefreshableApplicationContext

IoC 容器的初始化

IoC 容器的初始化过程,主要就体现在 AbstractApplicationContext 的 refresh() 方法中,其实现如下:

public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
...
    @Override
    public void refresh() throws BeansException, IllegalStateException {
        this.startupShutdownLock.lock();
        try {
            this.startupShutdownThread = Thread.currentThread();

            StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

            // 1.Prepare this context for refreshing.
            prepareRefresh();

            // 2.Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // 3.Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);

            try {
                // 4.Allows post-processing of the bean factory in context subclasses.
                postProcessBeanFactory(beanFactory);

                StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
                // 5.Invoke factory processors registered as beans in the context.
                invokeBeanFactoryPostProcessors(beanFactory);

                //6.Register bean processors that intercept bean creation.
                registerBeanPostProcessors(beanFactory);
                beanPostProcess.end();

                // 7.Initialize message source for this context.
                initMessageSource();

                // 8.Initialize event multicaster for this context.
                initApplicationEventMulticaster();

                // 9.Initialize other special beans in specific context subclasses.
                onRefresh();

                // 10.Check for listener beans and register them.
                registerListeners();

                // 11.Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);

                // 12.Last step: publish corresponding event.
                finishRefresh();
            }

            catch (RuntimeException | Error 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 {
                contextRefresh.end();
            }
        }
        finally {
            this.startupShutdownThread = null;
            this.startupShutdownLock.unlock();
        }
    }
...
}

各个方法功能说明如下:

image

创建 Bean 容器前的准备工作

prepareRefresh():准备工作,记录下容器的启动时间、标记“已启动”状态、处理配置文件中的占位符。

protected void prepareRefresh() {
    // 记录启动时间
    this.startupDate = System.currentTimeMillis();
    this.closed.set(false);
    this.active.set(true);

    if (logger.isDebugEnabled()) {
        if (logger.isTraceEnabled()) {
            logger.trace("Refreshing " + this);
        }
        else {
            logger.debug("Refreshing " + getDisplayName());
        }
    }

    // Initialize any placeholder property sources in the context environment.
    initPropertySources();

    // 校验 XML 配置文件
    getEnvironment().validateRequiredProperties();

    // Store pre-refresh ApplicationListeners...
    if (this.earlyApplicationListeners == null) {
        this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
    }
    else {
        // Reset local application listeners to pre-refresh state.
        this.applicationListeners.clear();
        this.applicationListeners.addAll(this.earlyApplicationListeners);
    }

    // Allow for the collection of early ApplicationEvents,
    // to be published once the multicaster is available...
    this.earlyApplicationEvents = new LinkedHashSet<>();
}

创建 Bean 容器,加载并注册 Bean

obtainFreshBeanFactory():这个方法是全文最重要的部分之一,这里将会初始化 BeanFactory、加载 Bean、注册 Bean 等等。

BeanDefinition 就是我们所说的 Spring 的 Bean,我们定义的各个 Bean 其实会转换成一个个 BeanDefinition 存在于 Spring 的 BeanFactory 中。Bean 在代码层面上可以简单认为是 BeanDefinition 的实例。
BeanDefinition 中保存了我们的 Bean 信息,比如这个 Bean 指向的是哪个类、是否是单例的、是否懒加载、这个 Bean 依赖了哪些 Bean 等等。

这一步会把配置文件就会解析成一个个的 Bean 定义,注册到 BeanFactory 中

// AbstractApplicationContext.java
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    refreshBeanFactory();
    return getBeanFactory(); // 返回刚刚创建的 BeanFactory
}

它会调用子类 AbstractRefreshableApplicationContext 的 refreshBeanFactory() 方法实现来刷新内部的 BeanFactory。

刷新 BeanFactory

其中,载入 Bean 定义信息的具体过程如下:

public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
    ...
    @Override
    protected final void refreshBeanFactory() throws BeansException {
        if (hasBeanFactory()) { // 如果 ApplicationContext 中已经加载过 BeanFactory 了,它会先销毁所有 Bean,并关闭 BeanFactory
            destroyBeans();
            closeBeanFactory();
        }
        try {
            DefaultListableBeanFactory beanFactory = createBeanFactory(); // 初始化一个 DefaultListableBeanFactory
            beanFactory.setSerializationId(getId()); // 用于 BeanFactory 的序列化
            customizeBeanFactory(beanFactory); // 设置 BeanFactory 的两个配置属性:是否允许 Bean 覆盖、是否允许循环引用
            loadBeanDefinitions(beanFactory); // 加载 Bean 到 BeanFactory 中
            this.beanFactory = beanFactory;
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }
    ...
}

ApplicationContext 虽然继承自 BeanFactory,但是它不应该被理解为 BeanFactory 的实现类,而是其内部持有一个实例化的 BeanFactory,即 DefaultListableBeanFactory ,后续所有的 BeanFactory 相关的操作其实是委托给这个实例来处理的。

上述代码中,最开始会创建一个 DefaultListableBeanFactory,并保存在 ApplicationContext 中,这一步的主要的方法是:loadBeanDefinitions()。

加载 Bean

loadBeanDefinitions():这个方法将根据配置,加载各个 Bean,然后放到 BeanFactory 中

其中,loadBeanDefinitions() 的实现如下:

public abstract class AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext {
    ...
    @Override
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        // Create a new XmlBeanDefinitionReader for the given BeanFactory.
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

        // Configure the bean definition reader with this context's
        // resource loading environment.
        beanDefinitionReader.setEnvironment(getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

        // Allow a subclass to provide custom initialization of the reader,
        // then proceed with actually loading the bean definitions.
        initBeanDefinitionReader(beanDefinitionReader);
        loadBeanDefinitions(beanDefinitionReader);
    }
    ...
}

注册 BeanDefinition

// org/springframework/beans/factory/support/DefaultListableBeanFactory.java
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
        implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {

    }
}

到这里已经初始化了 Bean 容器, 配置也相应的转换为了一个个 BeanDefinition,然后注册了各个 BeanDefinition 到注册中心,并且发送了注册事件。

Bean 容器实例化完成后

准备 Bean 容器

prepareBeanFactory(beanFactory):在使用 ApplicationContext 时需要做一些准备工作。这些准备工作是在这一步处理的,包括:为容器配置 ClassLoader、PropertyEditor 和 BeanPost-Processor 等,从而为容器的启动做好必要的准备。

postProcessBeanFactory(beanFactory)

postProcessBeanFactory(beanFactory) 是在所有的 beanDenifition 加载完成之后,bean 实例化之前执行。

为了能够修改 bean definitions,或者对 BeanFactory 做一些其他配置,就可以通过继承 ClassPathXmlApplicationContext 类,并重写 postProcessBeanFactory 方法即可。

invokeBeanFactoryPostProcessors(beanFactory)

拿到当前应用上下文 beanFactoryPostProcessors 变量中的值,实例化并调用所有已注册的 BeanFactoryPostProcessor。必须在singleton之前调用。

registerBeanPostProcessors(beanFactory);

初始化所有的 singleton beans。实例化并且注册所有的BeanPostProcessor beans,必须在任何bean实例化之前调用。

初始化所有的 singleton beans

finishBeanFactoryInitialization(beanFactory):会负责初始化所有的 singleton beans。

到目前为止,应该说 BeanFactory 已经创建完成,并且所有的实现了 BeanFactoryPostProcessor 接口的 Bean 都已经初始化并且其中的 postProcessBeanFactory(factory) 方法已经得到回调执行了。而且 Spring 已经“手动”注册了一些特殊的 Bean,如 environment、systemProperties 等。

剩下的就是初始化 singleton beans 了,我们知道它们是单例的,如果没有设置懒加载,那么 Spring 会在接下来初始化所有的 singleton beans。

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    // Initialize conversion service for this context.
    if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
            beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
        beanFactory.setConversionService(
                beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
    }

    // Register a default embedded value resolver if no BeanFactoryPostProcessor
    // (such as a PropertySourcesPlaceholderConfigurer bean) registered any before:
    // at this point, primarily for resolution in annotation attribute values.
    if (!beanFactory.hasEmbeddedValueResolver()) {
        beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
    }

    // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
    String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
    for (String weaverAwareName : weaverAwareNames) {
        getBean(weaverAwareName);
    }

    // Stop using the temporary ClassLoader for type matching.
    beanFactory.setTempClassLoader(null);

    // Allow for caching all bean definition metadata, not expecting further changes.
    beanFactory.freezeConfiguration();

    // Instantiate all remaining (non-lazy-init) singletons.
    beanFactory.preInstantiateSingletons(); // 开始初始化
}

其中,preInstantiateSingletons() 的实现如下:

// org/springframework/beans/factory/support/DefaultListableBeanFactory.java
public void preInstantiateSingletons() throws BeansException {
    if (logger.isTraceEnabled()) {
        logger.trace("Pre-instantiating singletons in " + this);
    }

    // Iterate over a copy to allow for init methods which in turn register new bean definitions.
    // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

    // Trigger initialization of all non-lazy singleton beans...
    for (String beanName : beanNames) {
        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
            if (isFactoryBean(beanName)) {
                Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                if (bean instanceof SmartFactoryBean<?> smartFactoryBean && smartFactoryBean.isEagerInit()) {
                    getBean(beanName);
                }
            }
            else {
                getBean(beanName); // 对于普通的 Bean,只要调用 getBean(beanName) 这个方法就可以进行初始化了
            }
        }
    }

    // Trigger post-initialization callback for all applicable beans...
    for (String beanName : beanNames) {
        Object singletonInstance = getSingleton(beanName);
        if (singletonInstance instanceof SmartInitializingSingleton smartSingleton) {
            StartupStep smartInitialize = getApplicationStartup().start("spring.beans.smart-initialize")
                    .tag("beanName", beanName);
            smartSingleton.afterSingletonsInstantiated();
            smartInitialize.end();
        }
    }
}

其中,getBean 的实现如下:

// org/springframework/beans/factory/support/AbstractBeanFactory.java
public Object getBean(String name) throws BeansException {
    return doGetBean(name, null, null, false);
}

protected <T> T doGetBean(
    String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
    throws BeansException {
    // ...
    return createBean(beanName, mbd, args);
    // ...
}

创建 Bean

doCreateBean():创建 Bean 实例

// org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
    throws BeanCreationException {
    // ...
    Object beanInstance = doCreateBean(beanName, mbdToUse, args);
    // ...
}

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
    throws BeanCreationException {
    // ...
    if (instanceWrapper == null) {
        instanceWrapper = createBeanInstance(beanName, mbd, args);  // 创建 Bean 实例
    }
    // ...
    // 依赖注入:属性注入
    populateBean(beanName, mbd, instanceWrapper);
    // 调用bean factory的回调,执行bean初始化的后处理流程
    exposedObject = initializeBean(beanName, exposedObject, mbd);
    // ...
    // 处理循环依赖
    if (earlySingletonExposure) {
        Object earlySingletonReference = getSingleton(beanName, false);
        if (earlySingletonReference != null) {
            if (exposedObject == bean) {
                exposedObject = earlySingletonReference;
            }
            else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                String[] dependentBeans = getDependentBeans(beanName);
                Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
                for (String dependentBean : dependentBeans) {
                    if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                        actualDependentBeans.add(dependentBean);
                    }
                }
                if (!actualDependentBeans.isEmpty()) {
                    // ...
                }
            }
        }
    }
}

创建 Bean 实例的过程

// org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    // Make sure bean class is actually resolved at this point.
    Class<?> beanClass = resolveBeanClass(mbd, beanName);

    // ...
    if (resolved) {
        if (autowireNecessary) {
            return autowireConstructor(beanName, mbd, null, null); // 构造函数依赖注入
        }
        else {
            return instantiateBean(beanName, mbd); // 无参构造函数依赖注入
        }
    }

    // Candidate constructors for autowiring?
    Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
    if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
            mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
        return autowireConstructor(beanName, mbd, ctors, args);
    }

    // Preferred constructors for default construction?
    ctors = mbd.getPreferredConstructors();
    if (ctors != null) {
        return autowireConstructor(beanName, mbd, ctors, null);
    }

    // No special handling: simply use no-arg constructor.
    return instantiateBean(beanName, mbd); // 无参构造函数依赖注入
}

这里,我们以无参构造函数的依赖注入为例来介绍其注入过程,其代码实现下:

// org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java
protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
    try {
        Object beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this); // 实例化
        BeanWrapper bw = new BeanWrapperImpl(beanInstance);
        initBeanWrapper(bw);
        return bw;
    }
    catch (Throwable ex) {
        throw new BeanCreationException(mbd.getResourceDescription(), beanName, ex.getMessage(), ex);
    }
}

instantiate() 方法的实现如下:

// org/springframework/beans/factory/support/SimpleInstantiationStrategy.java
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
    if (!bd.hasMethodOverrides()) {
        // ...
        // 利用构造方法进行实例化
        return BeanUtils.instantiateClass(constructorToUse);
    }
    else {
        // ...
        // 存在方法覆写,利用 CGLIB 来完成实例化,需要依赖于 CGLIB 生成子类
        return instantiateWithMethodInjection(bd, beanName, owner);
    }
}

Bean 属性注入

populateBean(beanName, mbd, instanceWrapper):负责进行属性设值,处理依赖。

其代码实现如下:

initializeBean

initializeBean(beanName, exposedObject, mbd):处理各种回调。

属性注入完成后,这一步其实就是处理各种回调了,这块代码比较简单。

其代码实现如下:


参考:

标签:容器,beanFactory,Spring,beanName,剖析,Bean,BeanFactory,beans,IoC
From: https://www.cnblogs.com/larry1024/p/17942592

相关文章

  • springBoot通过AOP(面向切面编程)实现自动保存请求日志
    1.定义注解importjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.annotation.Target;@Target(ElementType.METHOD)//指定该注解只能应用于方法上@Retention(RetentionPolicy.......
  • Elastic实战:彻底解决spring-data-elasticsearch日期、时间类型数据读取报错问题
    0.引言在使用spring-data-elasticsearch读取es中时间类型的数据时出现了日期转换报错,不少初学者会在这里困惑很久,所以今天我们专门来解读该问题的几种解决方案。1.问题分析该问题的报错形式一般是:Failedtoconvertfromtype[java.lang.String]totype[java.util.Date]f......
  • Spring Boot3.x集成ElasticSearch8.x
    SpringBoot3.x集成ElasticSearch8.x版本说明,本demo使用SpringBoot3.2.1+JDK17+ElasticSearch8.11.3前提是已经部署好了自己的ElasticSearch环境,我这里直接用容器默认部署好了,能访问即可创建SpringBoot项目导入pom依赖<dependency><grou......
  • Spring事务传播机制
    1.Spring对事物的支持一般有两种方式编程式事务管理:通过 TransactionTemplate或者TransactionManager手动管理事务,实际应用中很少使用,这不是本文的重点,就不在这里赘述。声明式事务管理:使用场景最多,也是最推荐使用的方式,直接加上@Transactional注解即可。2.Transactional注......
  • springboot~shardingsphere在非spring框架中的使用
    shardingsphere已经很方便的被springboot集成了,你只要引入sharding-jdbc-spring-boot-starter这个包就可以了,而如果是原生java的话,你就需要自己去实现了,主要是重新定义数据源,定义规则等问题,本文主要介绍原生环境下的shardingsphere的使用。依赖引用<dependencies><!--......
  • [spring] spring学习笔记(2): 通过xml实现依赖注入 - 特殊注入类型
    实际应用中,我们的对象可能会引用很多不同类型的东西,不单单只是几个数值对象类型在前一篇文章中,已经使用引用对象作为例子,关键在于使用ref<!--注意引用的对象要先创建Bean,id为weapon1--><beanid="player1"class="com.demo.player"> <!--通过setter注入,注意ref的......
  • springboot第48集:【思维导图】地图,面向对象,异常,功能代码
    在SpringBoot中,可以通过编写拦截器(Interceptor)来对请求进行拦截与处理。下面是一个简单的拦截器实现示例:创建一个类并实现HandlerInterceptor接口publicclassAuthInterceptorimplementsHandlerInterceptor{@OverridepublicbooleanpreHandle(HttpServletRequest......
  • Springboot上传文件大小限制处理
    今天在开发过程中遇到一个文件上传的问题io.undertow.server.RequestTooBigException:UT000020:Connectionterminatedasrequestwaslargerthan10485760Servlet容器使用的是undertow,看异常信息应该是默认存在10MB的文件大小限制。百度了一下,找到如下配置,问题得以解决,记......
  • Spring Cloud整体架构解析
    SpringCloud整体架构SpringCloud的中文名我们就暂且称呼它为“春云”吧,听上去是多么朴实无华的名字,不过呢一般名字起的低调的都是厉害角色,我们就看看SpringCloud都提供了哪些靠谱功能吧。SpringCloud是一款微服务架构的一站式解决方案,你在微服务化过程中碰到的任何问题,都可......
  • SpringSecurity表单认证(二)
    用户名+密码系统默认登录用户名:user密码每次服务启动后随机生成密码用户信息获取原理(数据库获取)实现该接口,security默认自动生成密码关闭。框架源码:packageorg.springframework.security.core.userdetails;publicinterfaceUserDetailsService{UserDetailsloa......