欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

mybatis中mapper代理的生成過(guò)程全面分析

 更新時(shí)間:2023年09月18日 11:36:58   作者:Mr_姚  
這篇文章主要為大家介紹了mybatis中mapper代理的生成過(guò)程全面分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

mybatis中mapper代理的生成過(guò)程

構(gòu)建代理類(lèi)工廠

從入口點(diǎn)開(kāi)始一步一步看,首先SqlSessionFactoryBuilder類(lèi)中build()方法加載配置文件

  public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    try {
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      // ...省略
    }
  }

將配置文件讀取為XMLConfigBuilder對(duì)象,并調(diào)用parse()方法來(lái)解析文件,進(jìn)到parse()

  public Configuration parse() {
     // ...省略
    parsed = true;
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
  }

可以看到具體的解析過(guò)程是在parseConfiguration方法中進(jìn)行的。

  private void parseConfiguration(XNode root) {
    try {
       // ...省略
      //解析mapper
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }

這里重點(diǎn)看一下最后解析mapper的方法mapperElement(root.evalNode("mappers")),進(jìn)到方法里,

  private void mapperElement(XNode parent) throws Exception {
    if (parent != null) {
      for (XNode child : parent.getChildren()) {
        if ("package".equals(child.getName())) {
          //   package 形式加載 ,加載package下的所有class文件
          String mapperPackage = child.getStringAttribute("name");
          configuration.addMappers(mapperPackage);
        } else {
          String resource = child.getStringAttribute("resource");
          String url = child.getStringAttribute("url");
          String mapperClass = child.getStringAttribute("class");
          if (resource != null && url == null && mapperClass == null) {
            // 通過(guò)Mapper.xml 加載
            ErrorContext.instance().resource(resource);
            InputStream inputStream = Resources.getResourceAsStream(resource);
            XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
            mapperParser.parse();
          } else if (resource == null && url != null && mapperClass == null) {
            // 通過(guò)Mapper.xml 加載
            ErrorContext.instance().resource(url);
            InputStream inputStream = Resources.getUrlAsStream(url);
            XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
            mapperParser.parse();
          } else if (resource == null && url == null && mapperClass != null) {
            // 通過(guò)單個(gè)class文件加載
            Class<?> mapperInterface = Resources.classForName(mapperClass);
            configuration.addMapper(mapperInterface);
          } else {
            throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
          }
        }
      }
    }
  }

整個(gè)mapperElement()方法就是加載mapper的過(guò)程了,可以看到加載mapper
有兩種形式:通過(guò)class文件和通過(guò)xml文件。

構(gòu)建mapper代理的過(guò)程也就是從這開(kāi)始的,那就一步一步分析。

看一下通過(guò)XML文件加載的過(guò)程,mybatis將mapper相關(guān)的配置讀取為一個(gè)XMLMapperBuilder對(duì)象,并通過(guò)parse()方法進(jìn)行解析,進(jìn)到這個(gè)方法中

  public void parse() {
    if (!configuration.isResourceLoaded(resource)) {
      // 加載xml文件
      configurationElement(parser.evalNode("/mapper"));
      configuration.addLoadedResource(resource);
      // 加載mapper class文件
      bindMapperForNamespace();
    }
   // ...省略
  }

parse()方法做了主要做了兩件事,加載xml文件和加載class文件。

看一下加載xml的過(guò)程

  private void configurationElement(XNode context) {
    try {
      // 獲取xml文件的namespace
      String namespace = context.getStringAttribute("namespace");
      if (namespace == null || namespace.equals("")) {
        throw new BuilderException("Mapper's namespace cannot be empty");
      }
      // 保存獲取xml文件的namespace
      builderAssistant.setCurrentNamespace(namespace);
       // ...省略
    } catch (Exception e) {
      throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e);
    }
  }

