zoukankan      html  css  js  c++  java
  • mybatis对java自定义注解的使用——入门篇

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

    1.

    最近在学习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的代码片段.

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

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

    (上面写的还不是很完全,后续补充。)

  • 相关阅读:
    一个Winform下DataGridView控件外观的自定义类
    从以往子类化跟踪MouseLeave深入讨论VB6的自定义Hook类
    使用VB6写一个自定义的进度信息框窗口
    C#研究OpenXML之路(4-使用第三方库)
    Access SQL实现连续及不连续Rank排名
    C#研究OpenXML之路(3-OpenXMLSDKToolV25.msi)
    C#研究OpenXML之路(2-DocumentFormat.OpenXml命名空间)
    C#研究OpenXML之路(1-新建工作簿文件)
    统一我的博客文章的CSS样式代码
    C#图片灰度处理(位深度24→位深度8)
  • 原文地址:https://www.cnblogs.com/sharpest/p/6097682.html
Copyright © 2011-2022 走看看