转自:https://www.cnblogs.com/sonofelice/p/4980161.html

最近在学习spring和ibatis框架。

以前在天猫实习时做过的一个小项目用到的mybatis,在其使用过程中,不加思索的用了比较原始的一种持久化方式:

在一个包中写一个DAO的接口,在另一个包里面写DAO的实现,使用sqlMapClient来从***-sql.xml中读取相应的sql。

  1. public interface IBaseDaoiBatis {
  2. Object get(String statementName);
  3. }
  4. public class BaseDaoiBatis implements IBaseDaoiBatis {
  5. public Object get(String statementName) {
  6. return getSqlMapClientTemplate().queryForObject(statementName);
  7. }
  8. }
  9. //对应的mybatis配置文件里面的sql:
  10. <sqlMap>
  11. <typeAlias alias="sonarBean" type="com.**--**.SonarScanDataDisplayBean" />
  12. <select id="getSonarScanData" parameterClass="java.lang.Integer" resultClass="java.lang.String">
  13. <![CDATA[
  14. SELECT name FROM mm_test where id=#id#;
  15. ]]>
  16. </select>
  17. </sqlMap>

最近搭建了一个spring+ibatis的项目,发现了一种新的持久化方式:

只写一个dao的接口,在接口的方法中直接注解上用到的sql语句,觉得蛮巧妙的。借来用一下。注意,接口上方多了一个@Mapper注解。而每个方法上都是@Select() 注解,值为对应的sql。

  1. @Mapper
  2. public interface TestDao {
  3. @Select("select id, name, name_pinyin from mm_test; ")
  4. List<MmTest> selectAll();
  5.  
  6. @Insert("insert into mm_test(id, name) values(#{id}, #{name})")
  7. public void insertUser(MmTest mmtTestS);
  8. }

那么这个@Mapper注解究竟是个什么东西,是怎么起到注解的作用的?ibatis是怎么来识别这种注解的呢?对我这个java小白来说,注解,是spring特有的东西嘛?自学java的时候好像很少接触注解啊。不过竟然有java.lang.annotation 这个包,这到底是怎么回事?

那我们先来看一下Mapper这个自定义注解的定义:

  1. import org.springframework.stereotype.Component;
  2.  
  3. import java.lang.annotation.*;
  4. @Target({ ElementType.TYPE })
  5. @Retention(RetentionPolicy.RUNTIME)
  6. @Documented
  7. @Component
  8. public @interface Mapper {
  9. String value() default "";
  10. }

