Spring父子工厂

对于Spring的父子工厂:

  1. 父工厂和子工厂的配置会整合在一起
  2. 如果父子工厂中存在相同的配置,会采用子工厂的配置

代码:

父工厂applicationContext-parent.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="p" class="edu.hzb.first.Person">

    </bean>

    <bean id="user" class="edu.hzb.first.User">
        <property name="id" value="2"/>
        <property name="name" value="jeremy"/>
    </bean>
</beans>

子工厂applicationContext-child.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="user" class="edu.hzb.first.User">
        <property name="id" value="1"/>
        <property name="name" value="hzb"/>
    </bean>
</beans>

测试代码:

@Test
    public void test3() {
        //父容器
        DefaultListableBeanFactory parent = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(parent);
        xmlBeanDefinitionReader.loadBeanDefinitions(new ClassPathResource("applicationContext-parent.xml"));

        //子容器
        DefaultListableBeanFactory child = new DefaultListableBeanFactory(parent);
        XmlBeanDefinitionReader xmlBeanDefinitionReader1 = new XmlBeanDefinitionReader(child);
        xmlBeanDefinitionReader1.loadBeanDefinitions(new ClassPathResource("applicationContext-child.xml"));

        Person p = (Person) child.getBean("p");
        User user = (User) child.getBean("user");
        System.out.println(p);
        System.out.println(user);
	   //这个user仍然是子容器中的user
        User user1 = (User) parent.getBean("user");
        System.out.println(user);

    }

学习哔哩哔哩《孙哥讲Spring5》视频所做的笔记

