Spring高手之路12——BeanDefinitionRegistry与BeanDefinition合并解析

这篇具有很好参考价值的文章主要介绍了Spring高手之路12——BeanDefinitionRegistry与BeanDefinition合并解析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 什么是BeanDefinitionRegistry?

  BeanDefinitionRegistry 是一个非常重要的接口,存在于 Springorg.springframework.beans.factory.support 包中,它是 Spring 中注册和管理 BeanDefinition 的核心组件。

  让我们回顾一下上一篇说的 BeanDefinition。在 Spring 中,一个 Bean 就是一个被 Spring 管理的对象,而一个 BeanDefinition 则是一个 Bean 的配置描述,它描述了一个 Bean 的数据。它包含了 Bean 的类名、是否为抽象类、构造函数和属性值等信息。这些元数据将指导 Spring 如何创建和初始化 Bean

  再来看一下 BeanDefinitionRegistry 的作用,BeanDefinitionRegistry 的主要职责就是注册和管理这些 BeanDefinition。我们可以把它看作是一个存放 BeanDefinition 的注册表,向其中注册新的 BeanDefinition,或者检索和删除现有的 BeanDefinition。它提供了一些方法,如 registerBeanDefinition(String, BeanDefinition)removeBeanDefinition(String),和 getBeanDefinition(String),用于执行这些操作。

  在 Spring 的内部,BeanDefinitionRegistry 通常由 BeanFactory 实现,特别是 DefaultListableBeanFactoryGenericApplicationContext,它们都实现了这个接口。

2. 为什么需要BeanDefinitionRegistry?

如果BeanDefinitionRegistry不存在,Spring的某些核心功能会受到什么样的影响?

  1. 资源解析的统一性BeanDefinition作为一个统一的数据结构存储了Bean的配置信息。如果没有BeanDefinitionRegistry,每种配置方式(XML、注解、Java配置)都需要各自的专门数据结构。这不仅会导致资源解析的代码复杂度增加,还可能在不同的解析机制之间产生不一致性。

  2. 依赖查找和注入BeanDefinitionRegistry提供了一个中心位置,充当了Bean定义的中央存储,可以快速查找Bean的定义。如果没有它,当需要注入一个Bean的依赖时,Spring不仅需要遍历所有的配置源来查找对应的Bean,而且还可能遭遇Bean定义不一致的问题,这会显著降低性能和准确性。

Bean定义不一致的例子如下:

<!-- in config1.xml -->
<bean id="sampleBean" class="com.example.SampleBean1" />

<!-- in config2.xml -->
<bean id="sampleBean" class="com.example.SampleBean2" />

  这里,sampleBean 在两个配置文件中都有定义,但它们引用了不同的类。如果没有BeanDefinitionRegistry集中处理这些定义,那么Spring在尝试初始化sampleBean时可能会遭遇混淆,比如Spring尝试创建ServiceA的实例并为它注入sampleBean时,就会出现一个问题:Spring应该选择哪一个sampleBean的定义?com.example.SampleBean1还是com.example.SampleBean2

  这就是所谓的“Bean定义不一致”问题。如果Spring不知道哪一个定义是正确的,那么它可能会注入错误的Bean,从而导致应用程序的行为出现问题或者失败。这也可能导致应用在运行时出现不可预测的错误,因为注入的Bean并不是应用期望的版本或类型。

  通过使用BeanDefinitionRegistrySpring可以在应用程序启动时检测这类问题,并在Bean定义冲突或不一致时提供明确的错误消息,而不是在运行时遭遇不确定的行为或错误。

  1. 延迟初始化和作用域管理BeanDefinitionRegistry存储了BeanDefinitionBeanDefinition中包含了Bean的作用域和其他元数据。如果没有这个BeanDefinitionRegistrySpring在执行Bean的延迟加载或根据作用域创建Bean时,需要重新解析原始的配置资源,这增加了处理时间并可能导致潜在的配置错误。

  2. 配置验证:当所有BeanDefinition注册到BeanDefinitionRegistry后,Spring可以进行配置的校验,例如检查循环依赖、确保Bean定义的完整性等。如果没有BeanDefinitionRegistrySpring需要在每次Bean初始化时进行检查,这不仅导致性能下降,还可能漏掉某些隐晦的配置问题。

  3. 生命周期管理:没有BeanDefinitionRegistry存储生命周期回调、初始化方法等信息,Spring在管理Bean的生命周期时,需要从原始的配置源获取这些信息。这不仅增加了管理的复杂度,还会使生命周期回调会变得复杂和笨重。

  简而言之,没有BeanDefinitionRegistrySpring会失去中心化的Bean管理,导致效率下降、错误处理分散、以及增加生命周期管理的复杂度。BeanDefinitionRegistry确保了Spring的高效、一致和稳定运行。