本文是分析mapper代理的生成過(guò)程,所以加載xml的具體細(xì)節(jié)就不詳細(xì)分析了,這里注意的是讀取xml文件中namespace標(biāo)簽的值,并將值設(shè)置到builderAssistant對(duì)象中
現(xiàn)在回過(guò)頭來(lái)看一下加載class文件的過(guò)程。進(jìn)到bindMapperForNamespace()方法中去

  private void bindMapperForNamespace() {
    // 獲取xml文件中設(shè)置的namespace值
    String namespace = builderAssistant.getCurrentNamespace();
    if (namespace != null) {
      Class<?> boundType = null;
      try {
        // 加載類(lèi)
        boundType = Resources.classForName(namespace);
      } catch (ClassNotFoundException e) {
        //ignore, bound type is not required
      }
      if (boundType != null) {
        if (!configuration.hasMapper(boundType)) {
          // Spring may not know the real resource name so we set a flag
          // to prevent loading again this resource from the mapper interface
          // look at MapperAnnotationBuilder#loadXmlResource
          configuration.addLoadedResource("namespace:" + namespace);
          // 添加到configuration中
          configuration.addMapper(boundType);
        }
      }
    }
  }

bindMapperForNamespace()通過(guò)xml文件中設(shè)置的namespace值加載對(duì)應(yīng)的mapper接口,最后通過(guò)configuration.addMapper()添加到configuration中。

還記不記得剛才提到的加載mapper有兩種形式:通過(guò)class文件和通過(guò)xml文件。通過(guò)class文件的方式直接調(diào)用configuration.addMapper()將mapper接口加載到了configuration 中了。

Configuration是mybatis的全局配置類(lèi),所有的mybatis相關(guān)的信息都保存在Configuration中。
繼續(xù)進(jìn)到ConfigurationaddMapper方法中

  public <T> void addMapper(Class<T> type) {
    mapperRegistry.addMapper(type);
  }

Configuration把對(duì)應(yīng)的mapper接口添加到mapperRegistry中,再進(jìn)到mapperRegistry.addMapper()方法中

  public <T> void addMapper(Class<T> type) {
    if (type.isInterface()) {
        // ...省略
      try {
        knownMappers.put(type, new MapperProxyFactory<T>(type));
         // ...省略
      } finally {
        if (!loadCompleted) {
          knownMappers.remove(type);
        }
      }
    }
  }

該方法首先判斷是否是接口,如果是接口則將mapper接口添加到knownMappers中。
看一下knownMappers的定義

  private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();

knownMappers是一個(gè)HashMap,它保存的是所有的mapper接口和對(duì)應(yīng)的mapper代理工廠。

到現(xiàn)在為止,mapper已經(jīng)加載完了,但是并沒(méi)有生成mapper的代理對(duì)象,只是生成了對(duì)應(yīng)的代理工廠。

生成并使用代理對(duì)象

mybatis并沒(méi)有在加載mapper接口的時(shí)候生成代理對(duì)象,而是在調(diào)用的時(shí)候生成的。
首先從入口開(kāi)始

sqlSession.getMapper(XXX.class)

sqlSession默認(rèn)是DefaultSqlSession。進(jìn)到DefaultSqlSessiongetMapper()方法中

  @Override
  public <T> T getMapper(Class<T> type) {
    return configuration.<T>getMapper(type, this);
  }

繼續(xù)到ConfigurationgetMapper

 public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
  }

繼續(xù)到mapperRegistry.getMapper()

  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    // ...省略
    }
    try {
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }

knownMappers中獲取到對(duì)應(yīng)mapper接口的代理工廠類(lèi)MapperProxyFactory,然后通過(guò)MapperProxyFactory獲取真正的代理對(duì)象。進(jìn)到MapperProxyFactorynewInstance()方法中

  public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }
   protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

首先生成了MapperProxy類(lèi),再通過(guò)Proxy生成真正的代理類(lèi)。
看一下MapperProxy類(lèi)

public class MapperProxy<T> implements InvocationHandler, Serializable {
  //  ...省略
}

