spring與mybatis整合(掃描Mapper接口)


<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"></property>
        <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"></property>
        <!-- 定義別名 -->
        <property name="typeAliasesPackage" value="com.booway.pojo"></property>

        <!-- 配置映射文件的位置,如果配置文件與mapper接口在同一個位置,可以不寫 -->
        <!-- <property name="mapperLocations" value="classpath:mybatis/mapper/*.xml"></property>  -->
         <!-- <property name="mapperLocations">
            <array>
                <value>classpath:mybatis/mapper/User.xml</value>
            </array>
        </property> -->
        
    </bean>

    <!-- 將mybatis實現的接口注入到spring容器中 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
        <property name="basePackage" value="com.booway.mapper"></property>
    </bean>


看下這個類的實現MapperScannerConfigurer

類申明為:
public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware

這個類實現了BeanDefinitionRegistryPostProcessor,InitializingBean,ApplicationContextAware,BeanNameAware接口

實現了BeanDefinitionRegistryPostProcessor接口意味着在beanDefinition注冊之后就會調用這個接口的postProcessBeanDefinitionRegistry方法。實現了InitializingBean接口意味在bean創建初始化時會調用afterPropertiesSet方法。ApplicationContextAware意味着會注入application實例,BeanNameAware意味着會注入這個bean當前的beanName


這幾個接口使用的順序為,BeanDefinitionRegistryPostProcessor,BeanNameAware,ApplicationContextAware,InitializingBean


1、先來看BeanDefinitionRegistryPostProcessor接口的實現方法

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
    if (this.processPropertyPlaceHolders) {//處理站位符
      processPropertyPlaceHolders();
    }

    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.registerFilters();
//掃描指定包下的類,將com.test.a,com.test,b拆分為數組
    scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
  }


public void registerFilters() {
    boolean acceptAllInterfaces = true;//默認獲取所有的接口作為mybatis的mapper接口

    // if specified, use the given annotation and / or marker interface
    if (this.annotationClass != null) {
//如果指定了標記的注解類型,那么就使用這個注解來標記mybatis的mapper接口
      addIncludeFilter(new AnnotationTypeFilter(this.annotationClass));
      acceptAllInterfaces = false;
    }

    // override AssignableTypeFilter to ignore matches on the actual marker interface
//通過標記的接口來識別是不是mapper接口,只要繼承了指定接口的就是,不過此處的邏輯認為繼承了這個接口的就返回false,也就是不是mybatis的mapper接口
    if (this.markerInterface != null) {
      addIncludeFilter(new AssignableTypeFilter(this.markerInterface) {
        @Override
        protected boolean matchClassName(String className) {
          return false;
        }
      });
      acceptAllInterfaces = false;
    }
//如果acceptAllInterfaces為true,也就是沒有指定任何篩選邏輯,那么認為任何接口都返回true
    if (acceptAllInterfaces) {
      // default include filter that accepts all classes
      addIncludeFilter(new TypeFilter() {
        @Override
        public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
          return true;
        }
      });
    }
//排除package-info.java
    // exclude package-info.java
    addExcludeFilter(new TypeFilter() {
      @Override
      public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        String className = metadataReader.getClassMetadata().getClassName();
        return className.endsWith("package-info");
      }
    });
  }



public int scan(String... basePackages) {
//獲取已經注冊bean的個數
        int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
//掃描
        doScan(basePackages);

        // Register annotation config processors, if necessary.如果包含注解配置,那么就注冊注解配置處理器。
        if (this.includeAnnotationConfig) {
            AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
        }
//新增加的beandefinitoinCount就是mybatis掃描添加的。
        return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
    }

 @Override
  public Set<BeanDefinitionHolder> doScan(String... basePackages) {
    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 {
//處理獲取到的beanDefinition
      processBeanDefinitions(beanDefinitions);
    }

    return beanDefinitions;
  }

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Assert.notEmpty(basePackages, "At least one base package must be specified");
        Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();
        for (String basePackage : basePackages) {
//獲取候選組件
            Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
            for (BeanDefinition candidate : candidates) {
//獲取范圍元數據,通過類獲取這個類的scope范圍還有代理模式
                ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
//將解析出來的scope設置到beanDefinition中
                candidate.setScope(scopeMetadata.getScopeName());
//使用命名生成器生成beanName
                String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
                if (candidate instanceof AbstractBeanDefinition) {
//給這個beanDefinition設置默認的屬性,比如默認的lazy屬性啊,等等
                    postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
                }
                if (candidate instanceof AnnotatedBeanDefinition) {
                //設置注解配置的一些屬性    AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
                }
//檢查候選beanDefinition類,以確定是否可以要進行注冊,防止重復注冊
                if (checkCandidate(beanName, candidate)) {
                    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                    definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                    beanDefinitions.add(definitionHolder);
                    registerBeanDefinition(definitionHolder, this.registry);
                }
            }
        }
        return beanDefinitions;
    }