3. BeanDefinitionRegistry 的使用

3.1 BeanDefinitionRegistry 简单例子

  在这个例子中,我们将创建一个简单的 Bean,注册到 DefaultListableBeanFactory(它实现了 BeanDefinitionRegistry 接口),然后从工厂中获取并使用这个 Bean

全部代码如下:

首先,我们需要一个 Bean 类,这是一个简单的 POJO 类:

package com.example.demo.bean;

public class MyBean {
    private String message;

    public void doSomething() {
        System.out.println("Hello, world!");
    }

    public void setMessage(String message){
        this.message  = message;
    }

    public void getMessage(){
        System.out.println("Your Message : " + message);
    }
}

然后,我们可以使用 DefaultListableBeanFactoryRootBeanDefinition 来创建并注册这个 Bean

package com.example.demo;

import com.example.demo.bean.MyBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;

public class DemoApplication {

    public static void main(String[] args) {
        // 创建 BeanDefinitionRegistry
        DefaultListableBeanFactory registry = new DefaultListableBeanFactory();

        // 创建一个 BeanDefinition
        BeanDefinition beanDefinition = new RootBeanDefinition(MyBean.class);

        // 注册 BeanDefinition
        registry.registerBeanDefinition("myBean", beanDefinition);

        // 从 BeanFactory 中获取 Bean
        MyBean myBean = registry.getBean("myBean", MyBean.class);

        // 使用 Bean
        myBean.doSomething();  // 输出:Hello, world!
    }
}

  这个程序会创建一个名为 "myBean"Bean,这个 BeanMyBean 类的一个实例。然后,我们从 BeanFactory 中获取这个 Bean,并调用其 doSomething 方法,打印 "Hello, world!"

beandefinitionregistry,Spring高手之路,BeanDefinition,Definition合并,Spring配置,Spring,Bean定义合并,原力计划

3.2 有关ImportBeanDefinitionRegistrar的实现类的例子

这个在第8篇(Spring高手之路8——Spring Bean模块装配的艺术:@Import详解)提到过,是3.5节,大家可以回头看,这里不重复粘贴代码。

4. BeanDefinition的合并

我们前一篇讲解BeanDefinition的时候没有讲解BeanDefinition的合并,这里补充说明。

  1. BeanDefinition

  在 Spring 中,BeanDefinition 是一个接口,它定义了 Bean 的配置信息,例如 Bean 的类名,是否是单例,依赖关系等。在 Spring 中,每一个 Bean 都对应一个 BeanDefinition 对象。

  1. 合并的意义

  在 Spring 中,有一种特殊的 BeanDefinition,叫做子 BeanDefinition,也就是我们在 XML 配置文件中通过 parent 属性指定的那种。这种子 BeanDefinition 可以继承父 BeanDefinition 的配置信息。

  合并的过程,就是把子 BeanDefinition 的配置信息和父 BeanDefinition 的配置信息合并起来,形成一个完整的配置信息。合并后的 BeanDefinition 对象包含了 Bean 创建所需要的所有信息,Spring 将使用这个完整的 BeanDefinition 来创建 Bean 实例。

  1. 合并的过程

  Spring 在需要创建 Bean 实例的时候,会先获取对应的 BeanDefinition 对象。如果这个 BeanDefinition 是一个子 BeanDefinitionSpring 就会找到它的父 BeanDefinition,然后把两者的配置信息合并起来,形成一个完整的 BeanDefinition

  这个过程是在 DefaultListableBeanFactorygetMergedBeanDefinition 方法中进行的,如果大家有兴趣,可以在这个方法中设置断点,看一看具体的合并过程。

  1. 合并过程的流程图

