前言: 本文将重点讲解Mybatis-spring的执行过程,对比mybatis和Mybatis-spring的流程差异,以及Mybatis-spring一级缓存失效的原因(文章方法15),和spring自动注入的原理和哪些属性不会自动装配的讲解。

解析mybatis-spring源码


文章目录

  • 解析mybatis-spring源码
  • 启动流程
  • 执行过程
  • 对象的自动装配


启动流程
  1. Mybatis配置类中的MapperScan
@Configuration
@EnableTransactionManagement
@MapperScan(basePackages = DataSourceConfiguration.PACKAGE, sqlSessionFactoryRef = DataSourceConfiguration.SQL_SESSION_FACTORY)
public class DataSourceConfiguration {}
  1. MapperScan中加了@Import注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({MapperScannerRegistrar.class})
@Repeatable(MapperScans.class)
public @interface MapperScan{}
  1. MapperScannerRegistrar类解析
  1. 在扫描到数据源配置类(如DataSourceConfiguration)时,扫描其@import注入的类,mybatis注入了一个MapperScannerConfigurer类,他是继承了BeanDefinitionRegistryPostProcessor接口的类。
  2. 注册完这个类后,spring再次扫描ImportBeanDefinitionRegistrar这个的时候,会执行MapperScannerConfigurerpostProcessBeanDefinitionRegistry方法。
  3. MapperScannerRegistrar在构造MapperScannerConfigurer的bd时,将解析@MapperScan的参数,例如basePackages = DataSourceConfiguration.PACKAGE, sqlSessionFactoryRef = DataSourceConfiguration.SQL_SESSION_FACTORY等,将其设置到MapperScannerConfigurer的bd中
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
     void registerBeanDefinitions(AnnotationMetadata annoMeta, AnnotationAttributes annoAttrs,
      BeanDefinitionRegistry registry, String beanName) {
    // 生成MapperScannerConfigurer类的bd
    BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
    builder.addPropertyValue("processPropertyPlaceHolders", true);
    // bd设置 解析加@MapperScan 填入的数据
    Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
    if (!Annotation.class.equals(annotationClass)) {
      builder.addPropertyValue("annotationClass", annotationClass);
    }

    Class<?> markerInterface = annoAttrs.getClass("markerInterface");
    if (!Class.class.equals(markerInterface)) {
      builder.addPropertyValue("markerInterface", markerInterface);
    }

    Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
    if (!BeanNameGenerator.class.equals(generatorClass)) {
      builder.addPropertyValue("nameGenerator", BeanUtils.instantiateClass(generatorClass));
    }

    Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
    if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
      builder.addPropertyValue("mapperFactoryBeanClass", mapperFactoryBeanClass);
    }

    String sqlSessionTemplateRef = annoAttrs.getString("sqlSessionTemplateRef");
    if (StringUtils.hasText(sqlSessionTemplateRef)) {
      builder.addPropertyValue("sqlSessionTemplateBeanName", annoAttrs.getString("sqlSessionTemplateRef"));
    }

    String sqlSessionFactoryRef = annoAttrs.getString("sqlSessionFactoryRef");
    if (StringUtils.hasText(sqlSessionFactoryRef)) {
      builder.addPropertyValue("sqlSessionFactoryBeanName", annoAttrs.getString("sqlSessionFactoryRef"));
    }

    List<String> basePackages = new ArrayList<>();
    basePackages.addAll(
        Arrays.stream(annoAttrs.getStringArray("value")).filter(StringUtils::hasText).collect(Collectors.toList()));

    basePackages.addAll(Arrays.stream(annoAttrs.getStringArray("basePackages")).filter(StringUtils::hasText)
        .collect(Collectors.toList()));

    basePackages.addAll(Arrays.stream(annoAttrs.getClassArray("basePackageClasses")).map(ClassUtils::getPackageName)
        .collect(Collectors.toList()));

    if (basePackages.isEmpty()) {
      basePackages.add(getDefaultBasePackage(annoMeta));
    }

    String lazyInitialization = annoAttrs.getString("lazyInitialization");
    if (StringUtils.hasText(lazyInitialization)) {
      builder.addPropertyValue("lazyInitialization", lazyInitialization);
    }

    String defaultScope = annoAttrs.getString("defaultScope");
    if (!AbstractBeanDefinition.SCOPE_DEFAULT.equals(defaultScope)) {
      builder.addPropertyValue("defaultScope", defaultScope);
    }
    builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(basePackages));
    // 注册的名字是importingClassMetadata.getClassName() + "#" + MapperScannerRegistrar.class.getSimpleName() + "#" + index;
    // 加@MapperScan类的配置类名#MapperScannerRegistrar#index
    registry.registerBeanDefinition(beanName, builder.getBeanDefinition());
  }
}
  1. MapperScannerConfigurer.postProcessBeanDefinitionRegistry的执行

