本篇主要是简单讲解,通用Mapper的实现原理,不是整合教程。每次学习一个新的框架/插件的时候,我们一开始都是按照官方示例写代码,达到了会用的目的。等用一段时候之后,就应该学习源码,学习它是如何设计的,为啥,简简单单的一个配置就可以完成很多事情。
示例代码来自插件自带的springBoot整合示例代码:
//简单的依赖,一个starter,一个h2内存数据库
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
package tk.mybatis.sample.domain;
import org.apache.ibatis.type.JdbcType;
import tk.mybatis.mapper.annotation.ColumnType;
import javax.persistence.Id;
import java.io.Serializable;
/**
* Description: Country
* Author: liuzh
* Update: liuzh(2014-06-06 13:38)
*/
public class Country implements Serializable {
private static final long serialVersionUID = 6569081236403751407L;
@Id
@ColumnType(jdbcType = JdbcType.BIGINT)
private Long id;
private String countryname;
private String countrycode;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getCountryname() {
return countryname;
}
public void setCountryname(String countryname) {
this.countryname = countryname;
}
public String getCountrycode() {
return countrycode;
}
public void setCountrycode(String countrycode) {
this.countrycode = countrycode;
}
}
package tk.mybatis.sample.mapper;
import org.apache.ibatis.annotations.Mapper;
import tk.mybatis.sample.domain.Country;
@Mapper
public interface CountryMapper extends tk.mybatis.mapper.common.Mapper<Country> {
}
package tk.mybatis.sample;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import tk.mybatis.sample.domain.Country;
import tk.mybatis.sample.mapper.CountryMapper;
import tk.mybatis.spring.annotation.MapperScan;
import java.util.List;
@MapperScan(basePackages = "tk.mybatis.sample.mapper")
@SpringBootApplication
public class SampleMapperApplication implements CommandLineRunner {
@Autowired
private CountryMapper countryMapper;
public static void main(String[] args) {
SpringApplication.run(SampleMapperApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
List<Country> countries = countryMapper.selectAll();
for (Country country : countries) {
System.out.println("Country Name: " + country.getCountryname());
}
}
}
首先,和普通boot项目没有啥区别,就是多了一个注解@MapperScan。我们先看下这个注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(tk.mybatis.spring.annotation.MapperScannerRegistrar.class)
public @interface MapperScan {
。。。
}
使用了@Import注解,作用就是初始化类放入spring的ioc容器中,那我们就去看看引入的这个类
package tk.mybatis.spring.annotation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import tk.mybatis.spring.mapper.ClassPathMapperScanner;
import tk.mybatis.spring.mapper.MapperFactoryBean;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
public static final Logger LOGGER = LoggerFactory.getLogger(MapperScannerRegistrar.class);
private ResourceLoader resourceLoader;
private Environment environment;
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
// this check is needed in Spring 3.1
if (resourc