MapperProxy實(shí)現(xiàn)了InvocationHandler接口,mapper接口的具體處理邏輯也就是在這類(lèi)中處理。

到此為止,代理對(duì)象才真正的生成。

與Spring集成時(shí)mapper代理的生成過(guò)程

mybatis與Spring集成時(shí)需要用到mybatis-spring的jar。

Spring注冊(cè)mapper代理類(lèi)

既然是與Spring集成,那么就要配置一下,將mybatis交給Spring管理。

spring的xml文件配置

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="driverClassName"/>
        <property name="url" value="url"/>
        <property name="username" value="username"/>
        <property name="password" value="password"/>
    </bean>
    <!--sqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <!--綁定mybatis配置文件-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <!--注冊(cè)Mapper.xm映射器-->
        <property name="mapperLocations" value="classpath:cn/ycl/mapper/*.xml"/>
    </bean>
    <!--注冊(cè)所有mapper-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!--basePackage 屬性是映射器接口文件的包路徑。-->
        <!--你可以使用分號(hào)或逗號(hào) 作為分隔符設(shè)置多于一個(gè)的包路徑-->
        <property name="basePackage" value="cn/ycl/mapper"/>
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
    </bean>

將mybatis交給Spring只需要配置3個(gè)bean就可以了

1、 數(shù)據(jù)庫(kù)相關(guān)的dataSource

2、 mybatis的sqlSessionFactory

3、 將mapper委托給Spring的工具類(lèi)MapperScannerConfigurer生成mapper代理的過(guò)程主要在MapperScannerConfigurer里,看一下MapperScannerConfigurer的定義

public class MapperScannerConfigurer
    implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {
    // ...省略
}

關(guān)鍵點(diǎn)在MapperScannerConfigurer 實(shí)現(xiàn)了BeanDefinitionRegistryPostProcessor,BeanDefinitionRegistryPostProcessor是Spring留的擴(kuò)展點(diǎn),可以往Spring中注冊(cè)自定義的bean。

MapperScannerConfigurer中實(shí)現(xiàn)了BeanDefinitionRegistryPostProcessorpostProcessBeanDefinitionRegistry()方法,mapper的注冊(cè)就是在該方法中注冊(cè)的

  public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
    // ...省略
    // 實(shí)例化ClassPathMapperScanner,并對(duì)scanner相關(guān)屬性進(jìn)行配置
    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);
    }
    // 注冊(cè)掃描規(guī)則
    scanner.registerFilters();
    // 掃描并注冊(cè)所有的mapper
    scanner.scan(
        StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
  }

postProcessBeanDefinitionRegistry()的主要邏輯是定義一個(gè)ClassPathMapperScanner對(duì)象,然后調(diào)用registerFilters()注冊(cè)掃描規(guī)則,最后調(diào)用scan()方法。

在xml中定義MapperScannerConfigurerbean時(shí)可以設(shè)置一個(gè)annotationClass屬性,值是一個(gè)注解類(lèi),調(diào)用registerFilters()時(shí),registerFilters()會(huì)添加一個(gè)只掃描設(shè)置有annotationClass注解的類(lèi),這里沒(méi)有設(shè)置,會(huì)掃描所有的接口。SpringBoot集成mybatis時(shí)會(huì)用到這個(gè)字段

看一下ClassPathMapperScanner類(lèi)的定義

public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
    // ...省略
}

ClassPathMapperScanner繼承了ClassPathBeanDefinitionScanner,ClassPathBeanDefinitionScanner是Spring中定義的,是一個(gè)從指定包內(nèi)掃描所有bean定義的Spring工具。

看一下ClassPathMapperScannerscan()方法

  public Set&lt;BeanDefinitionHolder&gt; doScan(String... basePackages) {
    Set&lt;BeanDefinitionHolder&gt; beanDefinitions = super.doScan(basePackages);

    if (beanDefinitions.isEmpty()) {
        // ...省略
    } else {
      processBeanDefinitions(beanDefinitions);
    }

    return beanDefinitions;
  }