明确一点 这是由上面 MapperScannerRegistrar注入的MapperScannerConfigurer。

他被spring运行的时机是在invokeBeanFactoryPostProcessors处理BeanDefinitionRegistry的最后部分

public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) { while (reiterate) { reiterate = false; postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (String ppName : postProcessorNames) { if (!processedBeans.contains(ppName)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); reiterate = true; } } sortPostProcessors(currentRegistryProcessors, beanFactory); registryProcessors.addAll(currentRegistryProcessors); // 这里去执行MapperScannerConfigurer.postProcessBeanDefinitionRegistry() invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); currentRegistryProcessors.clear(); } }

他创建了一个扫描器,去注册所有的XXXMapper接口到bd中,其中接口对应的实体类都是被代理出来的

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
    if (this.processPropertyPlaceHolders) {
      processPropertyPlaceHolders();
    }
    // 创建一个解析器ClassPathMapperScanner
    // 数据由MapperScannerRegistrar创建MapperScannerConfigurer的bd时设置的
    ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
    scanner.setAddToConfig(this.addToConfig);
    scanner.setAnnotationClass(this.annotationClass);
    scanner.setMarkerInterface(this.markerInterface);
    scanner.setSqlSessionFactory(this.sqlSessionFactory);
    scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
    scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
    scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
    scanner.setResourceLoader(this.applicationContext);
    scanner.setBeanNameGenerator(this.nameGenerator);
    scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
    if (StringUtils.hasText(lazyInitialization)) {
      scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization));
    }
    if (StringUtils.hasText(defaultScope)) {
      scanner.setDefaultScope(defaultScope);
    }
    scanner.registerFilters();
    // 扫描所有的XXXMapper接口(此处传入的是XXXMapper的包名字符串)
    // 函数解析5
    scanner.scan(
        StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
  }
  1. 扫描类父类的ClassPathBeanDefinitionScanner.doScan()
public int scan(String... basePackages) {
    // 记录扫描前注册bd的数量
        int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
    // 扫描(传入的是XXXMapper的包名数组)
    // 调用的是子类ClassPathMapperScanner.doScan
        this.doScan(basePackages);
        if (this.includeAnnotationConfig) {
            AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
        }
    // 返回扫描注册bd的数量
        return this.registry.getBeanDefinitionCount() - beanCountAtScanStart;
    }
  1. 调用扫描类ClassPathMapperScanner.doScan()

调用父类(方法7)去注册那几个XXXMapper的接口bd,并将bd返回,为了设置这几个bd对应的代理对象

public Set<BeanDefinitionHolder> doScan(String... basePackages) {
    // 这里返回的是函数7注册进spring的XXXXMapper(就那几个接口)的bd的Set集合
    Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);

    if (beanDefinitions.isEmpty()) {
      LOGGER.warn(() -> "No MyBatis mapper was found in '" + Arrays.toString(basePackages)
          + "' package. Please check your configuration.");
    } else {
        // 重点在这里,是处理这几个接口bd的实体代理对象
      processBeanDefinitions(beanDefinitions);
    }

    return beanDefinitions;
  }
  1. 再次进入父类的ClassPathBeanDefinitionScanner.doScan()

这里面就是扫描包下的类加入registry 并返回bd