beandefinitionregistry,Spring高手之路,BeanDefinition,Definition合并,Spring配置,Spring,Bean定义合并,原力计划

我们可以通过父子Bean的方式使用这个特性,下面是一个XML配置的例子:

<bean id="parentBean" class="com.example.ParentClass" abstract="true">
    <property name="commonProperty" value="commonValue" />
</bean>

<bean id="childBean" parent="parentBean">
    <property name="specificProperty" value="specificValue" />
</bean>

  在这个例子中,我们定义了两个bean,一个是 parentBean,另一个是 childBeanparentBeanabstract 的,表示它不会被实例化,只作为模板使用。childBeanparent 属性指向 parentBean,表示它继承了 parentBean 的配置。

  parentBean 有一个属性 commonProperty,值为 commonValuechildBean 有一个属性 specificProperty,值为 specificValue。在Spring解析这个配置文件,生成BeanDefinition的时候,childBeanBeanDefinition会包含两个属性:commonPropertyspecificProperty,这就是 BeanDefinition 的合并过程。

  Java配置中,我们无法直接模拟XML配置的BeanDefinition合并过程,因为这是Spring XML配置的一项特性,配置类通常会采用Java代码的继承或组合来重用bean定义,不会涉及到配置元数据层面的BeanDefinition合并。XML配置中的BeanDefinition合并特性允许我们定义一个父Bean,然后定义一些子Bean,子Bean可以继承父Bean的一些属性。

  这个特性在Java配置中并没有直接的替代品,因为Java配置通常更加依赖实例化过程中的逻辑,而不是元数据(即BeanDefinition)。在Java配置中,我们可以使用继承和组合等普通的Java特性来实现类似的结果,但这不是真正的BeanDefinition合并。因此,当我们从XML配置转换为Java配置时,通常需要手动将共享的属性复制到每个Bean的定义中。

4.1 调试验证BeanDefinition的合并

全部代码如下:

首先,创建 XML 配置文件 applicationContext.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="parentBean" class="com.example.demo.bean.ParentClass" abstract="true">
        <property name="commonProperty" value="commonValue" />
    </bean>

    <bean id="childBean" parent="parentBean" class="com.example.demo.bean.ChildClass">
        <property name="specificProperty" value="specificValue" />
    </bean>
</beans>

然后,创建 ParentClassChildClass,如下:

package com.example.demo.bean;

public abstract class ParentClass {

    private String commonProperty;

    public String getCommonProperty() {
        return commonProperty;
    }

    public void setCommonProperty(String commonProperty) {
        this.commonProperty = commonProperty;
    }
}
package com.example.demo.bean;

public class ChildClass extends ParentClass {

    private String specificProperty;

    public String getSpecificProperty() {
        return specificProperty;
    }

    public void setSpecificProperty(String specificProperty) {
        this.specificProperty = specificProperty;
    }
}

主程序如下:

package com.example.demo;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class DemoApplication {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        DefaultListableBeanFactory factory = (DefaultListableBeanFactory) context.getBeanFactory();

        // 获取childBean的原始BeanDefinition
        BeanDefinition childBeanDefinition = factory.getBeanDefinition("childBean");
        System.out.println("Child bean definition before merge: " + childBeanDefinition);

        // 获取合并后的BeanDefinition
        BeanDefinition mergedBeanDefinition = factory.getMergedBeanDefinition("childBean");
        System.out.println("Merged bean definition: " + mergedBeanDefinition);
    }
}

  在这个示例中,我们首先加载了 applicationContext.xml 配置文件,然后获取了 childBean 的原始 BeanDefinition。然后,我们调用 getMergedBeanDefinition 方法获取了合并后的 BeanDefinition,可以在这个过程中设置断点来查看合并过程的详细情况。

运行结果:

beandefinitionregistry,Spring高手之路,BeanDefinition,Definition合并,Spring配置,Spring,Bean定义合并,原力计划

  大家可以从运行结果看到打印了Generic beanRoot bean,代表了GenericBeanDefinitionRootBeanDefinition

