聊聊、手写Mybatis SpringBoot Starter
导航:
SpringBoot 现在应该很多公司都用到了,在它出现之前呢,我们用 Spring 要写很多的配置文件,各种各样的 XML 文件。而且我们在引入 Spring 的时候,会加入很多的 jar 包,很多时候会由于版本不匹配问题,而导致启动失败。在配置好文件和正确引入各种 jar 以后,我们需要将项目打包成 war,然后放到 web 服务器。
SpringBoot 是发展趋势,那么它有哪些特性呢?或者它能帮我们做什么呢?
SpringBoot特性
1.能够快速的创建项目,利用 Spring initializr 快速创建项目,平时我们用到的开发工具也集成了这些插件,所以非常方便
2.通过 jar 来启动项目,也就是内嵌的 web 服务器
3.通过 starter 来管理依赖,解决版本不匹配问题,零配置文件
4.可以检查程序健康状况,度量标准
创建 mybatis-spring-boot-starter
关于 starter 的命名,如果是我们自己创建 starter,一般是 项目名称-spring-boot-starter,这个和官网的 starter 不一样,官网的是将项目名称放最后,例如:spring-boot-starter-web
我创建的是 mybatis,所以是 mybatis-spring-boot-starter
自己写 SpringBoot Starter 必须要知道 EnableAutoConfiguration,SpringBoot 自动配置就是通过它来实现。SpringBoot 在启动的时候会去 META-INF 包下面读取 spring.factories 文件。
例如:mybatis-spring-boot-starter
spring.factories:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.rockcode.mybatis.configurations.MybatisAutoConfiguration
这里告诉 SpringBoot 我的自动配置类是 MybatisAutoConfiguration
MybatisAutoConfiguration
@Configuration
@EnableConfigurationProperties(MybatisProperties.class)
public class MybatisAutoConfiguration {
@Autowired
private MybatisProperties mybatisProperties;
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
return sqlSessionFactoryBean;
}
@Bean
public DataSource dataSource(){
DruidDataSource driverManagerDataSource = new DruidDataSource();
driverManagerDataSource.setDriverClassName(mybatisProperties.getDriver());
driverManagerDataSource.setUrl(mybatisProperties.getUrl());
driverManagerDataSource.setUsername(mybatisProperties.getUsername());
driverManagerDataSource.setPassword(mybatisProperties.getPassword());
return driverManagerDataSource;
}
}
MybatisProperties
@ConfigurationProperties(prefix = "mybatis.database")
public class MybatisProperties {
private String driver;
private String url;
private String username;
private String password;
// getter setter 方法忽略
}
上面有两个 SpringBoot 知识点,@ConfigurationProperties(prefix = "mybatis.database"),@EnableConfigurationProperties(MybatisProperties.class),这两个在 SpringBoot 用的非常多,它们的好处是,你可以直接
@Autowired
private MybatisProperties mybatisProperties;
这样你就可以获取到所有的属性值,也就是生成了 Bean 对象。例如我想获取 url,那么直接 mybatisProperties.getUrl() 就行。这两个类会在后面的 SpringBoot 源码系列 文章里面聊。
其他的类,跟《聊聊、手写Mybatis 注解配置方式》里面的内容一样。
AccountMapperFactoryBean
public class AccountMapperFactoryBean extends SqlSessionDaoSupport implements FactoryBean {
private Class mapperInterface;
public void setMapperInterface(Class mapperInterface) {
this.mapperInterface = mapperInterface;
}
@Autowired
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
super.setSqlSessionFactory(sqlSessionFactory);
}
@Override
protected void checkDaoConfig() {
super.checkDaoConfig();
notNull(this.mapperInterface, "Property 'mapperInterface' is required");
Configuration configuration = getSqlSession().getConfiguration();
configuration.addMapper(this.mapperInterface);
}
@Override
public Object getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
@Override
public Class<?> getObjectType() {
return this.mapperInterface;
}
}
AccountMapperScan
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(AccountImportBeanDefinitionRegistrar.class)
public @interface AccountMapperScan {
String[] value() default {};
String[] basePackages() default {};
}
AccountImportBeanDefinitionRegistrar
public class AccountImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
Map<String, Object> annotationAttributes = annotationMetadata.getAnnotationAttributes(AccountMapperScan.class.getName());
String[] value = (String[]) annotationAttributes.get("value");
String packages = value[0];
AccountClassPathMapperScanner myClassPathBeanDefinitionScanner = new AccountClassPathMapperScanner(beanDefinitionRegistry);
myClassPathBeanDefinitionScanner.registerFilters();
myClassPathBeanDefinitionScanner.scan(packages);
}
}
AccountClassPathMapperScanner
public class AccountClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
public AccountClassPathMapperScanner(BeanDefinitionRegistry registry) {
super(registry, false);
}
public void registerFilters() {
addIncludeFilter(new TypeFilter() {
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
return true;
}
});
}
@Override
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
Set<BeanDefinitionHolder> beanDefinitionHolders = super.doScan(basePackages);
GenericBeanDefinition definition;
for (BeanDefinitionHolder holder : beanDefinitionHolders) {
definition = (GenericBeanDefinition) holder.getBeanDefinition();
String beanClassName = definition.getBeanClassName();
try {
Class<?> clazz = Class.forName(beanClassName);
definition.setBeanClass(AccountMapperFactoryBean.class);
definition.getPropertyValues().add("mapperInterface", clazz);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
return beanDefinitionHolders;
}
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
}
}
application.properties
mybatis.database.driver = com.mysql.jdbc.Driver
mybatis.database.url = jdbc:mysql://127.0.0.1:3306/test?useSSL=false
mybatis.database.username = root
mybatis.database.password = root
pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
<relativePath/>
</parent>
<groupId>com.rockcode</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mybatis-spring-boot-starter</name>
<description>mybatis-spring-boot-starter</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.30</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.31</version>
</dependency>
</dependencies>
上面就是所有的代码和配置了,然后打包成 mybatis-spring-boot-starter-0.0.1-SNAPSHOT.jar。
在其他的项目中,我们只需要引用就可以。
<dependency>
<groupId>com.rockcode</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
好了,Mybatis 系列文章就到这里结束了。源码地址:https://github.com/xumiaoshun/mybatis-spring-boot-starter.git。