扫描的就是那几个XXXMapper接口;

在这里他先将bd注册后,还用set保存起来,为了后面设置这几个接口bd的实体对象(代理对象)

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Assert.notEmpty(basePackages, "At least one base package must be specified");
        Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet();
        String[] var3 = basePackages;
        int var4 = basePackages.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            String basePackage = var3[var5];
            Set<BeanDefinition> candidates = this.findCandidateComponents(basePackage);
            Iterator var8 = candidates.iterator();

            while(var8.hasNext()) {
                BeanDefinition candidate = (BeanDefinition)var8.next();
                ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
                candidate.setScope(scopeMetadata.getScopeName());
                String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
                if (candidate instanceof AbstractBeanDefinition) {
                    this.postProcessBeanDefinition((AbstractBeanDefinition)candidate, beanName);
                }

                if (candidate instanceof AnnotatedBeanDefinition) {
                    AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition)candidate);
                }

                if (this.checkCandidate(beanName, candidate)) {
                    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                    definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                    beanDefinitions.add(definitionHolder);
                    // 注册bd 这里注册了XXXXMapper接口的bd
                    this.registerBeanDefinition(definitionHolder, this.registry);
                }
            }
        }
    // 将注册的XXXXMapper接口的bd返回
        return beanDefinitions;
    }
  1. 扩展XXXMapper的bdClassPathMapperScanner.processBeanDefinitions()

这里面就是要给接口设置实例化对象,这样在使用接口执行操作的时候才能操作实例化对象;

由于在这里使用动态代理,无法拿到动态代理的对象,无法放入spring容器中,所以使用了FactoryBean对象去处理。

这里使用的是MapperFactoryBean.class

这里设置了MapperFactoryBean属性值的注入方式为AUTOWIRE_BY_TYPE

这里扩展一下spring的自动装配,在AbstractBeanDefinition.class下有如下几个标志:

  1. int AUTOWIRE_NO = 0; 表示不自动注入,但标记@Autowire的会自动注入;
  2. int AUTOWIRE_BY_NAME = 1; 通过属性的名字的方式查找JavaBean依赖的对象调用set方法为其注入;那具体什么属性需要装配,见方法10的解析
  3. int AUTOWIRE_BY_TYPE = 2; 通过属性的类型的方式查找JavaBean依赖的对象调用set方法为其注入;
  4. int AUTOWIRE_CONSTRUCTOR = 3; 通过属性的构造方法装配,无需set方法;

自动注入的标签区别

  1. @Resource 通过 byName 方式自动装配
  2. @Autowired 通过ByType 方式自动装配
  3. @Autowired 和@Qualifier 可以实现ByName的效果
    如果Spring中有2个类型相同的Bean在通过@Autowired会报错 我们可以通过@Qualifier 标签来进行区分

为了通用性,构造方法应该是这个接口的class

从而可以返回一个代理对象