public Set<BeanDefinition> findCandidateComponents(String basePackage) {
        Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();
        try {
//classpath*:com/test/a/**/*.class
            String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                    resolveBasePackage(basePackage) + "/" + this.resourcePattern;
            Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);//通過spring的PathMatchingResourcePatternResolver,獲取到所有符合條件的class資源
            boolean traceEnabled = logger.isTraceEnabled();
            boolean debugEnabled = logger.isDebugEnabled();
            for (Resource resource : resources) {
                if (traceEnabled) {
                    logger.trace("Scanning " + resource);
                }
                if (resource.isReadable()) {//如果是這個資源是可讀的
                    try {
                        MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);//將類包裝成元數據讀取器,底層使用的ASM框架。
                        if (isCandidateComponent(metadataReader)) {//通過過濾器配置這個類是否是候選組件
                            ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);//這個類繼承自GenericBeanDefinition
                            sbd.setResource(resource);
                            sbd.setSource(resource);
//判斷這個類是不是獨立的,是不是具體的(即不是抽象或接口,可以被繼承)
                            if (isCandidateComponent(sbd)) {
                                if (debugEnabled) {
                                    logger.debug("Identified candidate component class: " + resource);
                                }
                                candidates.add(sbd);
                            }
                            else {
                                if (debugEnabled) {
                                    logger.debug("Ignored because not a concrete top-level class: " + resource);
                                }
                            }
                        }
                        else {
                            if (traceEnabled) {
                                logger.trace("Ignored because not matching any filter: " + resource);
                            }
                        }
                    }
                    catch (Throwable ex) {
                        throw new BeanDefinitionStoreException(
                                "Failed to read candidate component class: " + resource, ex);
                    }
                }
                else {
                    if (traceEnabled) {
                        logger.trace("Ignored because not readable: " + resource);
                    }
                }
            }
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
        }
        return candidates;
    }



protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
//判斷當前類是否是排除的,如果是被排除,那么就不是候選的mapper
接口
        for (TypeFilter tf : this.excludeFilters) {
            if (tf.match(metadataReader, this.metadataReaderFactory)) {
                return false;
            }
        }
//判斷當前類是否被包含
        for (TypeFilter tf : this.includeFilters) {
            if (tf.match(metadataReader, this.metadataReaderFactory)) {
                return isConditionMatch(metadataReader);
            }
        }
        return false;
    }


@Override
    public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
        ScopeMetadata metadata = new ScopeMetadata();
        if (definition instanceof AnnotatedBeanDefinition) {
            AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
            AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(annDef.getMetadata(), this.scopeAnnotationType);
            if (attributes != null) {
//獲取Scope注解的value屬性值
                metadata.setScopeName(attributes.getAliasedString("value", this.scopeAnnotationType, definition.getSource()));
//獲取proxyMode屬性指定的代理模式
                ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");
                if (proxyMode == null || proxyMode == ScopedProxyMode.DEFAULT) {
                    proxyMode = this.defaultProxyMode;
                }
                metadata.setScopedProxyMode(proxyMode);
            }
        }
        return metadata;
    }


這樣就將定義的類變成了beanDefinition注冊到spring中



private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
    GenericBeanDefinition definition;
    for (BeanDefinitionHolder holder : beanDefinitions) {
      definition = (GenericBeanDefinition) holder.getBeanDefinition();

      if (logger.isDebugEnabled()) {
        logger.debug("Creating MapperFactoryBean with name '" + holder.getBeanName() 
          + "' and '" + definition.getBeanClassName() + "' mapperInterface");
      }

      // the mapper interface is the original class of the bean
      // but, the actual class of the bean is MapperFactoryBean
  //給這個 beanDefinition定義構造參數為自己,因為下面會定義FactoryBean
definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); // issue #59
//設置工廠bean
      definition.setBeanClass(this.mapperFactoryBean.getClass());
//設置addToConfig屬性
      definition.getPropertyValues().add("addToConfig", this.addToConfig);
//使用指定的工廠
      boolean explicitFactoryUsed = false;
      if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {//如果指定了sqlSessionFactory,表示配置文件中已經配置了對應的beanName
        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;
      }
//如果沒有指定明確的工廠bean使用,那么就設置轉配模式為按類型進行裝配,讓spring自己到容器中找到對應bean進行裝配。
      if (!explicitFactoryUsed) {
        if (logger.isDebugEnabled()) {
          logger.debug("Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
        }
        definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
      }
    }
  }


那么問題來了,既然最后把所有的類的都變為了MapperFactoryBean來創造,那么這個MapperFactoryBean是怎么構造這些接口的實現類的呢?

MapperFactoryBean實現了FactoryBean接口




//MapperFactoryBean的類定義
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {

  private Class<T> mapperInterface;

  private boolean addToConfig = true;

  public MapperFactoryBean() {
    //intentionally empty 
  }
  //這個構造參數在上面的分析中已經看到,它把對應Mapper接口設置進來了
  public MapperFactoryBean(Class<T> mapperInterface) {
    this.mapperInterface = mapperInterface;
  }

  /**
   * {@inheritDoc}
   */
  @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 {
        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();
      }
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public T getObject() throws Exception {
    return getSqlSession().getMapper(this.mapperInterface);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public Class<T> getObjectType() {
    return this.mapperInterface;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public boolean isSingleton() {
    return true;
  }

  //------------- mutators --------------

  /**
   * Sets the mapper interface of the MyBatis mapper
   *
   * @param mapperInterface class of the interface
   */
  public void setMapperInterface(Class<T> mapperInterface) {
    this.mapperInterface = mapperInterface;
  }

  /**
   * Return the mapper interface of the MyBatis mapper
   *
   * @return class of the interface
   */
  public Class<T> getMapperInterface() {
    return mapperInterface;
  }

  /**
   * If addToConfig is false the mapper will not be added to MyBatis. This means
   * it must have been included in mybatis-config.xml.
   * <p/>
   * If it is true, the mapper will be added to MyBatis in the case it is not already
   * registered.
   * <p/>
   * By default addToCofig is true.
   *
   * @param addToConfig
   */
  public void setAddToConfig(boolean addToConfig) {
    this.addToConfig = addToConfig;
  }

  /**
   * Return the flag for addition into MyBatis config.
   *
   * @return true if the mapper will be added to MyBatis in the case it is not already
   * registered.
   */
  public boolean isAddToConfig() {
    return addToConfig;
  }
}


//底層就是使用的mybatis獲取接口實現的方法。
public T getObject() throws Exception {
    return getSqlSession().getMapper(this.mapperInterface);
  }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM