欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

Mybatis-spring自動(dòng)注入機(jī)制原理

這篇文章主要介紹“Mybatis-spring自動(dòng)注入機(jī)制原理”,在日常操作中,相信很多人在Mybatis-spring自動(dòng)注入機(jī)制原理問題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”Mybatis-spring自動(dòng)注入機(jī)制原理”的疑惑有所幫助!接下來,請(qǐng)跟著小編一起來學(xué)習(xí)吧!

成都創(chuàng)新互聯(lián)公司從2013年成立,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項(xiàng)目成都網(wǎng)站制作、成都做網(wǎng)站、外貿(mào)營銷網(wǎng)站建設(shè)網(wǎng)站策劃,項(xiàng)目實(shí)施與項(xiàng)目整合能力。我們以讓每一個(gè)夢(mèng)想脫穎而出為使命,1280元新林做網(wǎng)站,已為上家服務(wù),為新林各地企業(yè)和個(gè)人服務(wù),聯(lián)系電話:13518219792

一、基礎(chǔ)背景

本篇文章的主要目的有兩個(gè):

  • 項(xiàng)目中使用mybatis,我們只定義了mapper的接口,并沒有實(shí)現(xiàn),那這些實(shí)現(xiàn)類的bean是如何生成的?

  • mapper接口的實(shí)例bean是如何注入到spring容器的?

包名版本號(hào)
spring-boot2.1.9.RELEASE
mybatis-spring2.0.0
mybatis-plus-boot-starter3.1.0
mybatis3.5.0

二、源碼分析

項(xiàng)目中我們使用@MapperScan來配置mapper接口的路徑,如下圖

@EnableTransactionManagement
@Configuration
@MapperScan("com.ke.newhouse.agency.project.dao.mapper")
public class MybatisPlusConfiguration {
 
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }
}

在這些mapper路徑下都是我們定義的接口,@MapperScan的作用有哪些呢,我們先看下@MapperScan的定義

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
@Repeatable(MapperScans.class)
public @interface MapperScan {
}

在MapperScan的定義中我們目前只需要關(guān)注@Import(MapperScannerRegistrar.class),其含義是將MapperScannerRegistrar.class引入到spring容器中

public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
 
  private ResourceLoader resourceLoader;

  /**
   * {@inheritDoc}
   */
  @Override
  public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    AnnotationAttributes mapperScanAttrs = AnnotationAttributes
        .fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
    if (mapperScanAttrs != null) {
      registerBeanDefinitions(mapperScanAttrs, registry);
    }
  }
 
  void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry) {
 
    ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
 
    // this check is needed in Spring 3.1
    Optional.ofNullable(resourceLoader).ifPresent(scanner::setResourceLoader);
 
    Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
    if (!Annotation.class.equals(annotationClass)) {
      scanner.setAnnotationClass(annotationClass);
    }
 
    Class<?> markerInterface = annoAttrs.getClass("markerInterface");
    if (!Class.class.equals(markerInterface)) {
      scanner.setMarkerInterface(markerInterface);
    }
 
    Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
    if (!BeanNameGenerator.class.equals(generatorClass)) {
      scanner.setBeanNameGenerator(BeanUtils.instantiateClass(generatorClass));
    }
 
    Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
    if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
      scanner.setMapperFactoryBean(BeanUtils.instantiateClass(mapperFactoryBeanClass));
    }
 
    scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef"));
    scanner.setSqlSessionFactoryBeanName(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()));
 
    scanner.registerFilters();
    scanner.doScan(StringUtils.toStringArray(basePackages));
  }
}

可以看到MapperScannerRegistrar是繼承于ImportBeanDefinitionRegistrar接口,在spring中ImportBeanDefinitionRegistrar的也是創(chuàng)建bean的一種方式,它首先會(huì)定義好bean的一些基礎(chǔ)信息,如beanName, class等等,然后在spring啟動(dòng)的時(shí)候調(diào)用其registerBeanDefinitions方法,來生成和注冊(cè)bean。

我們直接看scanner.doScan(StringUtils.toStringArray(basePackages));這行的工作,最終會(huì)調(diào)用下面的方法 ClassPathMapperScanner