关于自定义注解:(查的别人的博客:http://www.cnblogs.com/mandroid/archive/2011/07/18/2109829.html)博客里面写的非常详细,并且注解的使用机制很容易理解。

拿上述的@Mapper来说,Retention选择的是RUNTIME策略,就是运行时注入。那么要在运行时获得注入的值,必然要用到java的反射机制。通过反射,拿到一个类运行时的方法变量等,来进行一系列的操作。

那我要考虑的下一个问题是,我定义的@Mapper,在我的工程里面是怎么识别的呢?

来看一下我spring的配置文件中关于mybatis的配置

  1. <!--mybatis-->
  2. <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  3. <property name="dataSource" ref="dataSource" />
  4. <property name="configLocation">
  5. <value>classpath:myBatis/mapper.xml</value>
  6. </property>
  7. </bean>
  8. <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  9. <property name="basePackage" value="com.**.**.**.dao" />
  10. <property name="annotationClass" value="com.nuomi.crm.annotation.Mapper"/>
  11. <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
  12. </bean>

在org.mybatis.spring.mapper.MapperScannerConfigurer这个类里面,应该是会去扫描我自定义的com.nuomi.crm.annotation.Mapper这个类的。

  1. <configuration>
  2. <settings>
  3. <!-- 将下划线字段名称映射为驼峰变量 -->
  4. <setting name="mapUnderscoreToCamelCase" value="true" />
  5. <!-- 进制mybatis进行延迟加载 -->
  6. <setting name="lazyLoadingEnabled" value="false"/>
  7. </settings>
  8. <mappers>
  9. </mappers>
  10. </configuration>

在我的mapper.xml里面只需要进行这一简单的配置就可以了(配置的含义后续补充)

接下来看一下mybatis自带的这个MapperScannerConfigurer究竟怎么实现的,来使用我这个自定义的注解@Mapper呢。

  1. public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {
  2. private Class<? extends Annotation> annotationClass;
  3. public void setAnnotationClass(Class<? extends Annotation> annotationClass) {
  4. this.annotationClass = annotationClass;
  5. }/**
  6. * {@inheritDoc}
  7. *
  8. * @since 1.0.2
  9. */
  10. public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
  11. if (this.processPropertyPlaceHolders) {
  12. processPropertyPlaceHolders();
  13. }
  14.  
  15. ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
  16. scanner.setAddToConfig(this.addToConfig);
  17. scanner.setAnnotationClass(this.annotationClass);
  18. scanner.setMarkerInterface(this.markerInterface);
  19. scanner.setSqlSessionFactory(this.sqlSessionFactory);
  20. scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
  21. scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
  22. scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
  23. scanner.setResourceLoader(this.applicationContext);
  24. scanner.setBeanNameGenerator(this.nameGenerator);
  25. scanner.registerFilters();
  26. scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
  27. }
  28.  
  29. /*
  30. * BeanDefinitionRegistries are called early in application startup, before
  31. * BeanFactoryPostProcessors. This means that PropertyResourceConfigurers will not have been
  32. * loaded and any property substitution of this class' properties will fail. To avoid this, find
  33. * any PropertyResourceConfigurers defined in the context and run them on this class' bean
  34. * definition. Then update the values.
  35. */
  36. private void processPropertyPlaceHolders() {
  37. Map<String, PropertyResourceConfigurer> prcs = applicationContext.getBeansOfType(PropertyResourceConfigurer.class);
  38.  
  39. if (!prcs.isEmpty() && applicationContext instanceof GenericApplicationContext) {
  40. BeanDefinition mapperScannerBean = ((GenericApplicationContext) applicationContext)
  41. .getBeanFactory().getBeanDefinition(beanName);
  42.  
  43. // PropertyResourceConfigurer does not expose any methods to explicitly perform
  44. // property placeholder substitution. Instead, create a BeanFactory that just
  45. // contains this mapper scanner and post process the factory.
  46. DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
  47. factory.registerBeanDefinition(beanName, mapperScannerBean);
  48.  
  49. for (PropertyResourceConfigurer prc : prcs.values()) {
  50. prc.postProcessBeanFactory(factory);
  51. }
  52.  
  53. PropertyValues values = mapperScannerBean.getPropertyValues();
  54.  
  55. this.basePackage = updatePropertyValue("basePackage", values);
  56. this.sqlSessionFactoryBeanName = updatePropertyValue("sqlSessionFactoryBeanName", values);
  57. this.sqlSessionTemplateBeanName = updatePropertyValue("sqlSessionTemplateBeanName", values);
  58. }
  59. }
  60.  
  61. }

上面只是截取的关于annotation的代码片段.

  1. scanner.setAnnotationClass(this.annotationClass);
    这里会去扫描配置的那个注解类。

mybatis的内部实现会使用java反射机制来在运行时去解析相应的sql。

