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。

 

(上面寫的還不是很完全,后續補充。)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM