好的!我来整合分析完整的源码流程,并给出详细的流程图。

1. 完整源码流程分析

阶段一:Spring 启动扫描阶段

位置:org.mybatis.spring.annotation.MapperScannerRegistrar

public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        // 1. 解析 @MapperScan 注解
        AnnotationAttributes mapperScanAttrs = AnnotationAttributes
            .fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
        
        // 2. 创建扫描器
        ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
        
        // 3. 开始扫描包路径
        scanner.scan(basePackages.toArray(new String[0]));
    }
}

位置:org.mybatis.spring.mapper.ClassPathMapperScanner

public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
    
    private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
        for (BeanDefinitionHolder holder : beanDefinitions) {
            GenericBeanDefinition definition = (GenericBeanDefinition) holder.getBeanDefinition();
            
            // 【关键】Bean Class 替换魔法
            String originalMapperClass = definition.getBeanClassName();
            
            // 替换为 MapperFactoryBean
            definition.getConstructorArgumentValues().addGenericArgumentValue(originalMapperClass);
            definition.setBeanClass(MapperFactoryBean.class);
            
            // 设置属性
            definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);
            definition.getPropertyValues().add("mapperInterface", originalMapperClass);
            
            // 此时 BeanDefinition 变为:
            // beanClass: MapperFactoryBean
            // constructorArgs: [UserMapper.class]
            // properties: {sqlSessionFactory: xxx, mapperInterface: UserMapper.class}
        }
    }
}

阶段二:Spring Bean 创建触发阶段

位置:org.springframework.beans.factory.support.DefaultListableBeanFactory

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory {
    
    // Spring 启动时预实例化单例 Bean
    public void preInstantiateSingletons() throws BeansException {
        List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
        
        for (String beanName : beanNames) {
            RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
            
            if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                // 【触发】获取 Bean 实例
                getBean(beanName);
            }
        }
    }
}

位置:org.springframework.beans.factory.support.AbstractBeanFactory

public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport {
    
    protected <T> T doGetBean(String name, Class<T> requiredType, Object[] args, boolean typeCheckOnly) {
        // 【核心逻辑】处理 FactoryBean
        return getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
    }
    
    protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
        // 检查是否是 FactoryBean
        if (!(beanInstance instanceof FactoryBean)) {
            return beanInstance;
        }
        
        // 【关键】FactoryBean 特殊处理
        Object object = getCachedObjectForFactoryBean(beanName);
        if (object == null) {
            FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
            object = getObjectFromFactoryBean(factory, beanName, !synthetic);
        }
        return object;
    }
}

位置:org.springframework.beans.factory.support.FactoryBeanRegistrySupport

public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanRegistry {
    
    private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName) {
        try {
            // 【最终触发点】调用 FactoryBean.getObject()
            return factory.getObject();
        } catch (Throwable ex) {
            throw new BeanCreationException(beanName, "FactoryBean threw exception", ex);
        }
    }
}

阶段三:Mapper 代理创建阶段

位置:org.mybatis.spring.mapper.MapperFactoryBean

public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
    
    @Override
    public T getObject() throws Exception {
        // 【委托给 MyBatis 创建代理】
        return getSqlSession().getMapper(this.mapperInterface);
    }
    
    @Override
    public SqlSession getSqlSession() {
        // 返回 SqlSessionTemplate
        return this.sqlSessionTemplate;
    }
}

位置:org.mybatis.spring.SqlSessionTemplate

public class SqlSessionTemplate implements SqlSession {
    
    public <T> T getMapper(Class<T> type) {
        // 获取 Configuration
        return getConfiguration().getMapper(type, this);
    }
}

位置:org.apache.ibatis.session.Configuration

public class Configuration {
    
    public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        // 从 MapperRegistry 获取
        return mapperRegistry.getMapper(type, sqlSession);
    }
}

位置:org.apache.ibatis.binding.MapperRegistry

public class MapperRegistry {
    
    public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        // 获取 MapperProxyFactory
        final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
        
        // 创建 MapperProxy
        return mapperProxyFactory.newInstance(sqlSession);
    }
}

位置:org.apache.ibatis.binding.MapperProxyFactory

public class MapperProxyFactory<T> {
    
    public T newInstance(SqlSession sqlSession) {
        // 创建 MapperProxy(InvocationHandler)
        final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
        
        // JDK 动态代理创建代理对象
        return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), 
                                         new Class[] { mapperInterface }, 
                                         mapperProxy);
    }
}

