zoukankan      html  css  js  c++  java
  • 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);
      }
  • 相关阅读:
    Oracle Core 学习笔记二 Transactions 和 Consistency 说明
    Oracle AUTO_SPACE_ADVISOR_JOB 说明
    Windows 下 ftp 上传文件 脚本
    Oracle 11g 中 Direct path reads 特性 说明
    Linux 使用 wget 下载 Oracle 软件说明
    Oracle 10g read by other session 等待 说明
    Oracle 11g RAC INS06006 Passwordless SSH connectivity not set up between the following node(s) 解决方法
    SecureCRT 工具 上传下载数据 与 ASCII、Xmodem、Ymodem 、Zmodem 说明
    Oracle RAC root.sh 报错 Timed out waiting for the CRS stack to start 解决方法
    Oracle RESETLOGS 和 NORESETLOGS 区别说明
  • 原文地址:https://www.cnblogs.com/honger/p/9519300.html
Copyright © 2011-2022 走看看