private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
    GenericBeanDefinition definition;
    for (BeanDefinitionHolder holder : beanDefinitions) {
      definition = (GenericBeanDefinition) holder.getBeanDefinition();
      //這里的beanClassName是mapper接口的接口名(第一個(gè)字母小寫)
      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
      definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); // issue #59
      //這行很重要,表示bean的實(shí)際class為MapperFactoryBean
      definition.setBeanClass(this.mapperFactoryBean.getClass());
 
      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() + "'.");
        //將該bean設(shè)置成按類型自動(dòng)裝配,目的在該bean中如果有依賴其他bean,會(huì)按類型自動(dòng)注入到該bean中
        definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
      }
    }
  }

我們?cè)倏碝apperFactoryBean類

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

 private Class<T> mapperInterface;

 private boolean addToConfig = true;

 public MapperFactoryBean() {
   //intentionally empty
 }
  
 public MapperFactoryBean(Class<T> mapperInterface) {
   this.mapperInterface = mapperInterface;
 }

 /**
  * {@inheritDoc}
  */
 @Override
 protected void checkDaoConfig() {
   super.checkDaoConfig();

   notNull(this.mapperInterface, "Property 'mapperInterface' is required");
   //父類中的屬性SqlSessionTemplate,該字段是在上面講的自動(dòng)裝配中注入的
   Configuration configuration = getSqlSession().getConfiguration();
   if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
     try {
       //將該mapper接口添加到MapperRegistry中去
       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);
 }
·····
·····
}

MapperFactoryBean的父類是SqlSessionDaoSupport,同時(shí)實(shí)現(xiàn)了接口FactoryBean

我們先分析SqlSessionDaoSupport。

使得MapperFactoryBean擁有了SqlSessionTemplate屬性,而同時(shí)SqlSessionDaoSupport繼承于DaoSupport,DaoSupport是InitializingBean的一個(gè)抽象類并實(shí)現(xiàn)了afterPropertiesSet方法,該方法使得在bean生成時(shí)執(zhí)行一些操作checkDaoConfig。在checkDaoConfig方法中會(huì)將該mapper接口添加到MapperRegistry中去,MapperRegistry可以看作是一個(gè)mapper的注冊(cè)中心

MapperRegistry

public class MapperRegistry {
 
  private final Configuration config;
  //保存mapper接口與代理工廠類的映射
  private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<>();
 
  public MapperRegistry(Configuration config) {
    this.config = config;
  }
 
  @SuppressWarnings("unchecked")
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }
 
  public <T> boolean hasMapper(Class<T> type) {
    return knownMappers.containsKey(type);
  }
 
  public <T> void addMapper(Class<T> type) {
    if (type.isInterface()) {
      if (hasMapper(type)) {
        throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
      }
      boolean loadCompleted = false;
      try {
        //將mapper接口與代理工廠類對(duì)應(yīng)起來
        knownMappers.put(type, new MapperProxyFactory<>(type));
        // It's important that the type is added before the parser is run
        // otherwise the binding may automatically be attempted by the
        // mapper parser. If the type is already known, it won't try.
        MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
        parser.parse();
        loadCompleted = true;
      } finally {
        if (!loadCompleted) {
          knownMappers.remove(type);
        }
      }
    }
  }
 
  /**
   * @since 3.2.2
   */
  public Collection<Class<?>> getMappers() {
    return Collections.unmodifiableCollection(knownMappers.keySet());
  }
 
  /**
   * @since 3.2.2
   */
  public void addMappers(String packageName, Class<?> superType) {
    ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<>();
    resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
    Set<Class<? extends Class<?>>> mapperSet = resolverUtil.getClasses();
    for (Class<?> mapperClass : mapperSet) {
      addMapper(mapperClass);
    }
  }
 
  /**
   * @since 3.2.2
   */
  public void addMappers(String packageName) {
    addMappers(packageName, Object.class);
  }
 
}

MapperProxyFactory是MapperProxy的工廠類,MapperProxy是Mapper的代理類

MapperProxy

public class MapperProxy<T> implements InvocationHandler, Serializable {
 
  private static final long serialVersionUID = -6424540398559729838L;
  private final SqlSession sqlSession;
  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethod> methodCache;
 