通過(guò)super.doScan(basePackages)已經(jīng)掃描到了所有的mapper,繼續(xù)processBeanDefinitions()方法

  private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
    AbstractBeanDefinition definition;
    BeanDefinitionRegistry registry = getRegistry();
    // 遍歷掃描到的所有bean
    for (BeanDefinitionHolder holder : beanDefinitions) {
      definition = (AbstractBeanDefinition) holder.getBeanDefinition();
      boolean scopedProxy = false;
      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");
      // 增加一個(gè)構(gòu)造方法,接口類(lèi)型作為構(gòu)造函數(shù)的入?yún)?
      definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); 
      // 將bean的類(lèi)型轉(zhuǎn)換成mapperFactoryBean
      definition.setBeanClass(this.mapperFactoryBeanClass);
      // 增加addToConfig屬性
      definition.getPropertyValues().add("addToConfig", this.addToConfig);
      definition.setAttribute(FACTORY_BEAN_OBJECT_TYPE, beanClassName);
      boolean explicitFactoryUsed = false;
      // 增加sqlSessionFactory屬性
      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;
      }
      // 增加sqlSessionTemplate屬性
      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() + "'.");
        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());
      }
    }
  }

這個(gè)方法比較長(zhǎng),但是并不復(fù)雜,主要邏輯為將掃描的bean的類(lèi)型修改成MapperFactoryBean類(lèi)型,并增加一個(gè)將接口類(lèi)型作為入?yún)⒌臉?gòu)造函數(shù),也就是說(shuō)Spring獲取mapper時(shí)都是通過(guò)FactoryBean生成的。最后通過(guò)調(diào)用egistry.registerBeanDefinition() 方法注冊(cè)到Spring中。

看一下mybatis提供的MapperFactoryBean的定義

public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
}

MapperFactoryBean實(shí)現(xiàn)了FactoryBean,FactoryBean是一個(gè)Spring提供的一個(gè)能生產(chǎn)對(duì)象的工廠Bean

MapperFactoryBean同時(shí)繼承了SqlSessionDaoSupport,SqlSessionDaoSupport繼承了DaoSupportDaoSupport實(shí)現(xiàn)了InitializingBean。InitializingBean的作用是在Spring初始化bean對(duì)象時(shí)會(huì)首先調(diào)用InitializingBeanafterPropertiesSet()方法。