mybatis对java自定义注解的使用的更多相关文章

  1. mybatis对java自定义注解的使用——入门篇

    最近在学习spring和ibatis框架. 以前在天猫实习时做过的一个小项目用到的mybatis,在其使用过程中,不加思索的用了比较原始的一种持久化方式: 在一个包中写一个DAO的接口,在另一个包里面 ...

  2. java自定义注解类

    一.前言 今天阅读帆哥代码的时候,看到了之前没有见过的新东西, 比如java自定义注解类,如何获取注解,如何反射内部类,this$0是什么意思? 于是乎,学习并整理了一下. 二.代码示例 import ...

  3. java自定义注解实现前后台参数校验

    2016.07.26 qq:992591601,欢迎交流 首先介绍些基本概念: Annotations(also known as metadata)provide a formalized way ...

  4. java自定义注解注解方法、类、属性等等【转】

    http://anole1982.iteye.com/blog/1450421 http://www.open-open.com/doc/view/51fe76de67214563b20b385320 ...

  5. java自定义注解知识实例及SSH框架下,拦截器中无法获得java注解属性值的问题

    一.java自定义注解相关知识 注解这东西是java语言本身就带有的功能特点,于struts,hibernate,spring这三个框架无关.使用得当特别方便.基于注解的xml文件配置方式也受到人们的 ...

  6. Java自定义注解的实现

    Java自定义注解的实现,总共三步(eg.@RandomlyThrowsException): 1.首先编写一个自定义注解@RandomlyThrowsException package com.gi ...

  7. Java自定义注解源码+原理解释(使用Java自定义注解校验bean传入参数合法性)

    Java自定义注解源码+原理解释(使用Java自定义注解校验bean传入参数合法性) 前言:由于前段时间忙于写接口,在接口中需要做很多的参数校验,本着简洁.高效的原则,便写了这个小工具供自己使用(内容 ...

  8. JAVA自定义注解 ------ Annotation

    日常开发工作中,合理的使用注解,可以简化代码编写以及使代码结构更加简单,下面记录下,JAVA自定义注解的开发过程. 定义注解声明类. 编写注解处理器(主要起作用部分). 使用注解. 相关知识点介绍, ...

  9. Java自定义注解和运行时靠反射获取注解

    转载:http://blog.csdn.net/bao19901210/article/details/17201173/ java自定义注解 Java注解是附加在代码中的一些元信息,用于一些工具在编 ...

随机推荐

  1. mysql TOP语句 语法

    mysql TOP语句 语法 作用:用于规定要返回的记录的数目. 语法:SELECT column_name(s) FROM table_name LIMIT number 说明:对于拥有数千条记录的 ...

  2. JDK1.8 LinkedList双向链表源码

    序言 LinkedList是一个双向链表 也就是说list中的每个元素,在存储自身值之外,还 额外存储了其前一个和后一个元素的地址,所以也就可以很方便地根据当前元素获取到其前后的元素 链表的尾部元素的 ...

  3. Mysql索引深入理解

    一.  引言 Mysql 我们平常用的很多,了解的很多,今天别的不说,直接说mysql的底层是什么,说到底层,就想到数据结构,那么,mysql的数据结构是什么呢? 是B + tree .那么数据库中的 ...

  4. H. The Game of Life

    题目链接:http://exam.upc.edu.cn/problem.php?id=5206 题意:邻居为八个方向.若一个活人有2或3个邻居,遗传一代,否则死亡:若一个死人有3个邻居,则下一代复活. ...

  5. git pull失误提交

    git pull 提示错误,Your local changes to the following files would be overwritten by merge 到公司后本来打算git pu ...

  6. spring- junit测试事务回滚

    http://blog.csdn.net/molingduzun123/article/details/49383235

  7. SpringBoot与数据源

    1.JDBC <dependency> <groupId>org.springframework.boot</groupId> <artifactId> ...

  8. linux的find和grep区别?

    为什么会把 grep和find 这两个命令拿在一起来讨论? 是因为他们之间有一个容易混淆的地方, [在我的记忆中] : -name ? 它是find的选项! 不是grep的选项! 实际上, find基 ...

  9. How to derive mean and variance of a Gaussian?

    PRML exercise 1.8: To derive mean: change of variable z = x - u, use symmetry To derive variance: di ...

  10. 监听整个页面上的DOM树变化

    在线预览 方法 使用<Web API 接口>的<MutationObserver> MutationObserver 网上查到的很多都是使用Mutation events的,但 ...