阶段四:方法调用拦截阶段

位置:org.apache.ibatis.binding.MapperProxy

public class MapperProxy<T> implements InvocationHandler {
    
    @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);
        }
    }
    
    private MapperMethodInvoker cachedInvoker(Method method) throws Throwable {
        return methodCache.computeIfAbsent(method, m -> {
            // 创建 MapperMethod
            return new PlainMethodInvoker(new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
        });
    }
}

位置:org.apache.ibatis.binding.MapperMethod

public class MapperMethod {
    
    public Object execute(SqlSession sqlSession, Object[] args) {
        // 根据 SQL 类型执行不同操作
        switch (command.getType()) {
            case SELECT:
                if (method.returnsMany()) {
                    // 调用 SqlSessionTemplate.selectList()
                    result = executeForMany(sqlSession, args);
                }
                // ... 其他操作类型
        }
    }
    
    private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
        // 【委托给 SqlSessionTemplate】
        return sqlSession.selectList(command.getName(), param);
    }
}

2. 完整流程图

graph TD
    A[Spring容器启动] --> B[@MapperScan扫描]
    B --> C[ClassPathMapperScanner]
    C --> D{扫描Mapper接口}
    D --> E[找到UserMapper接口]
    E --> F[创建BeanDefinition]
    F --> G[Bean Class替换]
    G --> H[BeanClass: MapperFactoryBean<br>构造参数: UserMapper.class]
    
    H --> I[Spring初始化单例Bean]
    I --> J{需要UserMapper Bean?}
    J -->|依赖注入| K[AbstractBeanFactory.getBean]
    J -->|显式调用| K
    J -->|@Autowired| K
    
    K --> L[创建MapperFactoryBean实例]
    L --> M[FactoryBeanRegistrySupport.getObjectFromFactoryBean]
    M --> N[调用MapperFactoryBean.getObject]
    
    N --> O[SqlSessionTemplate.getMapper]
    O --> P[Configuration.getMapper]
    P --> Q[MapperRegistry.getMapper]
    Q --> R[MapperProxyFactory.newInstance]
    R --> S[创建MapperProxy动态代理]
    S --> T[JDK Proxy.newProxyInstance]
    
    T --> U[返回MapperProxy给Spring]
    U --> V[Spring注册为UserMapper Bean]
    
    V --> W[业务代码调用userMapper.method]
    W --> X[MapperProxy.invoke拦截]
    X --> Y[MapperMethod.execute]
    Y --> Z[SqlSessionTemplate.xxx]
    Z --> AA[SqlSessionInterceptor事务管理]
    AA --> AB[真实数据库操作]
    
    style A fill:#e1f5fe
    style N fill:#fff3e0
    style S fill:#e8f5e8
    style X fill:#fce4ec
    style AB fill:#ffebee

3. 核心触发时机总结

3.1 初始创建时机

// 时机1: Spring 启动预实例化
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args); // ← 这里触发
    }
}

// 时机2: 懒加载首次访问
@Lazy
@Autowired
private UserMapper userMapper; // ← 首次访问时触发

3.2 运行时触发时机

// 时机3: 依赖注入
@Service
public class UserService {
    @Autowired  // ← 创建 UserService 时触发
    private UserMapper userMapper;
}

// 时机4: 显式获取
@Bean
public SomeBean someBean(ApplicationContext context) {
    UserMapper mapper = context.getBean(UserMapper.class); // ← 调用时触发
    return new SomeBean(mapper);
}

// 时机5: 方法参数注入
@EventListener
public void handleEvent(SomeEvent event, UserMapper userMapper) { // ← 事件触发时
    userMapper.doSomething();
}

4. 关键设计模式总结

  1. 工厂模式MapperFactoryBean 作为 Mapper 的工厂
  2. 代理模式MapperProxy 拦截方法调用
  3. 装饰器模式:多层代理增强功能
  4. 模板方法SqlSessionTemplate 统一处理事务
  5. 注册表模式MapperRegistry 管理 Mapper 注册

这个完整流程展示了 MyBatis-Spring 如何通过巧妙的 BeanDefinition 替换和 FactoryBean 机制,将 MyBatis 的 Mapper 接口无缝集成到 Spring 容器中,让开发者可以像使用普通 Spring Bean 一样使用 Mapper 接口。

更多推荐