为什么有两个不同的 BeanDefinition 类型( GenericBeanDefinition 和 RootBeanDefinition)

GenericBeanDefinition:

  • 这是一个通用的BeanDefinition实现类,可以配置任何类型的bean
  • 它通常用于读取XML、注解或其他形式的配置。
  • 与其它特定的BeanDefinition相比,它是比较简单和轻量级的。
  • 当使用<bean>元素在XML中定义bean时,通常会为该bean创建一个GenericBeanDefinition实例。

RootBeanDefinition:

  • 这是一个完整的bean定义,包含了bean的所有配置信息,如构造函数参数、属性值、方法覆盖等。
  • 它通常用于合并父子bean定义。也就是说,当一个bean定义继承另一个bean定义时,RootBeanDefinition负责持有合并后的最终配置。
  • 除了GenericBeanDefinition之外,它还包含许多与bean的实例化、依赖解析和初始化相关的内部细节。
  • Spring的内部工作流中,尽管开始时可以有各种BeanDefinition实现,但在容器的后期处理阶段,它们通常都会转化为RootBeanDefinition,因为在这个阶段需要一个完整和固定的bean定义来进行bean的创建。

调试点1:我们从BeanFactory中获取了子bean的原始BeanDefinition。这个BeanDefinition只表示了XML中为子 bean配置的元数据,没有与父Bean的合并,只能看到specificProperty属性。

beandefinitionregistry,Spring高手之路,BeanDefinition,Definition合并,Spring配置,Spring,Bean定义合并,原力计划

调试点2:用getMergedBeanDefinition之后,控制台打印的 BeanDefinition 的类型变为了 RootBeanDefinition ,此时,我们从BeanFactory中获取了合并后的子BeanBeanDefinition。由于子BeanBeanDefinition与父BeanBeanDefinition已合并,所以能看到一个完整的属性集,这里在propertyValues中看到两个属性键值对:commonPropertyspecificProperty,这表明子Bean继承了父Bean的属性值。

beandefinitionregistry,Spring高手之路,BeanDefinition,Definition合并,Spring配置,Spring,Bean定义合并,原力计划

注意,这个示例的目的是展示 BeanDefinition 的合并过程,因此我们直接操作了 BeanFactory。在实际的应用开发中,我们一般不会直接操作 BeanFactory

4.2 BeanDefinition合并的目的

  1. 提供完整的BeanDefinition信息:在配置中,我们经常会使用父子BeanDefinition(如通过<bean>标签的parent属性)。子BeanDefinition可能只会定义需要改变或增加的bean属性,而父BeanDefinition则提供共享的默认定义。在这种情况下,合并操作会将父子BeanDefinition的信息合并为一个完整的BeanDefinition,用于接下来的bean创建。

  2. 优化性能:合并操作的结果通常会被缓存起来,因此在下次获取同样的bean时,可以直接从缓存中获取合并后的BeanDefinition,避免了重复的合并操作,从而提高了性能。

  3. 解决循环依赖:在处理bean之间的循环依赖时,需要尽早抛出已经处理(例如实例化和属性填充)的bean,这时就需要一个完整的BeanDefinition信息。因此,BeanDefinition的合并在解决循环依赖问题上也有重要作用。

简而言之,BeanDefinition的合并是为了得到一个完整、准确的BeanDefinition,以供Spring IoC容器后续的bean创建和依赖解析使用。

4.3 图解BeanDefinition合并与Spring初始化关系

beandefinitionregistry,Spring高手之路,BeanDefinition,Definition合并,Spring配置,Spring,Bean定义合并,原力计划

  1. 资源定位

在此阶段,Spring会根据用户的配置来确定需要加载的资源位置,资源可能来源于多种配置方式,如XMLJava注解或Java配置。

  1. 读取配置

Spring从确定的配置源中读取Bean定义信息

  • 对于XML配置,解析器会处理每一个<bean>元素。在这个时候,特别是存在父子Bean关系的定义,这些定义被解析为原始的BeanDefinition,但并没有合并。

  • 对于注解和Java配置,BeanDefinition被解析为独立的定义,通常不涉及父子关系。

  1. 注册BeanDefinition