DaoSupportafterPropertiesSet()中調(diào)用了checkDaoConfig()方法。

    public final void afterPropertiesSet() throws IllegalArgumentException, BeanInitializationException {
        this.checkDaoConfig();

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

具體checkDaoConfig()方法的實(shí)現(xiàn)邏輯在MapperFactoryBean

 protected void checkDaoConfig() {
    super.checkDaoConfig();

    notNull(this.mapperInterface, "Property 'mapperInterface' is required");

    Configuration configuration = getSqlSession().getConfiguration();
    if (this.addToConfig &amp;&amp; !configuration.hasMapper(this.mapperInterface)) {
      try {
        configuration.addMapper(this.mapperInterface);
      } catch (Exception e) {
        // ..省略
      } finally {
        ErrorContext.instance().reset();
      }
    }
  }

OK,到這又回到mybatis了。在前面中說(shuō)了configuration.addMapper()方法只是生成了對(duì)應(yīng)的代理工廠。

以上整個(gè)過(guò)程,即把mapper注冊(cè)為Spring的bean,又將mapper設(shè)置到mybatis中的configuration中,所以,在使用時(shí)既可以使用Spring自動(dòng)注入那一套,又可以使用mybatis中通過(guò)sqlSession來(lái)獲取mapper的代理對(duì)象

Spring生成代理對(duì)象

Spring中所有的mapper對(duì)應(yīng)的bean是mapper對(duì)應(yīng)的MapperFactoryBean,那么在獲取mapper bean時(shí)是通過(guò)MapperFactoryBeangetObject()方法生成的

  public T getObject() throws Exception {
    return getSqlSession().getMapper(this.mapperInterface);
  }

MapperFactoryBean先獲取到sqlsession,再通過(guò)getMapper()獲取到的代理對(duì)象。到這里就回到了mybatis生成代理對(duì)象的過(guò)程了。

與SpringBoot集成時(shí)mapper代理的生成過(guò)程

mybatis與Spring集成時(shí)需要用到mybatis-spring-boot-starter的jar,mybatis-spring-boot-starter依賴(lài)mybatis-spring-boot-autoconfigure這個(gè)jar,而mybatis-spring-boot-autoconfigure這個(gè)jar又依賴(lài)mybatis-spring這個(gè)jar,所以最終其實(shí)還是mybatis集成Spring那一套

根據(jù)SpringBoot自動(dòng)加載的原理直接看mybatis-spring-boot-autoconfigurejar下META-INF/spring.factories文件

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration,\
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

SpringBoot會(huì)自動(dòng)加載MybatisAutoConfiguration這個(gè)類(lèi),直接看這個(gè)類(lèi),MybatisAutoConfiguration定義了mybtis所需的各個(gè)bean。

    //生成SqlSessionFactory
    @Bean
    @ConditionalOnMissingBean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        // ...省略
    }
    //生成SqlSessionTemplate
    @Bean
    @ConditionalOnMissingBean
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
     // ...省略
    }
    //掃描mapper
     @Configuration
    @Import({MybatisAutoConfiguration.AutoConfiguredMapperScannerRegistrar.class})
    @ConditionalOnMissingBean({MapperFactoryBean.class, MapperScannerConfigurer.class})
    public static class MapperScannerRegistrarNotFoundConfiguration implements InitializingBean {
        public MapperScannerRegistrarNotFoundConfiguration() {
        }
        public void afterPropertiesSet() {
            MybatisAutoConfiguration.logger.debug("Not found configuration for registering mapper bean using @MapperScan, MapperFactoryBean and MapperScannerConfigurer.");
        }
    }
     //掃描mapper
     public static class AutoConfiguredMapperScannerRegistrar implements BeanFactoryAware, ImportBeanDefinitionRegistrar {
        private BeanFactory beanFactory;
        public AutoConfiguredMapperScannerRegistrar() {
        }
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            if (!AutoConfigurationPackages.has(this.beanFactory)) {
                MybatisAutoConfiguration.logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.");
            } else {
                MybatisAutoConfiguration.logger.debug("Searching for mappers annotated with @Mapper");
                List<String> packages = AutoConfigurationPackages.get(this.beanFactory);
                if (MybatisAutoConfiguration.logger.isDebugEnabled()) {
                    packages.forEach((pkg) -> {
                        MybatisAutoConfiguration.logger.debug("Using auto-configuration base package '{}'", pkg);
                    });
                }
                //生成MapperScannerConfigurer 
                BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
                builder.addPropertyValue("processPropertyPlaceHolders", true);
                // 注冊(cè)掃描規(guī)則
                builder.addPropertyValue("annotationClass", Mapper.class);
                builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(packages));
                BeanWrapper beanWrapper = new BeanWrapperImpl(MapperScannerConfigurer.class);
                Stream.of(beanWrapper.getPropertyDescriptors()).filter((x) -> {
                    return x.getName().equals("lazyInitialization");
                }).findAny().ifPresent((x) -> {
                    builder.addPropertyValue("lazyInitialization", "${mybatis.lazy-initialization:false}");
                });
                registry.registerBeanDefinition(MapperScannerConfigurer.class.getName(), builder.getBeanDefinition());
            }
        }
        public void setBeanFactory(BeanFactory beanFactory) {
            this.beanFactory = beanFactory;
        }
    }
    