private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
    AbstractBeanDefinition definition;
    BeanDefinitionRegistry registry = getRegistry();
    for (BeanDefinitionHolder holder : beanDefinitions) {
      definition = (AbstractBeanDefinition) holder.getBeanDefinition();
      boolean scopedProxy = false;
      // 这里是false不进入 bd都是XXXMapper
      if (ScopedProxyFactoryBean.class.getName().equals(definition.getBeanClassName())) {
        definition = (AbstractBeanDefinition) Optional
            .ofNullable(((RootBeanDefinition) definition).getDecoratedDefinition())
            .map(BeanDefinitionHolder::getBeanDefinition).orElseThrow(() -> new IllegalStateException(
                "The target bean definition of scoped proxy bean not found. Root bean definition[" + holder + "]"));
        scopedProxy = true;
      }
      String beanClassName = definition.getBeanClassName();
      LOGGER.debug(() -> "Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + beanClassName
          + "' mapperInterface");

      // the mapper interface is the original class of the bean
      // but, the actual class of the bean is MapperFactoryBean
      // 设置FactoryBean构造函数的参数
      definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); // issue #59
      // setBeanClass MapperFactoryBean.class;
      definition.setBeanClass(this.mapperFactoryBeanClass);

      definition.getPropertyValues().add("addToConfig", this.addToConfig);

      boolean explicitFactoryUsed = false;
      if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {
        definition.getPropertyValues().add("sqlSessionFactory",
            new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
        explicitFactoryUsed = true;
      } else if (this.sqlSessionFactory != null) {
        definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);
        explicitFactoryUsed = true;
      }

      if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {
        if (explicitFactoryUsed) {
          LOGGER.warn(
              () -> "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
        }
        definition.getPropertyValues().add("sqlSessionTemplate",
            new RuntimeBeanReference(this.sqlSessionTemplateBeanName));
        explicitFactoryUsed = true;
      } else if (this.sqlSessionTemplate != null) {
        if (explicitFactoryUsed) {
          LOGGER.warn(
              () -> "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
        }
        definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
        explicitFactoryUsed = true;
      }

      if (!explicitFactoryUsed) {
        LOGGER.debug(() -> "Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
          // 在这里设置了FactoryBean属性值注入方式
        definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
      }

      definition.setLazyInit(lazyInitialization);

      if (scopedProxy) {
        continue;
      }

      if (ConfigurableBeanFactory.SCOPE_SINGLETON.equals(definition.getScope()) && defaultScope != null) {
        definition.setScope(defaultScope);
      }

      if (!definition.isSingleton()) {
        BeanDefinitionHolder proxyHolder = ScopedProxyUtils.createScopedProxy(holder, registry, true);
        if (registry.containsBeanDefinition(proxyHolder.getBeanName())) {
          registry.removeBeanDefinition(proxyHolder.getBeanName());
        }
        registry.registerBeanDefinition(proxyHolder.getBeanName(), proxyHolder.getBeanDefinition());
      }
    }
  }
  1. MapperFactoryBean.class

用于生成XXXMapper.class 的代理对象,具体看方法11

这里面继承了SqlSessionDaoSupport这个对象不一般,具体看方法10的解析

public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
     
      // 传入的接口XXXMapper.class
     private Class<T> mapperInterface;
   
     private boolean addToConfig = true;
   
     public MapperFactoryBean() {
       // intentionally empty
     }
       // 构造函数 传入的接口XXXMapper.class
     public MapperFactoryBean(Class<T> mapperInterface) {
       this.mapperInterface = mapperInterface;
     }
       // 返回代理对象 这个 代理对象见*方法11*
     @Override
     public T getObject() throws Exception {
       return getSqlSession().getMapper(this.mapperInterface);
     }
   
     // 返回生成对象的类型 也就是传入的接口XXXMapper.class
     @Override
     public Class<T> getObjectType() {
       return this.mapperInterface;
     }
  // 在实例化的时候会调用
     @Override
     protected void checkDaoConfig() {
       super.checkDaoConfig();
   
       notNull(this.mapperInterface, "Property 'mapperInterface' is required");
       Configuration configuration = getSqlSession().getConfiguration();
       if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
         try {
             //  String mappedStatementId = this.type.getName() + "." + method.getName();
             // 这里 configuration会将接口中的sql语句解析封装成MappedStatement, 其中id就是包名+方法名
           configuration.addMapper(this.mapperInterface);
         } catch (Exception e) {
           logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", e);
           throw new IllegalArgumentException(e);
         } finally {
           ErrorContext.instance().reset();
         }
       }
     }
   
   }
  1. 父类 SqlSessionDaoSupport.class和DaoSupport.class

DaoSupport在创建bean的过程中会调用SqlSessionDaoSupport的checkDaoConfig方法

而MapperFactoryBean中又重写了checkDaoConfig方法,所以在实例化MapperFactoryBean的时候会调用MapperFactoryBean.checkDaoConfig(),当中就是解析sql语句封装MappedStatement对象。

public abstract class SqlSessionDaoSupport extends DaoSupport {
   @Override
  protected void checkDaoConfig() {
    notNull(this.sqlSessionTemplate, "Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required");
  }
   
