Spring源码剖析(三) [新]Mybatis-Spring最全最详细的调用和执行过程解析

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

解析mybatis-spring源码

启动流程
  1. Mybatis配置类中的MapperScan

    @Configuration
    @EnableTransactionManagement
    @MapperScan(basePackages = DataSourceConfiguration.PACKAGE, sqlSessionFactoryRef = DataSourceConfiguration.SQL_SESSION_FACTORY)
    public class DataSourceConfiguration {}
    
  2. MapperScan中加了@Import注解

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE})
    @Documented
    @Import({MapperScannerRegistrar.class})
    @Repeatable(MapperScans.class)
    public @interface MapperScan{}
    
  3. 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());
      }
    }
    
  4. 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));
      }
    
  5. 扫描类父类的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;
        }
    
  6. 调用扫描类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;
      }
    
  7. 再次进入父类的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;
        }
    
  8. 扩展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());
          }
        }
      }
    
  9. 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();
             }
           }
         }
       
       }
    
  10. 父类 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 {
        }
    }
    
  11. 调用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);
        }
    }
    
  12. 调用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);
            }
        }
        
    }
    
  2. 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;
               }
           }
    
  3. 转到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);
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BugGuys

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值