以上就是mybatis中mapper代理的生成過(guò)程全面分析的詳細(xì)內(nèi)容,更多關(guān)于mybatis mapper代理生成的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • JavaWeb三大組件之一的Filter詳解

    JavaWeb三大組件之一的Filter詳解

    本篇文章主要介紹了JavaWeb三大組件之中的Filter過(guò)濾器詳解,實(shí)例分析了JavaWeb之Filter過(guò)濾器的使用技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2022-06-06
  • SpringMVC 參數(shù)綁定相關(guān)知識(shí)總結(jié)

    SpringMVC 參數(shù)綁定相關(guān)知識(shí)總結(jié)

    這篇文章主要介紹了SpringMVC 參數(shù)綁定相關(guān)知識(shí)總結(jié),幫助大家更好的理解和學(xué)習(xí)使用SpringMVC,感興趣的朋友可以了解下
    2021-03-03
  • java8 LocalDate LocalDateTime等時(shí)間類(lèi)用法實(shí)例分析

    java8 LocalDate LocalDateTime等時(shí)間類(lèi)用法實(shí)例分析

    這篇文章主要介紹了java8 LocalDate LocalDateTime等時(shí)間類(lèi)用法,結(jié)合具體實(shí)例形式分析了LocalDate、LocalTime、LocalDateTime等日期時(shí)間相關(guān)類(lèi)的功能與具體使用技巧,需要的朋友可以參考下
    2017-04-04
  • Java中System.setProperty()用法與實(shí)際應(yīng)用場(chǎng)景

    Java中System.setProperty()用法與實(shí)際應(yīng)用場(chǎng)景

    System.setProperty是Java中用于設(shè)置系統(tǒng)屬性的方法,它允許我們?cè)谶\(yùn)行時(shí)為Java虛擬機(jī)(JVM)或應(yīng)用程序設(shè)置一些全局的系統(tǒng)屬性,下面這篇文章主要給大家介紹了關(guān)于Java中System.setProperty()用法與實(shí)際應(yīng)用場(chǎng)景的相關(guān)資料,需要的朋友可以參考下
    2024-04-04
  • SpringBoot之核心依賴(lài)和自動(dòng)配置方式

    SpringBoot之核心依賴(lài)和自動(dòng)配置方式

    這篇文章主要介紹了SpringBoot之核心依賴(lài)和自動(dòng)配置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • Java實(shí)現(xiàn)的數(shù)字簽名算法RSA完整示例

    Java實(shí)現(xiàn)的數(shù)字簽名算法RSA完整示例

    這篇文章主要介紹了Java實(shí)現(xiàn)的數(shù)字簽名算法RSA,結(jié)合完整實(shí)例形式詳細(xì)分析了RSA算法的相關(guān)概念、原理、實(shí)現(xiàn)方法及操作技巧,需要的朋友可以參考下
    2019-09-09
  • Java圖片上傳實(shí)現(xiàn)代碼

    Java圖片上傳實(shí)現(xiàn)代碼

    這篇文章主要為大家詳細(xì)介紹了Java圖片上傳實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-05-05
  • SpringBoot下載文件的正確解法方式

    SpringBoot下載文件的正確解法方式

    這篇文章主要給大家介紹了關(guān)于SpringBoot下載文件的正確解法方式,SpringBoot是一款流行的框架,用于開(kāi)發(fā)Web應(yīng)用程序,在使用SpringBoot構(gòu)建Web應(yīng)用程序時(shí),可能需要實(shí)現(xiàn)文件下載的功能,需要的朋友可以參考下
    2023-08-08
  • MyBatis 實(shí)現(xiàn)數(shù)據(jù)的批量新增和刪除的操作

    MyBatis 實(shí)現(xiàn)數(shù)據(jù)的批量新增和刪除的操作

    這篇文章主要介紹了MyBatis 實(shí)現(xiàn)數(shù)據(jù)的批量新增和刪除的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-02-02
  • 詳解Spring關(guān)于@Resource注入為null解決辦法

    詳解Spring關(guān)于@Resource注入為null解決辦法

    這篇文章主要介紹了詳解Spring關(guān)于@Resource注入為null解決辦法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05

最新評(píng)論