Spring会将所有解析得到的BeanDefinition注册到BeanDefinitionRegistry中。

  1. 处理BeanDefinition

在这个阶段,Spring进行BeanDefinition的预处理。

  • 如果从XML配置中读取的Bean之间存在父子关系,这时会进行合并,合并后的BeanDefinition确保子Bean继承了父Bean的所有属性,并且能够覆盖它们。
  • 而基于注解或Java配置的Bean定义,由于没有明确的父子关系,这种合并操作通常不会发生。
  1. Bean的实例化与属性填充
  • 此阶段标志着Spring生命周期的开始。

  • 所有的BeanDefinition,无论是原始的还是经过合并的,都会在此阶段转化为实际的Bean实例。

  • Spring容器将负责管理这些Bean的完整生命周期,包括但不限于依赖注入、属性设置。

  1. Bean的初始化
  • 包括调用Bean的初始化方法,例如实现了InitializingBean接口的afterPropertiesSet方法或者通过init-method属性指定的自定义初始化方法。

  • 在此阶段,Bean已经完全准备好,可以供应用程序使用。

  1. 注册Bean的销毁方法
  • Spring会跟踪并注册Bean的销毁方法。

  • 这确保了当Spring容器关闭时,它会正确地调用每个Bean的销毁方法,例如实现了DisposableBean接口的destroy方法或通过destroy-method属性指定的自定义方法。

从这里可以看到BeanDefinition的合并发生在实际Bean实例化之前的早期阶段,这确保了当Spring去创建一个Bean实例时,它有一个完整的、合并的定义可以依赖。

5. BeanDefinition的合并的源码分析

5.1 BeanDefinition合并过程时序图

beandefinitionregistry,Spring高手之路,BeanDefinition,Definition合并,Spring配置,Spring,Bean定义合并,原力计划

5.2 BeanDefinition合并过程源码解读

这里讲一下前一篇没提到的BeanDefinition的合并,我们针对Spring 5.3.7的源码分析一下,先展示图,后面分析。

beandefinitionregistry,Spring高手之路,BeanDefinition,Definition合并,Spring配置,Spring,Bean定义合并,原力计划

我们分析一下AbstractBeanFactory类的几个方法。

// 获取本地合并后的 BeanDefinition
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
    // 从缓存中获取合并后的 BeanDefinition
    RootBeanDefinition mbd = (RootBeanDefinition)this.mergedBeanDefinitions.get(beanName);
    // 如果缓存中的 BeanDefinition 不为空并且未过时,则直接返回
    // 否则,对 BeanDefinition 进行合并
    return mbd != null && !mbd.stale ? mbd : this.getMergedBeanDefinition(beanName, this.getBeanDefinition(beanName));
}

// 获取合并后的 BeanDefinition
protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd) throws BeanDefinitionStoreException {
    // 直接调用 getMergedBeanDefinition 方法,将 containingBd 设为 null
    return this.getMergedBeanDefinition(beanName, bd, (BeanDefinition)null);
}