  public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
    this.sqlSession = sqlSession;
    this.mapperInterface = mapperInterface;
    this.methodCache = methodCache;
  }
 
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      } else if (isDefaultMethod(method)) {
        return invokeDefaultMethod(proxy, method, args);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
    //使用緩存來保存MapperMethod
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    //最終會(huì)調(diào)用這里來執(zhí)行mapper中的方法
    return mapperMethod.execute(sqlSession, args);
  }
 
  private MapperMethod cachedMapperMethod(Method method) {
    return methodCache.computeIfAbsent(method, k -> new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
  }
 
  private Object invokeDefaultMethod(Object proxy, Method method, Object[] args)
      throws Throwable {
    final Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class
        .getDeclaredConstructor(Class.class, int.class);
    if (!constructor.isAccessible()) {
      constructor.setAccessible(true);
    }
    final Class<?> declaringClass = method.getDeclaringClass();
    return constructor
        .newInstance(declaringClass,
            MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED
                | MethodHandles.Lookup.PACKAGE | MethodHandles.Lookup.PUBLIC)
        .unreflectSpecial(method, declaringClass).bindTo(proxy).invokeWithArguments(args);
  }
 
 
}

我們?cè)诮又治鯩apperFactoryBean的另一個(gè)功能接口FactoryBean,實(shí)現(xiàn)FactoryBean這個(gè)接口使得MapperFactoryBean成為了一個(gè)工廠bean,它的功能是:從spring容器中獲取該工廠bean的具體實(shí)例是通過getObject方法

MapperFactoryBean

public T getObject() throws Exception {
    return getSqlSession().getMapper(this.mapperInterface);
  }
 
 
····
 
public <T> T getMapper(Class<T> type) {
    return getConfiguration().getMapper(type, this);
  }
 
···
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
  }
 
···
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }
 
···
 
public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }

可以看到最終從spring中獲取mapper的實(shí)例的時(shí)候,是獲取mapper的代理類

三、類UML圖

Mybatis-spring自動(dòng)注入機(jī)制原理

四、結(jié)論

  • 使用mybaits,其中mapper接口最終的實(shí)例是MapperProxy生成的代理類

  • 通過ImportBeanDefinitionRegistrar這種方式來注入到spring容器中

到此,關(guān)于“Mybatis-spring自動(dòng)注入機(jī)制原理”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!

分享題目:Mybatis-spring自動(dòng)注入機(jī)制原理
鏈接分享:http://chinadenli.net/article40/jsijeo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供虛擬主機(jī)、動(dòng)態(tài)網(wǎng)站、自適應(yīng)網(wǎng)站網(wǎng)站維護(hù)、網(wǎng)站內(nèi)鏈、網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站建設(shè)
国产精品夜色一区二区三区不卡| 日本办公室三级在线观看| 五月综合婷婷在线伊人| 国产精品一区二区丝袜| 国自产拍偷拍福利精品图片| 久久人人爽人人爽大片av| 久久这里只精品免费福利| 91亚洲精品国产一区| 青青操精品视频在线观看| 免费亚洲黄色在线观看| 美女被后入视频在线观看| 中文字幕五月婷婷免费| 国产精品久久精品国产| 免费午夜福利不卡片在线 视频 | 午夜福利直播在线视频| 色婷婷成人精品综合一区| 欧美日韩在线视频一区| 美国女大兵激情豪放视频播放 | 日韩18一区二区三区| 久久99午夜福利视频| 日韩免费国产91在线| 国产一区在线免费国产一区| 成人日韩视频中文字幕| 国产一级内片内射免费看 | 国产精品伦一区二区三区在线| 激情少妇一区二区三区| 激情视频在线视频在线视频| 午夜精品福利视频观看| 黄色国产精品一区二区三区| 国产又黄又猛又粗又爽的片 | 尹人大香蕉中文在线播放| 91欧美日韩中在线视频| 亚洲中文在线中文字幕91| 男女午夜在线免费观看视频| 亚洲一区二区久久观看| 亚洲精品中文字幕在线视频| 中文字幕在线区中文色| 经典欧美熟女激情综合网| 四季av一区二区播放| 草草草草在线观看视频| 欧美日韩一级aa大片|