  // 见set方法
  public SqlSession getSqlSession() {
    return this.sqlSessionTemplate;
  }
    
  // 这里sqlSessionTemplate的值是在初始化bean的时候赋值的
  // this.sqlSessionTemplate.getSqlSessionFactory()就是调用方法11里的sqlSessionFactory
  public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
    if (this.sqlSessionTemplate == null || sqlSessionFactory != this.sqlSessionTemplate.getSqlSessionFactory()) {
      this.sqlSessionTemplate = createSqlSessionTemplate(sqlSessionFactory);
    }
  }
}

// DaoSupport.class
public abstract class DaoSupport implements InitializingBean {
    protected final Log logger = LogFactory.getLog(this.getClass());

    public DaoSupport() {
    }
    
    // Spring实例化Bean后会执行afterPropertiesSet
    // 由于是抽象方法这里都将调用子类的实现
    public final void afterPropertiesSet() throws IllegalArgumentException, BeanInitializationException {
        this.checkDaoConfig();

        try {
        this.initDao();
        } catch (Exception var2) {
            throw new BeanInitializationException("Initialization of DAO failed", var2);
        }
    }

    protected abstract void checkDaoConfig() throws IllegalArgumentException;

    protected void initDao() throws Exception {
    }
}
  1. 调用SqlSessionTemplate.class中的getMapper()->Configuration.getMapper()
  1. 这个类中的sqlSessionFactory,在mybatis配置类中通过SqlSessionFactoryBean.class创建了bean并注册进spring中。这里直接自动装配,返回的是DefaultSqlSessionFactory.class 他实现了SqlSessionFactory接口
@Configuration
@EnableTransactionManagement
@MapperScan(basePackages = DataSourceConfiguration.PACKAGE, sqlSessionFactoryRef = DataSourceConfiguration.SQL_SESSION_FACTORY)
public class DataSourceConfiguration { 
    // ******
    
	@Bean(name = DataSourceConfiguration.SQL_SESSION_FACTORY)
    public SqlSessionFactory initSqlSessionFactory() throws Exception {
        // SqlSessionFactory是一个接口,实际返回是DefaultSqlSessionFactory
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(initDataSource());

        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        sqlSessionFactoryBean.setMapperLocations(resolver.getResources("classpath:/mapper/*.xml"));
        sqlSessionFactoryBean.setTypeAliasesPackage(typeAliasesPackage);
        return sqlSessionFactoryBean.getObject();
    }
}

  1. DefaultSqlSessionFactory.class中维护了一个属性Configuration,Configuration属性里面有jdbc的链接信息以及Map<String, MappedStatement> mappedStatements;这个map就是装着sql语句和id。
  2. getMapper()实际调用的是Configuration中的getMapper()
  3. SqlSessionTemplate的构造方法中定义了一个sqlSessionProxy对象代理了一个SqlSession对象,他是最终执行sql的地方,这里可参考后面的方法15
public class SqlSessionTemplate implements SqlSession, DisposableBean {
    // 这个sqlSessionFactory实际上在你配置mybatis的配置类时 定义了@Bean返回的是sqlSessionFactory
    private final SqlSessionFactory sqlSessionFactory;
    // 构造方法
   public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,
      PersistenceExceptionTranslator exceptionTranslator) {

    notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
    notNull(executorType, "Property 'executorType' is required");

    this.sqlSessionFactory = sqlSessionFactory;
    this.executorType = executorType;
    this.exceptionTranslator = exceptionTranslator;
       // 代理对象,真正的王者在这里
    this.sqlSessionProxy = (SqlSession) newProxyInstance(SqlSessionFactory.class.getClassLoader(),
        new Class[] { SqlSession.class }, new SqlSessionInterceptor());
  }
    
    @Override
    public <T> T getMapper(Class<T> type) {
      return getConfiguration().getMapper(type, this);
    }
    @Override
  	public Configuration getConfiguration() {
    	return this.sqlSessionFactory.getConfiguration();
  	}
}