// 获取合并后的 BeanDefinition
protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd) throws BeanDefinitionStoreException {
    synchronized(this.mergedBeanDefinitions) {
        RootBeanDefinition mbd = null;
        RootBeanDefinition previous = null;

        // 如果没有包含的 BeanDefinition,那么从缓存中获取合并后的 BeanDefinition
        if (containingBd == null) {
            mbd = (RootBeanDefinition)this.mergedBeanDefinitions.get(beanName);
        }

        // 如果缓存中的 BeanDefinition 为空或者过时,那么创建新的 BeanDefinition 进行合并
        if (mbd == null || mbd.stale) {
            previous = mbd;

            // 如果 bd 没有父名称,即没有继承其他的 bean
            // 那么就直接 clone 这个 bd,生成一个 RootBeanDefinition
            if (bd.getParentName() == null) {
                if (bd instanceof RootBeanDefinition) {
                    mbd = ((RootBeanDefinition)bd).cloneBeanDefinition();
                } else {
                    mbd = new RootBeanDefinition(bd);
                }
            } else { // 如果 bd 是一个子 BeanDefinition(即有父 BeanDefinition)
                // 首先获取父 BeanDefinition
                BeanDefinition pbd;
                try {
                    String parentBeanName = this.transformedBeanName(bd.getParentName());
                    if (!beanName.equals(parentBeanName)) {
                        pbd = this.getMergedBeanDefinition(parentBeanName);
                    } else {
                        BeanFactory parent = this.getParentBeanFactory();
                        if (!(parent instanceof ConfigurableBeanFactory)) {
                            throw new NoSuchBeanDefinitionException(parentBeanName, "Parent name '" + parentBeanName + "' is equal to bean name '" + beanName + "': cannot be resolved without a ConfigurableBeanFactory parent");
                        }

                        pbd = ((ConfigurableBeanFactory)parent).getMergedBeanDefinition(parentBeanName);
                    }
                } catch (NoSuchBeanDefinitionException var11) {
                    throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName, "Could not resolve parent bean definition '" + bd.getParentName() + "'", var11);
                }

                // 创建一个新的 RootBeanDefinition 并覆盖 bd 中的属性
                // 这就完成了父子 BeanDefinition 的合并
                mbd = new RootBeanDefinition(pbd);
                mbd.overrideFrom(bd);
            }

            // 如果合并后的 BeanDefinition 没有指定作用域
            // 则默认设置为 singleton
            if (!StringUtils.hasLength(mbd.getScope())) {
                mbd.setScope("singleton");
            }

            // 如果定义了父 BeanDefinition 且父 BeanDefinition 的作用域不是 singleton 但子 BeanDefinition 的作用域是 singleton
            // 则将子 BeanDefinition 的作用域设置为父 BeanDefinition 的作用域
            if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
                mbd.setScope(containingBd.getScope());
            }

            // 如果不存在包含的 BeanDefinition 并且需要缓存 BeanMetadata
            // 那么就将这个新创建并合并的 BeanDefinition 放入 mergedBeanDefinitions 缓存中
            if (containingBd == null && this.isCacheBeanMetadata()) {
                this.mergedBeanDefinitions.put(beanName, mbd);
            }
        }

        // 如果之前存在过期的 BeanDefinition
        // 那么从过期的 BeanDefinition 中拷贝相关的缓存到新的 BeanDefinition 中
        if (previous != null) {
            this.copyRelevantMergedBeanDefinitionCaches(previous, mbd);
        }

        // 返回合并后的 BeanDefinition
        return mbd;
    }
}

  这段代码主要完成了 BeanDefinition 的合并工作。当一个 BeanDefinition 有父 BeanDefinition 时,Spring 会将子 BeanDefinition 的定义与父 BeanDefinition 的定义进行合并,生成一个新的完整的 BeanDefinition,这个过程就是 BeanDefinition 的合并。该合并的 BeanDefinition 会被缓存起来,以便下次使用。如果一个 BeanDefinition 没有父 BeanDefinition,则直接 clone 一份作为合并后的 BeanDefinition。在 Spring 的整个生命周期中,BeanDefinition 的合并可能会发生多次,每次获取 Bean 时,都会先进行 BeanDefinition 的合并。文章来源地址https://www.toymoban.com/news/detail-639520.html


欢迎一键三连~

有问题请留言,大家一起探讨学习

----------------------Talk is cheap, show me the code-----------------------

