MapperScan注解分析

MapperScan注解分析Spring3 x 版本支持使用 Configuratio 和 Bean 注解来提供基于 Java 的配置 如果使用基于 java 的配置 可以使用 MapperScan 注解来扫描映射 Mapper 接口类 MapperScan value org springframew orm mapper sqlSessionFa sqlSessionFa

Spring 3.x+版本支持使用@Configuration和@Bean注解来提供基于 Java 的配置。

如果使用基于java的配置,可以使用@MapperScan注解来扫描映射Mapper接口类。

 

@MapperScan(value = "org.springframework.orm.mapper", sqlSessionFactoryRef = "sqlSessionFactoryBean") // 通过Bean注解注入自定义构建的SqlSessionFactoryBean对象 @Bean public SqlSessionFactoryBean sqlSessionFactoryBean() throws Exception { SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); sqlSessionFactoryBean.setDataSource(dataSource()); sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver() .getResources("T1Mapper.xml")); sqlSessionFactoryBean.setTypeAliasesPackage("org.springframework.orm.entity"); return sqlSessionFactoryBean; }

value:指定mapper接口类包路径

sqlSessionFactoryRef:指定SqlSessionFactoryBean对象名

 

MapperScan进一步解析

@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented // 通过spring import注解方式加载 @Import(MapperScannerRegistrar.class) public @interface MapperScan { 
  

@Import 是被用来整合所有在@Configuration注解中定义的bean配置

这里MapperScannerRegistrar实现了ImportBeanDefinitionRegistrar接口注入bean,再通过import注解导入加载。

 @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { // 获取注解 AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName())); // 扩展spring中ClassPathBeanDefinitionScanner类将类扫面成BeanDefinition ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
 // 扫描包路径集 List 
  
    basePackages = new ArrayList 
   
     (); for (String pkg : annoAttrs.getStringArray("value")) { if (StringUtils.hasText(pkg)) { basePackages.add(pkg); } } for (String pkg : annoAttrs.getStringArray("basePackages")) { if (StringUtils.hasText(pkg)) { basePackages.add(pkg); } } for (Class 
     clazz : annoAttrs.getClassArray("basePackageClasses")) { basePackages.add(ClassUtils.getPackageName(clazz)); } // 注册相关filter scanner.registerFilters(); // 扫描 scanner.doScan(StringUtils.toStringArray(basePackages)); 
    
  

scanner.doScan中将实现mapper扫描映射

 // 通过spring提供的方法将mapper接口类扫描转换成BeanDefinitionHolder集合 Set 
  
    beanDefinitions = super.doScan(basePackages); if (beanDefinitions.isEmpty()) { logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration."); } else { // 再根据BeanDefinitionHolder做相关处理 processBeanDefinitions(beanDefinitions); } return beanDefinitions; 
  

processBeanDefinitions方法中会设置mapper注入对应实现的bean等配置

private MapperFactoryBean 
   mapperFactoryBean = new MapperFactoryBean  (); // 配置构造函数中参数值 definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); // issue #59 // 设置BeanClass为MapperFactoryBean类 definition.setBeanClass(this.mapperFactoryBean.getClass()); // 设置属性值 definition.getPropertyValues().add("addToConfig", this.addToConfig); 

definition.setBeanClass(this.mapperFactoryBean.getClass())此处设置mapper接口对应的实现类为MapperFactoryBean类。

MapperFactoryBean类实现了FactoryBean功能,最后实际执行的bean对象是通过getObject方法获取。

 public T getObject() throws Exception { // 此处使用了动态代理 return getSqlSession().getMapper(this.mapperInterface); }
 protected T newInstance(MapperProxy 
  
    mapperProxy) { // 通过MapperProxy生成mapper接口执行的代理对象 return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy); } public T newInstance(SqlSession sqlSession) { // MapperProxy就是实际的目标对象,也就是代理对象 final MapperProxy 
   
     mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache); return newInstance(mapperProxy); } 
    
  

到此处为止,可以看到mybatis加载的mapper接口对应的实现目标类都是MapperProxy对象。

 

SqlSessionTemplate类中执行具体操作是再次使用了一次代理

this.sqlSessionFactory = sqlSessionFactory; this.executorType = executorType; this.exceptionTranslator = exceptionTranslator; this.sqlSessionProxy = (SqlSession) newProxyInstance( SqlSessionFactory.class.getClassLoader(), new Class[] { SqlSession.class }, new SqlSessionInterceptor());
sqlSessionProxy代理对象是在SqlSessionTemplate对象构造方法时指定的 
 ...... public void select(String statement, ResultHandler handler) { this.sqlSessionProxy.select(statement, handler); } public void select(String statement, Object parameter, ResultHandler handler) { this.sqlSessionProxy.select(statement, parameter, handler); } ......

SqlSessionInterceptor代理类

private class SqlSessionInterceptor implements InvocationHandler { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 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) { closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory); } } } }

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/219792.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月17日 下午9:53
下一篇 2026年3月17日 下午9:53