public class Configuration {
    // ......
    protected final MapperRegistry mapperRegistry;
    protected final Map<String, MappedStatement> mappedStatements;
    // 构造函数
    public Configuration{
        // ......
        this.mapperRegistry = new MapperRegistry(this);
    }
    // 这里调用的是mapperRegistry的getMapper
    public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        return this.mapperRegistry.getMapper(type, sqlSession);
    }
}
  1. 调用MapperRegistry的getMapper()方法

这里通过mapperProxyFactory创建了一个代理对象,由MapperProxy进行实际的操作

public class MapperRegistry {
    private final Configuration config;
    private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap();

    public MapperRegistry(Configuration config) {
        this.config = config;
    }
    
    // 这个type就是那个XXXMapper的接口
    public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
        if (mapperProxyFactory == null) {
            throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
        } else {
            try {
                return mapperProxyFactory.newInstance(sqlSession);
            } catch (Exception var5) {
                throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
            }
        }
    }
}

public class MapperProxyFactory<T> {
    private final Class<T> mapperInterface;
    private final Map<Method, MapperMethodInvoker> methodCache = new ConcurrentHashMap();

    public MapperProxyFactory(Class<T> mapperInterface) {
        this.mapperInterface = mapperInterface;
    }

    public Class<T> getMapperInterface() {
        return this.mapperInterface;
    }

    public Map<Method, MapperMethodInvoker> getMethodCache() {
        return this.methodCache;
    }

    // 创建代理对象并返回 代理对象的实现方法由mapperProxy实现
    protected T newInstance(MapperProxy<T> mapperProxy) {
        return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
    }

    public T newInstance(SqlSession sqlSession) {
        MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
        return this.newInstance(mapperProxy);
    }
}
执行过程
  1. MapperProxy的具体代理过程

就是当我们调用XXXMapper接口的数据库操作方法时,他会创建一个MapperMethod对象,最终会调用MapperMethod中的execute方法。

创建MapperMethod时传入了XXXMapper接口,调用方法,Configuration。具体

class MapperMethod {
private final MapperMethod.SqlCommand command;
private final MapperMethod.MethodSignature method;

public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
  this.command = new MapperMethod.SqlCommand(config, mapperInterface, method);
  this.method = new MapperMethod.MethodSignature(config, mapperInterface, method);
}
public Object execute(SqlSession sqlSession, Object[] args){
  //....
}
}
public class MapperProxy<T> implements InvocationHandler, Serializable {
    private static final long serialVersionUID = -4724728412955527868L;
    private static final int ALLOWED_MODES = 15;
    private static final Constructor<Lookup> lookupConstructor;
    private static final Method privateLookupInMethod;
    private final SqlSession sqlSession;
    private final Class<T> mapperInterface;
    private final Map<Method, MapperProxy.MapperMethodInvoker> methodCache;

    public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperProxy.MapperMethodInvoker> methodCache) {
        this.sqlSession = sqlSession;
        this.mapperInterface = mapperInterface;
        this.methodCache = methodCache;
    }
    //proxy是我们之前的sqlSessionTemplate
    //这里执行的是 this.cachedInvoker(method).invoke(proxy, method, args, this.sqlSession);
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
            return Object.class.equals(method.getDeclaringClass()) ? method.invoke(this, args) : this.cachedInvoker(method).invoke(proxy, method, args, this.sqlSession);
        } catch (Throwable var5) {
            throw ExceptionUtil.unwrapThrowable(var5);
        }
    }
    // 执行这里
    // new MapperProxy.PlainMethodInvoker(new MapperMethod(this.mapperInterface, method, this.sqlSession.getConfiguration()));
    private MapperProxy.MapperMethodInvoker cachedInvoker(Method method) throws Throwable {
        try {
            MapperProxy.MapperMethodInvoker invoker = (MapperProxy.MapperMethodInvoker)this.methodCache.get(method);
            return invoker != null ? invoker : (MapperProxy.MapperMethodInvoker)this.methodCache.computeIfAbsent(method, (m) -> {
                if (m.isDefault()) {
                    try {
                        return privateLookupInMethod == null ? new MapperProxy.DefaultMethodInvoker(this.getMethodHandleJava8(method)) : new MapperProxy.DefaultMethodInvoker(this.getMethodHandleJava9(method));
                    } catch (InstantiationException | InvocationTargetException | NoSuchMethodException | IllegalAccessException var4) {
                        throw new RuntimeException(var4);
                    }
                } else {
                    // 执行这里 创建了一个MapperMethod对象
                    return new MapperProxy.PlainMethodInvoker(new MapperMethod(this.mapperInterface, method, this.sqlSession.getConfiguration()));
                }
            });
        } catch (RuntimeException var4) {
            Throwable cause = var4.getCause();
            throw (Throwable)(cause == null ? var4 : cause);
        }
    }
    
    // 内部子类
    private static class PlainMethodInvoker implements MapperProxy.MapperMethodInvoker {
        private final MapperMethod mapperMethod;

        public PlainMethodInvoker(MapperMethod mapperMethod) {
            this.mapperMethod = mapperMethod;
        }
        // 具体调用的是这里 调用MapperMethod的execute方法
        public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {
            return this.mapperMethod.execute(sqlSession, args);
        }
    }
    
}
  1. MapperMethod的execute()方法

