引言
Spring框架的魅力在于其强大的扩展机制,而BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor作为最底层的扩展点,直接掌控着Bean定义的解析、注册与修改流程。本文将结合完整的模拟Spring容器初始化案例,深入剖析这两个后处理器的底层实现原理,揭示Spring如何通过它们完成从类扫描、配置解析到Bean注册的生命周期管理。
一、Spring容器的核心架构:BeanFactory与BeanDefinitionRegistry
要理解后处理器的作用,首先需要明确Spring容器的核心组件:BeanFactory和BeanDefinitionRegistry。
1.1 BeanFactory:Bean的“工厂”
BeanFactory是Spring容器的核心接口,负责管理Bean的生命周期。其默认实现DefaultListableBeanFactory包含以下关键组件:
- BeanDefinitionMap:存储所有Bean的定义(
BeanDefinition对象),记录Bean的类型、作用域、依赖关系等元数据。 - BeanDefinitionRegistry:提供注册、删除、查询Bean定义的接口(
DefaultListableBeanFactory实现了此接口)。 - 后处理器集合:存储
BeanPostProcessor、BeanFactoryPostProcessor等扩展点,用于干预Bean的创建过程。
1.2 BeanDefinition:Bean的“设计图”
BeanDefinition是Bean的元数据描述,包含以下核心信息:
beanClass:Bean的Java类型(如BeanImitateA.class)。scope:作用域(singleton、prototype等)。constructorArguments:构造方法参数。initMethodName/destroyMethodName:初始化/销毁方法名。factoryBeanName/factoryMethodName:工厂Bean名称和工厂方法名(用于@Bean方法)。
关键结论:Spring容器的本质是“根据BeanDefinition创建和管理Bean实例的工厂”,而后处理器的作用是在这个过程中动态修改或扩展BeanDefinition。
二、BeanFactoryPostProcessor:修改Bean定义的“编辑器”
2.1 执行时机:Bean定义解析完成后
BeanFactoryPostProcessor的执行时机在refresh()方法的invokeBeanFactoryPostProcessors(beanFactory)阶段,此时:
- 所有
BeanDefinition已被加载到BeanDefinitionRegistry(如@Component、@Bean注解的类已被解析)。 - 但尚未实例化任何Bean(实例化发生在
finishBeanFactoryInitialization阶段)。
2.2 核心职责:修改现有BeanDefinition
BeanFactoryPostProcessor允许开发者:
- 解析自定义注解(如
@MyConfiguration)并生成额外的BeanDefinition。 - 修改现有
BeanDefinition的属性(如作用域、依赖关系)。 - 动态调整Bean的作用域(如将单例改为原型)。
2.3 源码级实现:ConfigurationClassPostProcessor的启示
Spring内置的ConfigurationClassPostProcessor是最典型的BeanFactoryPostProcessor,其核心逻辑如下(简化自Spring源码):
public class ConfigurationClassPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 1. 扫描所有被@Configuration标记的类(配置类)
Set<BeanDefinition> configCandidates = beanFactory.getBeanDefinitions().stream()
.filter(def -> ClassUtils.isPresent(def.getBeanClassName(), beanFactory.getBeanClassLoader()))
.filter(def -> ConfigurationClassUtils.checkConfigurationClassCandidate(def, beanFactory.getConfigurationAnnotations()))
.collect(Collectors.toSet());
// 2. 解析配置类中的@Bean方法、@ComponentScan等注解
for (BeanDefinition configDef : configCandidates) {
String configClassName = configDef.getBeanClassName();
try {
// 加载配置类元数据
Class<?> configClass = beanFactory.getBeanClassLoader().loadClass(configClassName);
ConfigurationClass config = new ConfigurationClass(configClass, configClassName);
// 处理@ComponentScan注解(触发组件扫描)
processComponentScan(config, beanFactory);
// 处理@Bean方法(生成BeanDefinition)
processBeanMethods(config, beanFactory);
} catch (ClassNotFoundException e) {
throw new BeanDefinitionStoreException("无法加载配置类:" + configClassName, e);
}
}
}
private void processComponentScan(ConfigurationClass config, ConfigurableListableBeanFactory beanFactory) {
// 解析@ComponentScan的basePackages,触发组件扫描逻辑(类似本文的ComponentScanPostProcessorCase)
}
private void processBeanMethods(ConfigurationClass config, ConfigurableListableBeanFactory beanFactory) {
// 解析@Bean方法,生成BeanDefinition(类似本文的BeanPostProcessorCase)
}
}
关键逻辑:ConfigurationClassPostProcessor通过解析配置类的元数据,将@Bean方法转换为BeanDefinition,并将@ComponentScan路径转换为组件扫描任务。这一过程为后续的组件扫描和@Bean方法注册奠定了基础。
三、BeanDefinitionRegistryPostProcessor:动态注册Bean的“工厂”
3.1 执行时机:Bean定义注册阶段
BeanDefinitionRegistryPostProcessor是BeanFactoryPostProcessor的子接口,额外提供了postProcessBeanDefinitionRegistry方法。其执行时机在BeanFactoryPostProcessor之前(更早介入Bean定义阶段),允许:
- 动态注册新的
BeanDefinition(如手动扫描的组件、Mapper接口)。 - 修改或删除已存在的
BeanDefinition(需谨慎使用)。
3.2 核心职责:动态扩展Bean定义
与BeanFactoryPostProcessor只能修改现有BeanDefinition不同,BeanDefinitionRegistryPostProcessor可以直接操作BeanDefinitionRegistry,实现:
- 手动注册第三方库的Bean(如MyBatis Mapper)。
- 动态生成配置类(如根据数据库表生成DAO)。
- 替换默认的Bean定义(如覆盖
DataSource的默认配置)。
3.3 源码级实现:组件扫描的底层逻辑
以本文的ComponentScanPostProcessorCase为例,模拟@ComponentScan的底层实现:
/**
* 手动模拟 @ComponentScan 注解的组件扫描逻辑
* <p>
* Spring @ComponentScan 核心实现:
* 1. ComponentScanAnnotationParser 解析 @ComponentScan 注解的参数(basePackages、includeFilters 等)
* 2. ClassPathBeanDefinitionScanner 执行扫描(基于解析的参数)
* 3. 扫描过程中,使用 ClassMetadata 判断类是否符合条件(如是否被 @Component 标记)
* 4. 符合条件的类会被封装为 BeanDefinition,并注册到 BeanDefinitionRegistry
*/
static class ComponentScanPostProcessorCase implements BeanDefinitionRegistryPostProcessor {
/**
* 在 Bean 定义注册阶段,模拟 @ComponentScan 扫描组件并注册 BeanDefinition
* <p>
* 关键底层步骤:
* 1. 解析 @ComponentScan 注解:获取 basePackages、includeFilters、excludeFilters 等参数
* 2. 资源定位:根据 basePackages 生成类路径资源模式 (如 classpath*:com/xxx/*.class)
* 3. 资源扫描:使用 PathMatchingResourcePatternResolver 扫描所有匹配的资源
* 4. 元数据读取:使用 CachingMetadataReaderFactory 读取每个资源的类元数据
* 5. 组件过滤:通过 AnnotationMetadata 判断类是否被 @Component 或其派生注解标记
* 6. BeanDefinition 构建:为符合条件的类生成 BeanDefinition(默认作用域为单例)
* 7. Bean 名称生成:使用 AnnotationBeanNameGenerator 生成(类名首字母小写,或 @Component(name=...) 指定)
* 8. 注册 BeanDefinition:将生成的 BeanDefinition 存入 BeanDefinitionRegistry
*
* @param beanFactory Bean 定义注册中心
*/
@Override // context.refresh();
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
log.info("[ComponentScanPostProcessorCase] 开始执行组件扫描...");
try {
// 1. 定位被 @ComponentScan 标记的配置类(示例:ImitateConfig)
Class<?> configClass = ImitateConfig.class;
log.info("[ComponentScanPostProcessorCase] 处理配置类:{}", configClass.getName());
// 2. 解析 @ComponentScan 注解的 basePackages(示例:com.dwl.bean_factory_post_processor.imitate)
ComponentScan componentScan = AnnotationUtils.findAnnotation(configClass, ComponentScan.class);
if (componentScan == null || componentScan.basePackages().length == 0) {
log.warn("[ComponentScanPostProcessorCase] 未找到 @ComponentScan 注解或 basePackages 配置");
return;
}
String[] basePackages = componentScan.basePackages();
log.info("[ComponentScanPostProcessorCase] 扫描包路径:{}", String.join(",", basePackages));
// 3. 初始化类路径扫描器(使用 AnnotationBeanNameGenerator 生成 Bean 名称)
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
AnnotationBeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
// 4. 遍历每个包路径,扫描类文件
for (String basePackage : basePackages) {
String resourcePattern = "classpath*:" + basePackage.replace('.', '/') + "/**/*.class";
log.info("[ComponentScanPostProcessorCase] 扫描包 {} 对应的资源模式:{}", basePackage, resourcePattern);
// 5. 扫描类路径资源
Resource[] resources = new PathMatchingResourcePatternResolver()
.getResources(resourcePattern);
log.info("[ComponentScanPostProcessorCase] 包 {} 扫描到 {} 个类文件资源", basePackage, resources.length);
// 6. 检查每个类是否为组件(@Component 或其派生注解)
for (Resource resource : resources) {
MetadataReader reader = factory.getMetadataReader(resource);
ClassMetadata classMetadata = reader.getClassMetadata();
String className = classMetadata.getClassName();
// 6.1 判断是否包含 @Component 或其派生注解(如 @Service、@Repository)
// 注:@Component 是根注解,@Service 等是其派生注解(通过 @Component 元注解)
boolean isComponent = reader.getAnnotationMetadata()
.hasAnnotation(Component.class.getName())
|| reader.getAnnotationMetadata()
.hasMetaAnnotation(Component.class.getName()); // 检查元注解
if (!isComponent) {
log.info("[ComponentScanPostProcessorCase] 跳过非组件类:{}", className);
continue;
}
// 7. 生成 BeanDefinition(默认作用域为单例,无作用域注解时)
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
.genericBeanDefinition(classMetadata.getClassName())
.getBeanDefinition();
log.info("[ComponentScanPostProcessorCase] 生成 BeanDefinition:{}", className);
// 8. 生成 Bean 名称(默认规则:类名首字母小写)
String beanName = beanNameGenerator.generateBeanName(beanDefinition, beanFactory);
log.info("[ComponentScanPostProcessorCase] 生成 Bean 名称:{}(对应类:{})", beanName, className);
// 9. 注册 BeanDefinition(核心操作)
beanFactory.registerBeanDefinition(beanName, beanDefinition);
log.info("[ComponentScanPostProcessorCase] 注册组件 Bean:{}", beanName);
}
}
} catch (Exception e) {
throw new RuntimeException("组件扫描或注册失败", e);
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 无需实现(当前场景无需修改 BeanFactory)
}
}
关键步骤解析:
- 资源加载:
PathMatchingResourcePatternResolver负责将包路径转换为类路径资源模式(如classpath*:com/dwl/.../**/*.class),并加载所有匹配的.class文件。 - 元数据读取:
CachingMetadataReaderFactory通过缓存类元数据(如类的注解、方法、字段)避免重复IO,提升性能。 - 组件过滤:通过
ClassMetadata和AnnotationMetadata判断类是否被@Component或其派生注解(如@Service)标记。 - Bean定义生成:使用
BeanDefinitionBuilder构建BeanDefinition,默认作用域为单例(SCOPE_SINGLETON)。 - Bean名称生成:
AnnotationBeanNameGenerator根据类名生成默认Bean名称(首字母小写),或使用@Component(name="xxx")指定的名称。
四、@Bean方法的解析与注册:ConfigurationClassPostProcessor的深层逻辑
4.1 @Bean方法的底层处理流程
Spring处理@Bean方法的流程由ConfigurationClassPostProcessor主导,核心步骤如下(结合本文BeanPostProcessorCase案例):
4.1.1 识别配置类
被@Configuration或@Component标记的类会被识别为配置类。配置类的特点是:
- 可以包含
@Bean方法。 - 支持方法级依赖注入(
@Bean方法之间可相互调用,返回单例)。 - 支持
@PostConstruct、InitializingBean等生命周期回调。
4.1.2 解析@Bean方法
通过MetadataReader读取配置类的元数据,获取所有被@Bean标记的方法:
// 伪代码:解析配置类的@Bean方法
Set<MethodMetadata> beanMethods = reader.getAnnotationMetadata().getAnnotatedMethods(Bean.class.getName());
4.1.3 生成BeanDefinition
为每个@Bean方法生成BeanDefinition,关键属性包括:
beanClass:方法的返回类型(如BeanImitateA.class)。factoryBeanName:配置类的名称(如"beanImitateConfig")。factoryMethodName:@Bean方法的名称(如"beanImitateA")。scope:方法上的@Scope注解值(默认singleton)。initMethodName:方法上的@Bean(initMethod="xxx")指定的初始化方法。
示例:对于BeanImitateConfig中的beanImitateA()方法,生成的BeanDefinition如下:
// 4.1 构建 BeanDefinition(工厂方法为当前 @Bean 方法,工厂 Bean 为配置类)
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
.genericBeanDefinition()
.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR)
.setFactoryMethodOnBean(method.getMethodName(), "beanImitateConfig") // 工厂方法:配置类的 @Bean 方法
.getBeanDefinition();
4.1.4 注册BeanDefinition
将生成的BeanDefinition注册到BeanDefinitionRegistry,后续容器刷新时会实例化这些Bean。
五、Mapper接口的手动注册:MyBatis与Spring整合的底层原理
5.1 MapperFactoryBean的作用
MyBatis与Spring整合的核心是将Mapper接口绑定到SqlSessionFactory,这一过程通过MapperFactoryBean实现。MapperFactoryBean是FactoryBean的实现类,负责:
- 获取
SqlSessionFactory(通过依赖注入)。 - 为Mapper接口生成代理对象(JDK动态代理或CGLIB)。
- 代理对象将方法调用转发给
SqlSession执行SQL。
5.2 自定义后处理器模拟Mapper扫描
本文的MapperPostProcessorCase模拟了MyBatis的MapperScannerConfigurer,核心逻辑如下:
5.2.1 扫描Mapper包
通过ClassPathResourcePatternResolver加载指定包路径下的所有类文件:
String basePackage = "com.dwl.bean_factory_post_processor.mapper_imitate.mapper";
String resourcePattern = "classpath*:" + basePackage.replace('.', '/') + "/**/*.class";
Resource[] resources = new PathMatchingResourcePatternResolver().getResources(resourcePattern);
5.2.2 过滤Mapper接口
通过ClassMetadata判断类是否为接口:
ClassMetadata classMetadata = reader.getClassMetadata();
if (!classMetadata.isInterface()) {
continue; // 跳过非接口类
}
5.2.3 生成MapperFactoryBean的BeanDefinition
为每个Mapper接口生成MapperFactoryBean的BeanDefinition,并注册到容器:
// 5. 构建 MapperFactoryBean 的 BeanDefinition
AbstractBeanDefinition mapperBeanDefinition = BeanDefinitionBuilder
.genericBeanDefinition(MapperFactoryBean.class)
.addConstructorArgValue(className) // 构造参数:Mapper 接口类(用于生成代理)
.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE) // 自动注入 SqlSessionFactory
.getBeanDefinition();
// 6. 生成 Bean 名称(默认规则:接口名首字母小写)
String beanName = className.substring(0, 1).toLowerCase() + className.substring(1);
log.info("[MapperPostProcessorCase] 生成 Bean 名称:{}(对应接口:{})", beanName, className);
// 7. 注册 BeanDefinition(核心操作:将 BeanDefinition 存入 BeanDefinitionRegistry)
registry.registerBeanDefinition(beanName, mapperBeanDefinition);
log.info("[MapperPostProcessorCase] 成功注册 Mapper Bean:{} -> {}", beanName, className);
5.2.4 容器刷新时的代理生成
当容器实例化MapperFactoryBean时,会调用其getObject()方法生成Mapper代理:
public class MapperFactoryBean<T> implements FactoryBean<T> {
private final Class<T> mapperInterface;
@Override
public T getObject() {
return sqlSessionFactory.getConfiguration().getMapper(mapperInterface, this);
}
// ... 其他方法(设置SqlSessionFactory等)
}
关键结论:通过自定义后处理器手动注册Mapper接口,本质上是模拟了MyBatis的MapperScannerConfigurer,将Mapper接口转换为FactoryBean,最终生成代理对象。
六、实战验证:完整容器初始化流程
通过本文开头的BeanFactoryPostProcessorCase主方法,我们可以验证各后处理器的执行效果:
6.1 场景1:基础容器 + Mapper扫描
// 注册核心后处理器:负责解析 @Configuration、@ComponentScan、@Bean 等注解
context.registerBean(ConfigurationClassPostProcessor.class);
log.info("[场景1] 4. 注册 ConfigurationClassPostProcessor → 后处理器列表新增该实例");
// 手动注册 Mapper 扫描器(模拟 Spring Boot 自动配置的 MapperScannerConfigurer)
context.registerBean(MapperScannerConfigurer.class,
db -> db.getPropertyValues().add("basePackage", "com.dwl.bean_factory_post_processor.convention.mapper"));
log.info("[场景1] 5. 注册 MapperScannerConfigurer → 用于扫描 @Mapper 接口并注册 MapperFactoryBean");
// 刷新容器(触发 Bean 生命周期全流程)
log.info("[场景1] 开始刷新容器...");
context.refresh(); // 核心方法:触发 BeanFactory 初始化、后处理器执行、Bean 实例化等
6.2 场景2:自定义组件扫描
log.info("\n===== 场景 2:自定义组件扫描后处理器(模拟 @ComponentScan) =====");
GenericApplicationContext context2 = new GenericApplicationContext();
context2.registerBean(ConfigurationClassPostProcessor.class); // 处理配置类的核心后处理器
context2.registerBean(ComponentScanPostProcessorCase.class); // 自定义组件扫描逻辑
context2.refresh();
6.3 场景3:手动注册@Bean方法
log.info("\n===== 场景 3:手动注册 @Bean 方法定义的 Bean(模拟 @Bean 注解处理) =====");
GenericApplicationContext context3 = new GenericApplicationContext();
context3.registerBean(ConfigurationClassPostProcessor.class); // 处理配置类
context3.registerBean("beanImitateConfig", BeanImitateConfig.class); // 包含 @Bean 方法的配置类
context3.registerBean(BeanPostProcessorCase.class); // 自定义 @Bean 方法解析后处理器
context3.refresh();
6.4 场景4:手动注册Mapper接口
log.info("\n===== 场景 4:手动注册 Mapper 接口(模拟 MyBatis 整合) =====");
GenericApplicationContext context4 = new GenericApplicationContext();
context4.registerBean(ConfigurationClassPostProcessor.class); // 处理配置类
context4.registerBean("mapperImitateConfig", MapperImitateConfig.class); // Mapper 配置类
context4.registerBean(MapperPostProcessorCase.class); // 自定义 Mapper 注册后处理器
context4.refresh();
七、总结与扩展
7.1 核心结论
- BeanFactoryPostProcessor:在Bean定义解析完成后,修改现有Bean定义(如解析
@Configuration中的@Bean方法)。 - BeanDefinitionRegistryPostProcessor:在Bean定义注册阶段,动态注册新Bean定义(如组件扫描、Mapper接口注册)。
- 组件扫描:通过
ClassPathBeanDefinitionScanner实现,核心是资源加载、元数据读取、组件过滤和Bean定义生成。 - @Bean方法解析:由
ConfigurationClassPostProcessor主导,将@Bean方法转换为BeanDefinition,工厂方法指向配置类。 - Mapper注册:通过自定义后处理器模拟
MapperScannerConfigurer,生成MapperFactoryBean的Bean定义,最终生成代理对象。
7.2 扩展思考
- 性能优化:
CachingMetadataReaderFactory通过缓存类元数据减少IO,实际开发中可借鉴此模式优化资源加载。 - 依赖注入:
@Bean方法的参数解析依赖Spring的依赖注入机制,底层通过BeanFactory的单例池实现。 - 作用域管理:Bean的作用域(单例、原型等)在
BeanDefinition中定义,实例化阶段由Scope接口实现。 - 自定义注解驱动:通过自定义后处理器,可实现类似
@Autowired的依赖注入、@PostConstruct的初始化回调等功能。
完整代码
package com.dwl.bean_factory_post_processor;
import com.dwl.bean_factory_post_processor.bean_imitate.BeanImitateConfig;
import com.dwl.bean_factory_post_processor.convention.ConventionConfig;
import com.dwl.bean_factory_post_processor.imitate.ImitateConfig;
import com.dwl.bean_factory_post_processor.mapper_imitate.MapperImitateConfig;
import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.mapper.MapperFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.MethodMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.Objects;
import java.util.Set;
/**
* @ClassName BeanFactoryPostProcessorCase
* @Description 演示 Spring 中 BeanFactoryPostProcessor 和 BeanDefinitionRegistryPostProcessor 的使用,
* 以及手动模拟 Spring 核心功能(如组件扫描、@Bean 注册、Mapper 接口绑定)的完整案例。
* <p>
* Spring 底层核心流程(贯穿所有场景):
* 1. 容器初始化阶段:
* - 创建 GenericApplicationContext → 内部初始化 DefaultListableBeanFactory(核心 BeanFactory 实现)
* - DefaultListableBeanFactory 初始化时注册大量内置后处理器(如 AutowiredAnnotationBeanPostProcessor)
* 2. 后处理器注册阶段:
* - 显式注册 ConfigurationClassPostProcessor(Spring 自动配置的核心后处理器)
* - 显式注册自定义后处理器(如 ComponentScanPostProcessorCase、BeanPostProcessorCase)
* 3. 容器刷新阶段(refresh() 方法):
* a. 准备刷新上下文(初始化环境变量、事件发布器等)
* b. 初始化 BeanFactory(设置类加载器、属性、内置后处理器)
* c. 执行 BeanFactoryPostProcessor(修改 BeanDefinition,如解析 @PropertySource)
* d. 注册 BeanDefinitionRegistryPostProcessor(动态注册 BeanDefinition,如本例中的 Mapper 扫描)
* e. 实例化所有剩余单例 Bean(按顺序:依赖注入 → 初始化 → 后置处理器)
* 4. 容器关闭阶段:
* - 销毁单例 Bean(调用销毁方法)
* - 关闭 BeanFactory(清理资源)
* @Version 1.0.0
* @Date 2025
* @Author By Dwl
*/
@Slf4j
public class BeanFactoryPostProcessorCase {
/**
* 主方法:通过 4 个场景演示 Spring 容器的不同初始化方式及底层原理
*/
public static void main(String[] args) {
/* 场景 1:基础容器 + 配置类 + Mapper 扫描(模拟 Spring Boot 自动配置) */
log.info("===== 场景 1:基础容器初始化(含 Mapper 扫描) =====");
GenericApplicationContext context = new GenericApplicationContext();
log.info("[场景1] 1. 创建 GenericApplicationContext,内部初始化 DefaultListableBeanFactory");
log.info("[场景1] - BeanFactory 类型:{}", context.getBeanFactory().getClass()); // 输出:class org.springframework.beans.factory.support.DefaultListableBeanFactory
log.info("[场景1] 2. 初始状态:beanDefinitionCount={}, singletonCount={}",
context.getBeanFactory().getBeanDefinitionCount(), context.getBeanFactory().getSingletonCount()); // 均为 0
// 注册配置类(会被 ConfigurationClassPostProcessor 处理)
context.registerBean(ConventionConfig.class);
log.info("[场景1] 3. 注册 ConventionConfig 配置类 → BeanDefinition 已加入 beanDefinitionMap");
// 注册核心后处理器:负责解析 @Configuration、@ComponentScan、@Bean 等注解
context.registerBean(ConfigurationClassPostProcessor.class);
log.info("[场景1] 4. 注册 ConfigurationClassPostProcessor → 后处理器列表新增该实例");
// 手动注册 Mapper 扫描器(模拟 Spring Boot 自动配置的 MapperScannerConfigurer)
context.registerBean(MapperScannerConfigurer.class,
db -> db.getPropertyValues().add("basePackage", "com.dwl.bean_factory_post_processor.convention.mapper"));
log.info("[场景1] 5. 注册 MapperScannerConfigurer → 用于扫描 @Mapper 接口并注册 MapperFactoryBean");
// 刷新容器(触发 Bean 生命周期全流程)
log.info("[场景1] 开始刷新容器...");
context.refresh(); // 核心方法:触发 BeanFactory 初始化、后处理器执行、Bean 实例化等
log.info("[场景1] 容器刷新完成,当前 Bean 定义列表(部分):");
Arrays.stream(context.getBeanDefinitionNames())
.filter(name -> name.contains("Convention") || name.contains("Mapper"))
.forEach(name -> log.info(" - {}", name));
context.close();
log.info("[场景1] 容器已关闭,清理所有 Bean 实例和资源");
/* 场景 2:仅注册 ConfigurationClassPostProcessor 和自定义组件扫描后处理器 */
log.info("\n===== 场景 2:自定义组件扫描后处理器(模拟 @ComponentScan) =====");
GenericApplicationContext context2 = new GenericApplicationContext();
context2.registerBean(ConfigurationClassPostProcessor.class); // 处理配置类的核心后处理器
context2.registerBean(ComponentScanPostProcessorCase.class); // 自定义组件扫描逻辑
context2.refresh();
log.info("[场景2] 容器刷新完成,扫描到的组件 Bean 列表:");
Arrays.stream(context2.getBeanDefinitionNames())
.filter(name -> name.startsWith("imitateBean")) // 过滤 ImitateBean 相关 Bean
.forEach(name -> log.info(" - {}", name));
context2.close();
/* 场景 3:手动通过 BeanDefinition 注册 @Bean 方法定义的 Bean */
log.info("\n===== 场景 3:手动注册 @Bean 方法定义的 Bean(模拟 @Bean 注解处理) =====");
GenericApplicationContext context3 = new GenericApplicationContext();
context3.registerBean(ConfigurationClassPostProcessor.class); // 处理配置类
context3.registerBean("beanImitateConfig", BeanImitateConfig.class); // 包含 @Bean 方法的配置类
context3.registerBean(BeanPostProcessorCase.class); // 自定义 @Bean 方法解析后处理器
context3.refresh();
log.info("[场景3] 容器刷新完成,@Bean 方法注册的 Bean 列表:");
Arrays.stream(context3.getBeanDefinitionNames())
.filter(name -> name.startsWith("beanImitate")) // 过滤 beanImitate 相关 Bean
.forEach(name -> log.info(" - {}", name));
context3.close();
/* 场景 4:手动注册 Mapper 接口的 BeanDefinition(模拟 MyBatis Mapper 扫描) */
log.info("\n===== 场景 4:手动注册 Mapper 接口(模拟 MyBatis 整合) =====");
GenericApplicationContext context4 = new GenericApplicationContext();
context4.registerBean(ConfigurationClassPostProcessor.class); // 处理配置类
context4.registerBean("mapperImitateConfig", MapperImitateConfig.class); // Mapper 配置类
context4.registerBean(MapperPostProcessorCase.class); // 自定义 Mapper 注册后处理器
context4.refresh();
log.info("[场景4] 容器刷新完成,Mapper 接口注册的 Bean 列表:");
Arrays.stream(context4.getBeanDefinitionNames())
.filter(name -> name.endsWith("Mapper")) // 过滤 Mapper 相关 Bean
.forEach(name -> log.info(" - {}", name));
context4.close();
}
/**
* 手动注册 Mapper 接口的 BeanDefinition(模拟 MyBatis Mapper 扫描逻辑)
* <p>
* MyBatis 整合 Spring 的核心原理:
* 1. MapperScannerConfigurer(实现 BeanDefinitionRegistryPostProcessor)在容器刷新时被触发
* 2. 扫描指定包下的所有 @Mapper 接口(通过类路径资源扫描)
* 3. 为每个接口生成 MapperFactoryBean 的 BeanDefinition(MapperFactoryBean 是 Spring 的 FactoryBean 实现)
* 4. MapperFactoryBean 在实例化时会通过 SqlSessionFactory 创建 Mapper 接口的代理对象(JDK 动态代理或 CGLIB)
* 5. 代理对象会将方法调用转发给 SqlSession 的对应方法(最终执行 SQL)
*/
static class MapperPostProcessorCase implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
log.info("[MapperPostProcessorCase] 开始扫描 Mapper 接口...");
try {
// 1. 定义扫描路径(示例:com.dwl.bean_factory_post_processor.mapper_imitate.mapper)
String basePackage = "com.dwl.bean_factory_post_processor.mapper_imitate.mapper";
String resourcePattern = "classpath*:" + basePackage.replace('.', '/') + "/**/*.class";
log.info("[MapperPostProcessorCase] 扫描路径转换为资源模式:{}", resourcePattern);
// 2. 扫描类路径资源(PathMatchingResourcePatternResolver 是 Spring 内置的资源解析器)
Resource[] resources = new PathMatchingResourcePatternResolver()
.getResources(resourcePattern);
log.info("[MapperPostProcessorCase] 扫描到 {} 个类文件资源", resources.length);
// 3. 使用 CachingMetadataReaderFactory 缓存类元数据(提升性能,避免重复解析)
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
log.info("[MapperPostProcessorCase] 使用 CachingMetadataReaderFactory 缓存类元数据(默认缓存大小无限制)");
// 4. 遍历资源,解析类元信息
for (Resource resource : resources) {
// 4.1 读取类元数据(MetadataReader 是 Spring 提供的类元信息读取接口)
MetadataReader reader = factory.getMetadataReader(resource);
ClassMetadata classMetadata = reader.getClassMetadata();
String className = classMetadata.getClassName();
log.info("[MapperPostProcessorCase] 处理类:{}", className);
// 4.2 过滤条件:必须是接口(@Mapper 接口是接口,而非类)
if (!classMetadata.isInterface()) {
log.info("[MapperPostProcessorCase] 跳过非接口类:{}", className);
continue;
}
// 4.3 检查是否包含 @Mapper 注解(或通过其他方式判断,如 MyBatis 的 @MapperScan 注解)
// 注:实际 MyBatis 中通过 MapperRegistry 扫描 @Mapper 接口,此处简化为直接判断接口
log.info("[MapperPostProcessorCase] 发现 @Mapper 接口:{}", className);
// 5. 构建 MapperFactoryBean 的 BeanDefinition
AbstractBeanDefinition mapperBeanDefinition = BeanDefinitionBuilder
.genericBeanDefinition(MapperFactoryBean.class)
.addConstructorArgValue(className) // 构造参数:Mapper 接口类(用于生成代理)
.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE) // 自动注入 SqlSessionFactory
.getBeanDefinition();
// 6. 生成 Bean 名称(默认规则:接口名首字母小写)
String beanName = className.substring(0, 1).toLowerCase() + className.substring(1);
log.info("[MapperPostProcessorCase] 生成 Bean 名称:{}(对应接口:{})", beanName, className);
// 7. 注册 BeanDefinition(核心操作:将 BeanDefinition 存入 BeanDefinitionRegistry)
registry.registerBeanDefinition(beanName, mapperBeanDefinition);
log.info("[MapperPostProcessorCase] 成功注册 Mapper Bean:{} -> {}", beanName, className);
}
} catch (Exception e) {
throw new RuntimeException("扫描或注册 Mapper 接口失败", e);
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 无需实现(当前场景仅需注册 BeanDefinition,无需修改 BeanFactory)
}
}
/**
* 手动注册 @Bean 方法定义的 Bean(模拟 @Bean 注解的处理逻辑)
* <p>
* Spring 处理 @Bean 的核心流程:
* 1. ConfigurationClassPostProcessor 扫描所有 @Configuration 配置类
* 2. 对每个配置类,解析其 @Bean 方法(通过反射或元数据读取)
* 3. 为每个 @Bean 方法生成对应的 BeanDefinition(工厂方法为 @Bean 方法,工厂 Bean 为配置类本身)
* 4. 将生成的 BeanDefinition 注册到 BeanDefinitionRegistry
* 5. 容器刷新时,实例化这些 Bean(调用配置类的 @Bean 方法,依赖注入参数)
*/
static class BeanPostProcessorCase implements BeanDefinitionRegistryPostProcessor {
/**
* 在 Bean 定义注册阶段,手动解析 @Bean 方法并注册 BeanDefinition
* <p>
* 关键底层步骤:
* 1. 定位配置类:通过类路径或显式注册的配置类(如 BeanImitateConfig)
* 2. 读取类元数据:使用 MetadataReader 读取配置类的类信息
* 3. 解析 @Bean 方法:通过 AnnotationMetadata 获取所有被 @Bean 标记的方法
* 4. 构建 BeanDefinition:为每个 @Bean 方法生成对应的 BeanDefinition
* 5. 注册 BeanDefinition:将 BeanDefinition 存入容器
*
* @param beanFactory Bean 定义注册中心
*/
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
log.info("[BeanPostProcessorCase] 开始解析 @Bean 方法...");
try {
// 1. 定位配置类(示例:BeanImitateConfig)
Class<?> configClass = BeanImitateConfig.class;
log.info("[BeanPostProcessorCase] 处理配置类:{}", configClass.getName());
// 2. 读取类元数据(使用 CachingMetadataReaderFactory 缓存元数据)
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
MetadataReader reader = factory.getMetadataReader(new ClassPathResource(
configClass.getName().replace('.', '/') + ".class"));
ClassMetadata classMetadata = reader.getClassMetadata();
log.info("[BeanPostProcessorCase] 配置类元数据:类名={}, 是否接口={}",
classMetadata.getClassName(), classMetadata.isInterface());
// 3. 获取所有 @Bean 方法的元信息(@Bean 注解的全限定名)
Set<MethodMetadata> beanMethods = reader.getAnnotationMetadata()
.getAnnotatedMethods(Bean.class.getName());
log.info("[BeanPostProcessorCase] 发现 {} 个 @Bean 方法", beanMethods.size());
// 4. 遍历 @Bean 方法,生成并注册 BeanDefinition
for (MethodMetadata method : beanMethods) {
log.info("[BeanPostProcessorCase] 处理 @Bean 方法:{}", method.getMethodName());
// 4.1 构建 BeanDefinition(工厂方法为当前 @Bean 方法,工厂 Bean 为配置类)
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
.genericBeanDefinition()
.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR)
.setFactoryMethodOnBean(method.getMethodName(), "beanImitateConfig") // 工厂方法:配置类的 @Bean 方法
.getBeanDefinition();
// 4.2 处理初始化方法(@Bean(initMethod = "xxx"))
String initMethod = Objects.requireNonNull(method.getAnnotationAttributes(Bean.class.getName()))
.get("initMethod").toString();
if (!initMethod.isEmpty()) {
beanDefinition.setInitMethodName(initMethod);
log.info("[BeanPostProcessorCase] 设置初始化方法:{}", initMethod);
}
// 4.3 注册 BeanDefinition(Bean 名称为方法名)
beanFactory.registerBeanDefinition(method.getMethodName(), beanDefinition);
log.info("[BeanPostProcessorCase] 注册 @Bean 方法定义的 Bean:{}", method.getMethodName());
}
} catch (Exception e) {
throw new RuntimeException("解析或注册 @Bean 方法失败", e);
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 无需实现(当前场景无需修改 BeanFactory)
}
}
/**
* 手动模拟 @ComponentScan 注解的组件扫描逻辑
* <p>
* Spring @ComponentScan 核心实现:
* 1. ComponentScanAnnotationParser 解析 @ComponentScan 注解的参数(basePackages、includeFilters 等)
* 2. ClassPathBeanDefinitionScanner 执行扫描(基于解析的参数)
* 3. 扫描过程中,使用 ClassMetadata 判断类是否符合条件(如是否被 @Component 标记)
* 4. 符合条件的类会被封装为 BeanDefinition,并注册到 BeanDefinitionRegistry
*/
static class ComponentScanPostProcessorCase implements BeanDefinitionRegistryPostProcessor {
/**
* 在 Bean 定义注册阶段,模拟 @ComponentScan 扫描组件并注册 BeanDefinition
* <p>
* 关键底层步骤:
* 1. 解析 @ComponentScan 注解:获取 basePackages、includeFilters、excludeFilters 等参数
* 2. 资源定位:根据 basePackages 生成类路径资源模式 (如 classpath*:com/xxx/*.class)
* 3. 资源扫描:使用 PathMatchingResourcePatternResolver 扫描所有匹配的资源
* 4. 元数据读取:使用 CachingMetadataReaderFactory 读取每个资源的类元数据
* 5. 组件过滤:通过 AnnotationMetadata 判断类是否被 @Component 或其派生注解标记
* 6. BeanDefinition 构建:为符合条件的类生成 BeanDefinition(默认作用域为单例)
* 7. Bean 名称生成:使用 AnnotationBeanNameGenerator 生成(类名首字母小写,或 @Component(name=...) 指定)
* 8. 注册 BeanDefinition:将生成的 BeanDefinition 存入 BeanDefinitionRegistry
*
* @param beanFactory Bean 定义注册中心
*/
@Override // context.refresh();
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
log.info("[ComponentScanPostProcessorCase] 开始执行组件扫描...");
try {
// 1. 定位被 @ComponentScan 标记的配置类(示例:ImitateConfig)
Class<?> configClass = ImitateConfig.class;
log.info("[ComponentScanPostProcessorCase] 处理配置类:{}", configClass.getName());
// 2. 解析 @ComponentScan 注解的 basePackages(示例:com.dwl.bean_factory_post_processor.imitate)
ComponentScan componentScan = AnnotationUtils.findAnnotation(configClass, ComponentScan.class);
if (componentScan == null || componentScan.basePackages().length == 0) {
log.warn("[ComponentScanPostProcessorCase] 未找到 @ComponentScan 注解或 basePackages 配置");
return;
}
String[] basePackages = componentScan.basePackages();
log.info("[ComponentScanPostProcessorCase] 扫描包路径:{}", String.join(",", basePackages));
// 3. 初始化类路径扫描器(使用 AnnotationBeanNameGenerator 生成 Bean 名称)
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
AnnotationBeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
// 4. 遍历每个包路径,扫描类文件
for (String basePackage : basePackages) {
String resourcePattern = "classpath*:" + basePackage.replace('.', '/') + "/**/*.class";
log.info("[ComponentScanPostProcessorCase] 扫描包 {} 对应的资源模式:{}", basePackage, resourcePattern);
// 5. 扫描类路径资源
Resource[] resources = new PathMatchingResourcePatternResolver()
.getResources(resourcePattern);
log.info("[ComponentScanPostProcessorCase] 包 {} 扫描到 {} 个类文件资源", basePackage, resources.length);
// 6. 检查每个类是否为组件(@Component 或其派生注解)
for (Resource resource : resources) {
MetadataReader reader = factory.getMetadataReader(resource);
ClassMetadata classMetadata = reader.getClassMetadata();
String className = classMetadata.getClassName();
// 6.1 判断是否包含 @Component 或其派生注解(如 @Service、@Repository)
// 注:@Component 是根注解,@Service 等是其派生注解(通过 @Component 元注解)
boolean isComponent = reader.getAnnotationMetadata()
.hasAnnotation(Component.class.getName())
|| reader.getAnnotationMetadata()
.hasMetaAnnotation(Component.class.getName()); // 检查元注解
if (!isComponent) {
log.info("[ComponentScanPostProcessorCase] 跳过非组件类:{}", className);
continue;
}
// 7. 生成 BeanDefinition(默认作用域为单例,无作用域注解时)
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
.genericBeanDefinition(classMetadata.getClassName())
.getBeanDefinition();
log.info("[ComponentScanPostProcessorCase] 生成 BeanDefinition:{}", className);
// 8. 生成 Bean 名称(默认规则:类名首字母小写)
String beanName = beanNameGenerator.generateBeanName(beanDefinition, beanFactory);
log.info("[ComponentScanPostProcessorCase] 生成 Bean 名称:{}(对应类:{})", beanName, className);
// 9. 注册 BeanDefinition(核心操作)
beanFactory.registerBeanDefinition(beanName, beanDefinition);
log.info("[ComponentScanPostProcessorCase] 注册组件 Bean:{}", beanName);
}
}
} catch (Exception e) {
throw new RuntimeException("组件扫描或注册失败", e);
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 无需实现(当前场景无需修改 BeanFactory)
}
}
}
package com.dwl.bean_factory_post_processor.bean_imitate;
import lombok.extern.slf4j.Slf4j;
/**
* @ClassName ImitateBeanA
* @Description 普通 Java 类(未被 @Component 标记),但通过 BeanImitateConfig 的 @Bean 方法注册为 Bean
* <p>
* Spring 中 Bean 的生命周期(以本类为例):
* 1. 实例化(Instantiation):调用无参构造方法创建对象(BeanImitateA())
* 2. 属性赋值(Populate Properties):无依赖注入(本类无字段)
* 3. 初始化(Initialization):
* a. @PostConstruct 注解方法(本类未使用)
* b. 实现 InitializingBean 接口的 afterPropertiesSet() 方法(本类未实现)
* c. 自定义初始化方法(本类未定义)
* 4. 就绪(Ready):Bean 被放入单例池,可供其他 Bean 注入使用
* 5. 销毁(Destruction):容器关闭时调用(本类未定义销毁方法)
* @Version 1.0.0
* @Date 2025
* @Author By Dwl
*/
@Slf4j
public class BeanImitateA {
public BeanImitateA() {
log.info("BeanImitateA 构造方法被调用(实例化阶段)");
}
// 示例:初始化方法(若通过 @Bean(initMethod = "init") 声明,会在属性赋值后调用)
public void init() {
log.info("BeanImitateA.init() 方法被调用(初始化阶段)");
}
}
package com.dwl.bean_factory_post_processor.bean_imitate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* @ClassName BeanImitateB
* @Description 被 @Component 标记的类(会被组件扫描自动注册为 Bean)
* <p>
* @Component 是 Spring 组件注解的根注解,其派生注解(@Service、@Repository、@Controller)语义相同,
* 仅用于区分业务场景。Spring 通过 ClassPathBeanDefinitionScanner 扫描这些注解的类,并注册为 Bean。
* <p>
* 底层原理:
* 1. 组件扫描时,ClassMetadata 判断类是否被 @Component 或其派生注解标记(通过 hasAnnotation 或 hasMetaAnnotation)
* 2. 符合条件的类会被封装为 BeanDefinition(默认作用域为单例,作用域由 @Scope 注解指定)
* 3. Bean 名称由 AnnotationBeanNameGenerator 生成(类名首字母小写,或 @Component(name = "xxx") 指定)
* @Version 1.0.0
* @Date 2025
* @Author By Dwl
*/
@Slf4j
@Component // 标记为 Spring 组件(会被组件扫描自动发现并注册)
public class BeanImitateB {
public BeanImitateB() {
log.info("BeanImitateB 构造方法被调用(实例化阶段)");
}
// 示例:@PostConstruct 初始化方法(需 javax.annotation.PostConstruct)
// @PostConstruct
// public void init() {
// log.info("ImitateBeanB.init() 方法被调用(初始化阶段)");
// }
}
package com.dwl.bean_factory_post_processor.bean_imitate;
/**
* @ClassName BeanImitateC
* @Description
* @Version 1.0.0
* @Date 2025
* @Author By Dwl
*/
public class BeanImitateC {
}
package com.dwl.bean_factory_post_processor.bean_imitate;
import com.alibaba.druid.pool.DruidDataSource;
import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
/**
* @ClassName BeanImitateConfig
* @Description 模拟 Spring 中 @Configuration 配置类的作用:
* 1. 使用 @Component 标记为 Spring 组件(会被组件扫描自动发现)
* 2. 使用 @ComponentScan 指定需要扫描的包路径(触发组件扫描逻辑)
* 3. 使用 @Bean 注册自定义 Bean(会被 ConfigurationClassPostProcessor 处理)
* <p>
* Spring 配置类底层原理:
* - 被 @Configuration 标记的类会被解析为 ConfigurationClass(配置类),其与普通类的区别在于:
* - 包含 @Bean 方法,这些方法会被解析为 BeanDefinition(工厂方法为 @Bean 方法,工厂 Bean 为配置类本身)
* - 支持方法级依赖注入(@Bean 方法之间可相互调用,Spring 会确保返回单例)
* - @ComponentScan 注解会触发类路径扫描,将符合条件的组件(@Component 及其派生注解)注册为 Bean
* @Version 1.0.0
* @Date 2025
* @Author By Dwl
*/
@Slf4j
@Component // 标记为 Spring 组件(会被组件扫描自动注册)
@ComponentScan("com.dwl.bean_factory_post_processor.bean_imitate") // 指定组件扫描包路径
public class BeanImitateConfig {
/**
* @return BeanImitateA 实例(由 Spring 管理生命周期)
* @Bean 注解标记的方法会被 Spring 处理:
* 1. 方法返回值类型作为 Bean 的类型(BeanImitateA)
* 2. 方法名作为 Bean 的名称(默认)或通过 @Bean(name = "xxx") 指定(示例中为 "beanImitateA")
* 3. 方法参数由 Spring 自动注入(依赖注入,如无参数则直接实例化)
* 4. 初始化方法通过 @Bean(initMethod = "xxx") 指定(示例中未使用)
* 5. 销毁方法通过 @Bean(destroyMethod = "xxx") 指定(示例中未使用)
*/
@Bean // 标记为需要注册的 Bean
public BeanImitateA beanImitateA() {
log.info("BeanImitateConfig.beanImitateA() 被调用,创建 BeanImitateA 实例");
return new BeanImitateA(); // Spring 会将此实例存入单例池(SingletonBeanRegistry)
}
/**
* 未被 @Bean 标记的方法不会被 Spring 处理(仅作为普通方法)
* 示例:用于演示非 @Bean 方法的行为
*/
public BeanImitateC beanImitateC() {
log.info("BeanImitateConfig.beanImitateC() 被调用,创建 BeanImitateC 实例");
return new BeanImitateC(); // 不会被注册为 Bean(除非手动注册或通过其他方式)
}
/**
* @Bean 方法依赖其他 Bean 的示例:
* Spring 会自动注入 SqlSessionFactoryBean 依赖的 DataSource(通过方法参数声明)
* <p>
* 底层流程:
* 1. 解析 @Bean 方法的参数类型(DataSource)
* 2. 在容器中查找匹配的 Bean(单例池中已存在的 DataSource)
* 3. 将找到的 Bean 注入到方法参数中(依赖注入)
*
* @param source 数据源(自动注入)
* @return SqlSessionFactoryBean 实例(依赖 DataSource)
*/
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource source) {
log.info("BeanImitateConfig.sqlSessionFactoryBean() 被调用,创建 SqlSessionFactoryBean 实例");
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(source); // 依赖注入 DataSource(由 Spring 自动完成)
return bean; // SqlSessionFactoryBean 本身也是一个 Bean(工厂 Bean)
}
/**
* 带初始化方法的 @Bean 示例:
* Spring 会在 Bean 实例化、依赖注入完成后,调用 initMethod 指定的方法
* <p>
* 底层流程:
* 1. 实例化 Bean(调用构造方法)
* 2. 依赖注入(@Autowired、@Resource 等注解处理)
* 3. 调用初始化方法(@Bean(initMethod = "init") 或 @PostConstruct)
*
* @return DruidDataSource 实例(已初始化)
*/
@Bean(initMethod = "init") // 指定初始化方法
public DruidDataSource druidDataSource() {
log.info("BeanImitateConfig.druidDataSource() 被调用,创建 DruidDataSource 实例");
DruidDataSource source = new DruidDataSource();
source.setUrl("jdbc:mysql://localhost:3306/spider_flow");
source.setUsername("root");
source.setPassword("");
return source; // Spring 会将其存入单例池,并在容器关闭时调用 close() 方法
}
}
package com.dwl.bean_factory_post_processor.convention.mapper;
import org.apache.ibatis.annotations.Mapper;
/**
* @ClassName ConventionBeanMapperA
* @Description
* @Version 1.0.0
* @Date 2025
* @Author By Dwl
*/
@Mapper
public interface ConventionBeanMapperA {
}
package com.dwl.bean_factory_post_processor.convention.mapper;
import org.apache.ibatis.annotations.Mapper;
/**
* @ClassName ConventionBeanMapperB
* @Description
* @Version 1.0.0
* @Date 2025
* @Author By Dwl
*/
@Mapper
public interface ConventionBeanMapperB {
}
package com.dwl.bean_factory_post_processor.convention;
/**
* @ClassName ConventionBean
* @Description
* @Version 1.0.0
* @Date 2025
* @Author By Dwl
*/
public class ConventionBean {
}
package com.dwl.bean_factory_post_processor.convention;
import com.alibaba.druid.pool.DruidDataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
/**
* @ClassName ConventionConfig
* @Description
* @Version 1.0.0
* @Date 2025
* @Author By Dwl
*/
@Component
@ComponentScan("com.dwl.bean_factory_post_processor.convention")
public class ConventionConfig {
@Bean
public ConventionBean conventionBean() {
return new ConventionBean();
}
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource source) {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(source);
return bean;
}
@Bean(initMethod = "init")
public DruidDataSource druidDataSource() {
DruidDataSource source = new DruidDataSource();
source.setUrl("jdbc:mysql://localhost:3306/spider_flow");
source.setUsername("root");
source.setPassword("");
return source;
}
}
package com.dwl.bean_factory_post_processor.imitate;
/**
* @ClassName ImitateBean
* @Description
* @Version 1.0.0
* @Date 2025
* @Author By Dwl
*/
public class ImitateBean {
}
package com.dwl.bean_factory_post_processor.imitate;
import lombok.extern.slf4j.Slf4j;
/**
* @ClassName ImitateBeanA
* @Description
* @Version 1.0.0
* @Date 2025
* @Author By Dwl
*/
@Slf4j
public class ImitateBeanA {
}
package com.dwl.bean_factory_post_processor.imitate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* @ClassName ImitateBeanB
* @Description
* @Version 1.0.0
* @Date 2025
* @Author By Dwl
*/
@Slf4j
@Component
public class ImitateBeanB {
public ImitateBeanB() {
}
}
package com.dwl.bean_factory_post_processor.imitate;
import org.springframework.stereotype.Service;
/**
* @ClassName ImitateBeanC
* @Description
* @Version 1.0.0
* @Date 2025
* @Author By Dwl
*/
@Service
public class ImitateBeanC {
}
package com.dwl.bean_factory_post_processor.imitate;
import com.alibaba.druid.pool.DruidDataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
/**
* @ClassName ImitateConfig
* @Description
* @Version 1.0.0
* @Date 2025
* @Author By Dwl
*/
@Component
@ComponentScan("com.dwl.bean_factory_post_processor.imitate")
public class ImitateConfig {
@Bean
public ImitateBean imitateBean() {
return new ImitateBean();
}
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource source) {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(source);
return bean;
}
@Bean(initMethod = "init")
public DruidDataSource druidDataSource() {
DruidDataSource source = new DruidDataSource();
source.setUrl("jdbc:mysql://localhost:3306/spider_flow");
source.setUsername("root");
source.setPassword("");
return source;
}
}
package com.dwl.bean_factory_post_processor.mapper_imitate.mapper;
import org.apache.ibatis.annotations.Mapper;
/**
* @ClassName MapperImitateBeanA
* @Description
* @Version 1.0.0
* @Date 2025
* @Author By Dwl
*/
@Mapper
public interface MapperImitateBeanA {
}
package com.dwl.bean_factory_post_processor.mapper_imitate.mapper;
import org.apache.ibatis.annotations.Mapper;
/**
* @ClassName MapperImitateBeanB
* @Description
* @Version 1.0.0
* @Date 2025
* @Author By Dwl
*/
@Mapper
public interface MapperImitateBeanB {
}
package com.dwl.bean_factory_post_processor.mapper_imitate;
/**
* @ClassName ImitateBeanA
* @Description
* @Version 1.0.0
* @Date 2025
* @Author By Dwl
*/
public class MapperImitateA {
}
package com.dwl.bean_factory_post_processor.mapper_imitate;
import org.springframework.stereotype.Component;
/**
* @ClassName MapperImitateB
* @Description
* @Version 1.0.0
* @Date 2025
* @Author By Dwl
*/
@Component
public class MapperImitateB {
}
package com.dwl.bean_factory_post_processor.mapper_imitate;
import com.alibaba.druid.pool.DruidDataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
/**
* @ClassName BeanImitateConfig
* @Description
* @Version 1.0.0
* @Date 2025
* @Author By Dwl
*/
@Component
@ComponentScan("com.dwl.bean_factory_post_processor.bean_imitate")
public class MapperImitateConfig {
@Bean
public MapperImitateA mapperImitateA() {
return new MapperImitateA();
}
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource source) {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(source);
return bean;
}
@Bean(initMethod = "init")
public DruidDataSource druidDataSource() {
DruidDataSource source = new DruidDataSource();
source.setUrl("jdbc:mysql://localhost:3306/spider_flow");
source.setUsername("root");
source.setPassword("");
return source;
}
/* 基本方式
@Bean
public MapperFactoryBean<MapperImitateBeanA> mapperImitateBeanA(SqlSessionFactory factory) {
MapperFactoryBean<MapperImitateBeanA> bean = new MapperFactoryBean<>(MapperImitateBeanA.class);
bean.setSqlSessionFactory(factory);
return bean;
}
@Bean
public MapperFactoryBean<MapperImitateBeanB> mapperImitateBeanB(SqlSessionFactory factory) {
MapperFactoryBean<MapperImitateBeanB> bean = new MapperFactoryBean<>(MapperImitateBeanB.class);
bean.setSqlSessionFactory(factory);
return bean;
}
*/
}