相关推荐

  • 蓝桥杯历年真题题目及题解目录汇总

    蓝桥杯历年真题题目及题解目录汇总先挖个大坑 省赛 B 组 2013 年第四届蓝桥杯省赛试题及详解 Java 本科 B 组 2014 年第五届蓝桥杯省赛试题及详解 Java 本科 B 组 2015 年第六届蓝桥杯省赛试题及详解 Java 本科 B 组 2016 年第七届蓝桥杯省赛试题及详解 Java 本科 B 组 2017 年第八届蓝桥杯省赛试题及详解 Java 本科 B 组 2018 年第九届蓝桥杯省赛试题及详解 Java 本科 B

    2026年3月19日
    3
  • mysql BLOB数据类型分类

    mysql BLOB数据类型分类mysqlBLOB 是是一个二进制大对象 可以容纳可变数量的数据 下面分别说说 mysqlBLOB 数据类型分类 可以分为 nbsp 有 4 种 BLOB 类型 TINYBLOB BLOB MEDIUMBLOB 和 LONGBLOB 来自 www oceanoemchin com 分别讲述其取值范围 可以更好理解二进制存储 1 TINYBLOB 数据类型 nbsp nbsp nbsp 0 255 字节 nbsp nbsp nbsp 不超过 255

    2026年3月19日
    2
  • 概率论:随机事件和概率事件_随机事件概率的求法

    概率论:随机事件和概率事件_随机事件概率的求法相关定义;随机试验:满足以下三个条件的:1.实验相同条件下可重复2.实验的所有结果都是明确可知的,且不止一个3.实验结果出来之前,最总会是个什么结果,我们是无法预料的。样本空间:随机实验的所有可能的结果的集合就是这个实验的样本空间。基本事件(样本点):就是样本空间的每一个具体的可能的结果随机事件:样本空间的子集必然事件:每次实验必定发生的事件…

    2022年10月18日
    3
  • DropDownList1 添加一个默认选中项

    DropDownList1 添加一个默认选中项DropDownList1添加一个默认选中项DropDownList1.DataSource=bb.drop();DropDownList1.DataTextField=”BookType”;DropDownList1.DataValueField=”BookTypeid”;DropDownList1.DataBind();DropDownList1.Ite..

    2022年7月18日
    15
  • Claude Code 原生支持 Windows:一篇详尽的安装与配置指南

    Claude Code 原生支持 Windows:一篇详尽的安装与配置指南

    2026年3月16日
    2
  • 用C语言进行小数进制转换(进制转化讲解)

    用C语言进行小数进制转换(进制转化讲解)进制的转换看这篇文档 gt https wenku baidu com view ab23dec5d4bb html 我这里不说了编程序实现如下功能 输入一个正的十进制纯小数和一个表示进制的整数 n n lt 10 然后将这个十进制纯小数转换为 n 进制小数 最后输出结果 提示 可以先将求得的 n 进制小数的每一位数存入一个数组中 然后再按符合要求的顺序输出 若不能精确转换 则保留 16 位小数 include stdio h in stdio h

    2026年3月17日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号