这里面我们挑一个executeForMany(), 他们最终都是调用sqlSession对象的方法,也就是前面的SqlSessionTemplate对象中的方法

public Object execute(SqlSession sqlSession, Object[] args) {
           Object result;
           Object param;
           switch(this.command.getType()) {
           case INSERT:
               param = this.method.convertArgsToSqlCommandParam(args);
               result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));
               break;
           case UPDATE:
               param = this.method.convertArgsToSqlCommandParam(args);
               result = this.rowCountResult(sqlSession.update(this.command.getName(), param));
               break;
           case DELETE:
               param = this.method.convertArgsToSqlCommandParam(args);
               result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));
               break;
           case SELECT:
               if (this.method.returnsVoid() && this.method.hasResultHandler()) {
                   this.executeWithResultHandler(sqlSession, args);
                   result = null;
               } else if (this.method.returnsMany()) {
                   result = this.executeForMany(sqlSession, args);
               } else if (this.method.returnsMap()) {
                   result = this.executeForMap(sqlSession, args);
               } else if (this.method.returnsCursor()) {
                   result = this.executeForCursor(sqlSession, args);
               } else {
                   param = this.method.convertArgsToSqlCommandParam(args);
                   result = sqlSession.selectOne(this.command.getName(), param);
                   if (this.method.returnsOptional() && (result == null || !this.method.getReturnType().equals(result.getClass()))) {
                       result = Optional.ofNullable(result);
                   }
               }
               break;
           case FLUSH:
               result = sqlSession.flushStatements();
               break;
           default:
               throw new BindingException("Unknown execution method for: " + this.command.getName());
           }
   
           if (result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) {
               throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ").");
           } else {
               return result;
           }
       }
   
   // 这里看execute调用的最终执行方法
   // 这里调用的是sqlSession的方法
   	private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
           Object param = this.method.convertArgsToSqlCommandParam(args);
           List result;
           if (this.method.hasRowBounds()) {
               RowBounds rowBounds = this.method.extractRowBounds(args);
               result = sqlSession.selectList(this.command.getName(), param, rowBounds);
           } else {
               result = sqlSession.selectList(this.command.getName(), param);
           }
   
           if (!this.method.getReturnType().isAssignableFrom(result.getClass())) {
               return this.method.getReturnType().isArray() ? this.convertToArray(result) : this.convertToDeclaredCollection(sqlSession.getConfiguration(), result);
           } else {
               return result;
           }
       }
  1. 转到SqlSessionTemplate.selectList()方法

SqlSessionTemplate中定义sqlSessionProxy代理对象,调用sqlSessionProxy的方法去执行DefaultSqlSession的方法,最后关闭了sqlSession导致了MyBatis的一级缓存失效,因为这里不关闭session,spring没有其他地方关闭了。

mybatis的执行sql是调用DefaultSqlSession去执行的,而spring是通过代理对象再去执行DefaultSqlSession