<think>好的,用户现在想了解Spring框架中的mergedBeanDefinitions的作用使用场景。我之前已经回答过关于Spring Bean初始化过程中动态代理的问题,现在需要结合用户提供的引用内容来详细解答。 首先,用户给出的引用[1]提到了AbstractBeanFactory中的getMergedLocalBeanDefinition方法,这个方法涉及mergedBeanDefinitions。我需要先理解这个方法的作用。根据代码,mergedBeanDefinitions是一个缓存,用来存储合并后的Bean定义。当需要获取Bean定义时,Spring会先检查这个缓存,如果存在就直接返回,否则进行合并处理。 接下来,我需要回忆SpringBean定义合并的概念。在Spring中,Bean定义可能存在父子关系,定义会继承定义的配置,同时可以覆盖某些属性。合并的过程就是将定义定义的属性合并成一个RootBeanDefinition,这样后续的Bean实例化就可以基于这个合并后的定义进行。 用户的问题是关于mergedBeanDefinitions的作用使用场景。根据引用中的代码,mergedBeanDefinitions缓存用于提高性能,避免重复合并Bean定义。每次获取Bean定义时,先检查缓存,存在则直接返回,不存在则进行合并并存入缓存。这样可以减少重复计算,提高效率。 使用场景方面,可能包括当存在父子Bean定义时,或者在处理Bean定义的继承属性覆盖时。例如,在复杂的配置中,多个Bean可能共享定义的通用配置,这时候合并过程就非常重要。此外,在Bean的后处理过程中,如BeanFactoryPostProcessor修改Bean定义时,合并后的定义会被使用。 需要注意的是,用户提供的引用中还提到了BeanFactoryPostProcessor的使用,如修改属性值或初始化方法,这可能与合并后的Bean定义相关,因为后续的处理都是基于合并后的定义进行的。例如,在修改Bean的属性时,操作的是已经合并过的Bean定义,确保所有继承的属性都被正确应用。 另外,引用[2]提到了JpaRepositoryFactoryBean的生成,这可能涉及到Spring Data的仓库配置,但暂时可能与mergedBeanDefinitions的关系不大。不过,当Spring Data创建这些工厂Bean时,可能也会涉及到Bean定义的合并,确保定义的属性被正确继承。 总结起来,mergedBeanDefinitions的主要作用是缓存合并后的Bean定义,避免重复合并,提升性能。使用场景包括处理父子Bean定义、Bean定义的后处理以及确保Bean实例化时使用的是完整的合并后的配置。 需要验证这些理解是否正确。例如,合并后的Bean定义是否在Bean的生命周期中被多次使用,是否在实例化、属性填充等阶段都依赖于此。同时,考虑是否有其他使用场景,如AOP代理生成时是否需要合并后的Bean定义信息。 另外,用户可能对mergedBeanDefinitions的具体使用时机内部机制感兴趣,需要解释清楚合并的过程以及缓存的管理策略,比如缓存的失效条件,何时会被清除或更新。 最后,确保回答结构清晰,分点说明作用场景,结合用户提供的代码引用,可能引用[^1][^3]来支持解释。</think>### Spring中mergedBeanDefinitions的作用与使用场景解析 mergedBeanDefinitions是Spring容器中用于处理Bean定义合并的核心缓存机制,其设计目标与使用场景贯穿Bean生命周期管理的关键环节。以下从实现原理与典型应用两个维度进行详细分析: --- #### 一、mergedBeanDefinitions的核心作用 1. **Bean定义合并缓存池** 当Spring容器遇到父子Bean定义时,通过mergedBeanDefinitions缓存已完成合并的`RootBeanDefinition`对象,避免重复计算带来的性能损耗。 ```java // AbstractBeanFactory源码示例 RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName); if (mbd != null) return mbd; // 直接返回缓存结果[^1] ``` 2. **配置继承解决方案** 处理父子Bean定义的属性继承时,通过合并操作生成**完整有效的配置元数据**: ```java // 合并定义与定义的示例过程 RootBeanDefinition merged = new RootBeanDefinition(parentDefinition); merged.overrideFrom(childDefinition); // 定义覆盖属性 ``` 3. **线程安全保证** 采用ConcurrentHashMap实现缓存,确保多线程环境下合并操作的正确性: ```java private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<>(256); ``` --- #### 二、典型使用场景 1. **父子Bean定义场景** 当配置中存在`<bean parent="...">`声明时,Spring必须合并父子定义生成最终配置: ```xml <!-- Bean定义 --> <bean id="parent" abstract="true" class="com.example.Parent" init-method="initBase"/> <!-- Bean定义 --> <bean id="child" parent="parent" init-method="initChild"/> <!-- 合并后init-method为initChild --> ``` 2. **注解驱动的配置合并** 使用`@Bean`注解方法生成Bean定义时,Spring自动合并类级别注解与方法级别配置: ```java @Configuration class AppConfig { @Bean(initMethod = "customInit") @Scope("prototype") public Service service() { // 合并类注解与方法配置 return new ServiceImpl(); } } ``` 3. **Bean后处理器干预** 在`BeanFactoryPostProcessor`阶段修改Bean定义时,必须基于合并后的定义进行操作: ```java public class CustomPostProcessor implements BeanFactoryPostProcessor { public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { RootBeanDefinition mergedDef = beanFactory.getMergedBeanDefinition("user"); mergedDef.getPropertyValues().add("role", "ADMIN"); // 操作合并后的定义[^3] } } ``` --- #### 三、合并过程的技术细节 1. **属性覆盖策略** Spring采用深度合并策略,对集合类属性(如`List`/`Map`)进行内容合并而非简单覆盖: ```java // 合并策略示例 mergedBd.getPropertyValues().addPropertyValues(childBd.getPropertyValues()); ``` 2. **元数据保留机制** 合并后的RootBeanDefinition会保留原始BeanDefinition的源信息,用于: - AOP代理生成时的配置检查 - 事件监听器解析 - 条件注解处理[^4] 3. **缓存失效策略** 当检测到Bean定义变更时(如通过`refresh()`重置容器),自动清空相关缓存: ```java public void clearMetadataCache() { this.mergedBeanDefinitions.clear(); } ``` --- #### 四、性能优化启示 1. **避免过度继承** 虽然父子Bean定义能提高配置复用性,但过多层级会导致: - 合并操作时间成本增加 - 缓存内存占用升高 2. **合理使用原型作用域** 原型Bean的每次获取都会触发合并检查,高频访问时建议: - 使用`@Scope(proxyMode=...)`优化 - 结合ObjectProvider延迟获取[^4] --- --相关问题--: 1. 如何通过编程方式修改已合并的Bean定义? 2. Spring如何解决合并过程中的循环依赖问题? 3. 合并后的Bean定义与原始定义在AOP处理中有何差异?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值