mybatis對java自定義註解的使用——入門篇

最近在學習spring和ibatis框架。html

之前在天貓實習時作過的一個小項目用到的mybatis,在其使用過程當中,不加思索的用了比較原始的一種持久化方式:java

在一個包中寫一個DAO的接口,在另外一個包裏面寫DAO的實現,使用sqlMapClient來從***-sql.xml中讀取相應的sql。android

public interface IBaseDaoiBatis {
     Object get(String statementName);
}
public class BaseDaoiBatis implements IBaseDaoiBatis {
 public Object get(String statementName) {
        return getSqlMapClientTemplate().queryForObject(statementName);
    }
}
//對應的mybatis配置文件裏面的sql:
<sqlMap>
    <typeAlias alias="sonarBean" type="com.**--**.SonarScanDataDisplayBean" />
    <select id="getSonarScanData" parameterClass="java.lang.Integer" resultClass="java.lang.String">
        <![CDATA[
            SELECT  name FROM mm_test  where id=#id#;  
        ]]>
    </select>
</sqlMap>

 

最近搭建了一個spring+ibatis的項目,發現了一種新的持久化方式:spring

只寫一個dao的接口,在接口的方法中直接註解上用到的sql語句,以爲蠻巧妙的。借來用一下。注意,接口上方多了一個@Mapper註解。而每一個方法上都是@Select() 註解,值爲對應的sql。sql

@Mapper
public interface TestDao {
    @Select("select id, name, name_pinyin from mm_test; ")
    List<MmTest> selectAll();
    
    @Insert("insert into mm_test(id, name) values(#{id}, #{name})")  
    public void insertUser(MmTest mmtTestS);    
}

 

那麼這個@Mapper註解到底是個什麼東西,是怎麼起到註解的做用的?ibatis是怎麼來識別這種註解的呢?對我這個java小白來講,註解,是spring特有的東西嘛?自學java的時候好像不多接觸註解啊。不過居然有java.lang.annotation 這個包,這究竟是怎麼回事?mybatis

那咱們先來看一下Mapper這個自定義註解的定義:app

import org.springframework.stereotype.Component;

import java.lang.annotation.*;
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Mapper {
    String value() default "";
}

 

關於自定義註解:(查的別人的博客:http://www.cnblogs.com/mandroid/archive/2011/07/18/2109829.html)博客裏面寫的很是詳細,而且註解的使用機制很容易理解。框架

拿上述的@Mapper來講,Retention選擇的是RUNTIME策略,就是運行時注入。那麼要在運行時得到注入的值,必然要用到java的反射機制。經過反射,拿到一個類運行時的方法變量等,來進行一系列的操做。post

那我要考慮的下一個問題是,我定義的@Mapper,在個人工程裏面是怎麼識別的呢?學習

來看一下我spring的配置文件中關於mybatis的配置

    <!--mybatis-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation">
            <value>classpath:myBatis/mapper.xml</value>
        </property>
    </bean>
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.**.**.**.dao" />
        <property name="annotationClass" value="com.nuomi.crm.annotation.Mapper"/>
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
    </bean>

 

org.mybatis.spring.mapper.MapperScannerConfigurer這個類裏面,應該是會去掃描我自定義的com.nuomi.crm.annotation.Mapper這個類的。

<configuration>
    <settings>
        <!-- 將下劃線字段名稱映射爲駝峯變量  -->
        <setting name="mapUnderscoreToCamelCase" value="true" />
        <!-- 進制mybatis進行延遲加載 -->
        <setting name="lazyLoadingEnabled" value="false"/>
    </settings>
    <mappers>
    </mappers>
</configuration>

 

在個人mapper.xml裏面只須要進行這一簡單的配置就能夠了(配置的含義後續補充)

接下來看一下mybatis自帶的這個MapperScannerConfigurer究竟怎麼實現的,來使用我這個自定義的註解@Mapper呢。

public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {
private Class<? extends Annotation> annotationClass;
  public void setAnnotationClass(Class<? extends Annotation> annotationClass) {
    this.annotationClass = annotationClass;
  }/**
   * {@inheritDoc}
   * 
   * @since 1.0.2
   */
  public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
    if (this.processPropertyPlaceHolders) {
      processPropertyPlaceHolders();
    }

    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.registerFilters();
    scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
  }

  /*
   * BeanDefinitionRegistries are called early in application startup, before
   * BeanFactoryPostProcessors. This means that PropertyResourceConfigurers will not have been
   * loaded and any property substitution of this class' properties will fail. To avoid this, find
   * any PropertyResourceConfigurers defined in the context and run them on this class' bean
   * definition. Then update the values.
   */
  private void processPropertyPlaceHolders() {
    Map<String, PropertyResourceConfigurer> prcs = applicationContext.getBeansOfType(PropertyResourceConfigurer.class);

    if (!prcs.isEmpty() && applicationContext instanceof GenericApplicationContext) {
      BeanDefinition mapperScannerBean = ((GenericApplicationContext) applicationContext)
          .getBeanFactory().getBeanDefinition(beanName);

      // PropertyResourceConfigurer does not expose any methods to explicitly perform
      // property placeholder substitution. Instead, create a BeanFactory that just
      // contains this mapper scanner and post process the factory.
      DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
      factory.registerBeanDefinition(beanName, mapperScannerBean);

      for (PropertyResourceConfigurer prc : prcs.values()) {
        prc.postProcessBeanFactory(factory);
      }

      PropertyValues values = mapperScannerBean.getPropertyValues();

      this.basePackage = updatePropertyValue("basePackage", values);
      this.sqlSessionFactoryBeanName = updatePropertyValue("sqlSessionFactoryBeanName", values);
      this.sqlSessionTemplateBeanName = updatePropertyValue("sqlSessionTemplateBeanName", values);
    }
  }

}

 上面只是截取的關於annotation的代碼片斷.

scanner.setAnnotationClass(this.annotationClass);
這裏會去掃描配置的那個註解類。

mybatis的內部實現會使用java反射機制來在運行時去解析相應的sql。

 

(上面寫的還不是很徹底,後續補充。)

相關文章
相關標籤/搜索