public class SqlSessionTemplate implements SqlSession, DisposableBean {
       // 这个sqlSessionFactory实际上在你配置mybatis的配置类时 定义了@Bean返回的是sqlSessionFactory
       private final SqlSessionFactory sqlSessionFactory;
       // 构造方法
      public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,
         PersistenceExceptionTranslator exceptionTranslator) {
   
       notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
       notNull(executorType, "Property 'executorType' is required");
   
       this.sqlSessionFactory = sqlSessionFactory;
       this.executorType = executorType;
       this.exceptionTranslator = exceptionTranslator;
          // 代理对象,真正的调用在这里
       this.sqlSessionProxy = (SqlSession) newProxyInstance(SqlSessionFactory.class.getClassLoader(),
           new Class[] { SqlSession.class }, new SqlSessionInterceptor());
      } 
       
    	@Override
    	public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
     	  return this.sqlSessionProxy.selectList(statement, parameter, rowBounds);
    	}
       
       // 子对象 他是执行sql的最终的地方
       private class SqlSessionInterceptor implements InvocationHandler {
       @Override
       public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
           // 这里的sqlsession应该就是DefaultSqlSession对象
         SqlSession sqlSession = getSqlSession(SqlSessionTemplate.this.sqlSessionFactory,
             SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);
         try {
           Object result = method.invoke(sqlSession, args);
           if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
             // force commit even on non-dirty sessions because some databases require
             // a commit/rollback before calling close()
             sqlSession.commit(true);
           }
           return result;
         } catch (Throwable t) {
           Throwable unwrapped = unwrapThrowable(t);
           if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
             // release the connection to avoid a deadlock if the translator is no loaded. See issue #22
             closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
             sqlSession = null;
             Throwable translated = SqlSessionTemplate.this.exceptionTranslator
                 .translateExceptionIfPossible((PersistenceException) unwrapped);
             if (translated != null) {
               unwrapped = translated;
             }
           }
           throw unwrapped;
         } finally {
           if (sqlSession != null) {
               // 结束时关闭了sqlsession,所以导致spring中mybatis的一级缓存失效
             closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
           }
         }
       }
     }
   
   }
对象的自动装配

在上述mybatis的分析中,实际上很多类的属性未加@Autowire都会自动注入对象的,那么到底那些属性会被自动注入呢?

  1. spring会自动扫描属性,把getXXX(),setXXX(),isXXXX()都会当作属性。(Kotlin 是用的isXXX())
  2. 如果属性值没有set方法或者手动设置不注入或者是简单类型则则不注入

简单类型:枚举,字符,数字,日期,URI/URL,class等类型;都不会装配

public static boolean isSimpleValueType(Class<?> type) {
        return Void.class != type && Void.TYPE != type && (ClassUtils.isPrimitiveOrWrapper(type) || Enum.class.isAssignableFrom(type) || CharSequence.class.isAssignableFrom(type) || Number.class.isAssignableFrom(type) || Date.class.isAssignableFrom(type) || Temporal.class.isAssignableFrom(type) || URI.class == type || URL.class == type || Locale.class == type || Class.class == type);
    }
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {
    
    protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) {
        Set<String> result = new TreeSet(); // 需要装配的属性集合
        PropertyValues pvs = mbd.getPropertyValues();
        // 这里可以获取到所有的属性
        PropertyDescriptor[] pds = bw.getPropertyDescriptors();
        PropertyDescriptor[] var6 = pds;
        int var7 = pds.length;

        for(int var8 = 0; var8 < var7; ++var8) {
            PropertyDescriptor pd = var6[var8];//属性描述器
            // 进行自动装配的判断
            // pd.getWriteMethod()是判断有没有set方法
            if (pd.getWriteMethod() != null && !this.isExcludedFromDependencyCheck(pd) && !pvs.contains(pd.getName()) && !BeanUtils.isSimpleProperty(pd.getPropertyType())) {
                result.add(pd.getName());
            }
        }

        return StringUtils.toStringArray(result);
    }
}