从 Spring 容器启动到最终创建 MapperProxy 的完整流程
·
好的,我来补充完整的调用链,包括从 Spring 容器启动到最终创建 MapperProxy 的完整流程。
完整调用链
Phase 1: 配置解析和扫描器注册阶段
Spring容器启动
↓
解析@MapperScan注解
↓
MapperScannerRegistrar.registerBeanDefinitions()
↓
创建MapperScannerConfigurer的BeanDefinition
↓
注册到Spring容器
Phase 2: BeanFactory后处理阶段
Spring容器refresh()
↓
invokeBeanFactoryPostProcessors()
↓
MapperScannerConfigurer.postProcessBeanDefinitionRegistry() // 作为BeanFactoryPostProcessor
↓
创建ClassPathMapperScanner并配置
↓
ClassPathMapperScanner.scan()
↓
ClassPathMapperScanner.doScan()
↓
ClassPathBeanDefinitionScanner.doScan() // 父类方法
│ ↓
│ forEach basePackage:
│ ↓
│ findCandidateComponents(basePackage) // 扫描类路径
│ ↓
│ 使用ASM读取class文件元数据
│ ↓
│ 应用include/exclude过滤器
│ ↓
│ 返回候选BeanDefinition集合
│ ↓
│ forEach BeanDefinition candidate:
│ ↓
│ 解析Scope元数据
│ ↓
│ 生成BeanName
│ ↓
│ postProcessBeanDefinition(candidate, beanName) // Spring默认处理
│ ↓
│ 处理通用注解(@Lazy, @Primary等)
│ ↓
│ checkCandidate() // 检查Bean是否可注册
│ ↓
│ 创建BeanDefinitionHolder
│ ↓
│ 应用ScopedProxy模式
│ ↓
│ 注册BeanDefinition到容器
↓
ClassPathMapperScanner.processBeanDefinitions() // MyBatis关键处理!
↓
forEach BeanDefinitionHolder:
↓
获取原始Mapper接口类名
↓
将BeanClass替换为MapperFactoryBean
↓
设置构造器参数(原始Mapper接口类名)
↓
设置属性(addToConfig, sqlSessionFactory等)
↓
设置自动装配模式
Phase 3: Bean实例化阶段
Spring容器getBean("userMapper")
↓
发现BeanDefinition的beanClass是MapperFactoryBean
↓
实例化MapperFactoryBean
↓
调用MapperFactoryBean.getObject()方法
↓
getSqlSession().getMapper(mapperInterface)
↓
SqlSessionTemplate.getMapper()
↓
Configuration.getMapper()
↓
MapperRegistry.getMapper()
↓
MapperProxyFactory.newInstance()
↓
创建MapperProxy实例
↓
Proxy.newProxyInstance()创建JDK动态代理
↓
返回MapperProxy代理对象
Phase 4: 方法调用阶段
业务代码调用userMapper.findById(1)
↓
JDK动态代理调用MapperProxy.invoke()
↓
MapperMethod.execute()
↓
SqlSessionTemplate.selectOne()
↓
SqlSessionInterceptor.invoke() // 管理SqlSession生命周期
↓
DefaultSqlSession.selectOne()
↓
执行SQL,返回结果
关键代码细节
1. findCandidateComponents 扫描过程
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
// 构建包路径模式:classpath*:com/example/mapper/**/*.class
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
// 获取资源文件
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
for (Resource resource : resources) {
if (resource.isReadable()) {
try {
// 使用ASM读取类元数据,避免加载类
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
// 检查是否匹配过滤器
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setResource(resource);
sbd.setSource(resource);
if (isCandidateComponent(sbd)) {
candidates.add(sbd);
}
}
} catch (Throwable ex) {
// 处理异常...
}
}
}
return candidates;
}
2. MapperFactoryBean.getObject() 创建代理
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
private Class<T> mapperInterface;
@Override
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
@Override
public Class<T> getObjectType() {
return this.mapperInterface;
}
}
3. MapperProxyFactory 创建代理实例
public class MapperProxyFactory<T> {
private final Class<T> mapperInterface;
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(),
new Class[] { mapperInterface }, mapperProxy);
}
}
4. MapperProxy 方法调用处理
public class MapperProxy<T> implements InvocationHandler, Serializable {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else {
// 缓存MapperMethod以提高性能
return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
}
总结
整个流程可以概括为四个主要阶段:
- 配置注册阶段:通过
@MapperScan注册扫描器 - Bean定义扫描阶段:扫描接口并转换为
MapperFactoryBean定义 - 代理创建阶段:Spring 实例化时通过
MapperFactoryBean创建MapperProxy - 方法执行阶段:通过动态代理将方法调用转换为 SQL 执行
这个完整流程确保了 MyBatis Mapper 接口能够无缝集成到 Spring 容器中,并提供了类型安全的数据库操作接口。
更多推荐

所有评论(0)