到了这里,关于Spring高手之路12——BeanDefinitionRegistry与BeanDefinition合并解析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring高手之路-SpringBean的生命周期

    目录 SpringBean的生命周期 整体介绍 详细介绍 1.实例化Bean 2.设置属性值 3.检查Aware 4.调用BeanPostProcessor的前置处理方法 5.调用InitializingBean的afterPropertiesSet方法 6.调用自定义init-method方法 7.调用BeanPostProcessor的后置处理方法 8.注册Destruction回调 9.Bean准备就绪 10.调用DisposableBean的d

    2024年02月03日
    浏览(39)
  • Spring高手之路-Spring在业务中常见的使用方式

    目录 通过IOC实现策略模式 通过AOP实现拦截增强 1.参数检验 2.缓存逻辑 3.日志记录 通过Event异步解耦 通过Spring管理事务 1.声明式事务 2.编程式事务 3.需要注意的问题 不能在事务中处理分布式缓存 不能在事务中执行 RPC 操作 不过度使用声明式事务 很多时候,我们需要对不同的

    2024年01月19日
    浏览(45)
  • Spring高手之路9——掌握Spring条件装配的秘密武器

      在 Spring 框架中,条件装配( Conditional Configuration )是一个非常重要的特性,它允许开发者根据满足的条件,动态地进行 Bean 的注册或是创建。这样就可以根据不同的环境或配置,创建不同的 Bean 实例,这一特性对于创建可配置和模块化的应用是非常有用的。 Spring 提供了一

    2024年02月16日
    浏览(47)
  • Spring高手之路10——解锁Spring组件扫描的新视角

      首先,我们将探讨一些 Spring 框架中 IOC ( Inversion of Control )的高级特性,特别是组件扫描的相关知识。组件扫描是 Spring 框架中一个重要的特性,它可以自动检测并实例化带有特定注解(如 @Component , @Service , @Controller 等)的类,并将它们注册为 Spring 上下文中的 bean 。这

    2024年02月16日
    浏览(48)
  • Spring高手之路-@Autowired和@Resource注解异同点

    目录 概述 相同点 1.都可以实现依赖注入 2.都可以用于注入任意类型的Bean 3.都支持通过名称、类型匹配进行注入 不同点 1.来源不同。 2.包含的属性不同 3.匹配方式(装配顺序)不同。 4.支持的注入对象类型不同 5.应用地方不同 @Autowired 和 @Resource 是在 Java 开发中用于实现依赖

    2024年02月03日
    浏览(46)
  • Spring高手之路5——彻底掌握Bean的生命周期

    在 Spring IOC 容器中, Bean 的生命周期大致如下: 实例化:当启动 Spring 应用时, IOC 容器就会为在配置文件中声明的每个 bean 创建一个实例。 属性赋值:实例化后, Spring 就通过反射机制给 Bean 的属性赋值。 调用初始化方法:如果 Bean 配置了初始化方法, Spring 就会调用它。

    2024年02月09日
    浏览(38)
  • Spring高手之路3——揭秘Spring依赖注入和SpEL表达式

    本篇会给大家举出各种 Spring 属性依赖注入的例子,方便大家理解。 我们在前面的文章中已经使用过 XML 进行 setter 方法的属性注入了,下面让我们再来回顾一下: 我们在前面的文章中也学习过如何在 bean 创建时通过编程方式设置属性: 使用XML进行setter方法注入 首先,我们需

    2024年02月08日
    浏览(44)
  • Spring高手之路8——Spring Bean模块装配的艺术:@Import详解

      在 Spring 中,手动装配通常是指通过 XML 配置文件明确指定 Bean 及其依赖,或者在代码中直接使用 new 创建对象并设定依赖关系。   然而,随着 Spring 2.0 引入注解,以及 Spring 3.0 全面支持注解驱动开发,这个过程变得更加自动化。例如,通过使用 @Component + @Compo

    2024年02月13日
    浏览(35)
  • Spring高手之路13——BeanFactoryPostProcessor与BeanDefinitionRegistryPostProcessor解析

       BeanFactoryPostProcessor 位于 org.springframework.beans.factory.config 包中。它与 BeanPostProcessor 有相似的核心逻辑,但它们之间的主要区别在于它们所操作的对象。 BeanFactoryPostProcessor 的主要目的是对 Bean 的配置元数据进行操作,这意味着它可以影响 Bean 的初始配置数据。   在 Sp

    2024年02月11日
    浏览(39)
  • Spring高手之路15——掌握Spring事件监听器的内部逻辑与实现

    在阅读本文之前需要你已经对事件监听器有了简单的了解,或去阅读前面的文章《 Spring高手之路7——事件机制与监听器的全面探索 》   在 Spring 中, ApplicationContext 可以形成一个层次结构,通常由主容器和多个子容器组成。一个常见的疑问是:当一个事件在其中一个容器

    2024年02月06日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包