自定义MyBatisAutoConfiguration,MyBatis的配置从未如此简单过~(实现自己的 start)
项目 github地址:https://github.com/winterme/pkusoft-mybatis
jar 包地址:链接:https://pan.baidu.com/s/1MMsZgjbm9yKkn4GfcZ1WIQ 提取码:to0t
在工作中,发现我们经理写的一个包很好用,就是只需要在 yml 上配置 数据库连接信息,包路径,xml路径,mybatis 就能跑了,很方便,也是也想自己写一个,参考了下经理的代码,自己写了个
其具体思路就是,实现 BeanDefinitionRegistryPostProcessor 接口,在 ioc注入的时候,读取 配置文件,进行动态注入。
注入方法和原来的java配置mybatis 一样,先创建 DataSource,然后 sqlSessionFactory,然后transaction。
yml 格式:
mybatis:
datasource:
config[0]:
# druid 监控类
type: com.alibaba.druid.pool.DruidDataSource
# 数据库连接驱动
driver-class-name: com.mysql.jdbc.Driver
# 数据库连接地址
url: jdbc:mysql://127.0.0.1:3306/zhangzq?useUnicode=true&characterEncoding=utf-8&useSSL=false&useLegacyDatetimeCode=false&serverTimezone=Hongkong&zeroDateTimeBehavior=convertToNull
username: root
password: xxxx
# tkmybatis 的扫描器,不写默认 MyBatis 的扫描器
mapper-scanner: tk.mybatis.spring.mapper.MapperScannerConfigurer
# mapper.java 所在包
base-package: com.zzq.zhangzq.mapper
# mapper.xml 所在包
mapper-location: classpath:com/zzq/zhangzq/mapper/*.xml
默认 0 为主数据源,其他的为从数据源。从 config[0] 开始,config[1],config[2]....
代码参考:
import com.alibaba.druid.pool.DruidDataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.boot.autoconfigure.SpringBootVFS;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.EnumerablePropertySource;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import tk.mybatis.spring.mapper.MapperScannerConfigurer;
import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Configuration
public class MyBatisAutoConfiguration implements BeanDefinitionRegistryPostProcessor, EnvironmentAware {
private static String PREFIX = "mybatis.datasource.config";
private static final Logger logger = LoggerFactory.getLogger(MyBatisAutoConfiguration.class);
private Environment environment;
private Integer [] integers;
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
HashSet set = new HashSet();
Iterator<PropertySource<?>> iterator = ((ConfigurableEnvironment) this.environment).getPropertySources().iterator();
while (iterator.hasNext()){
PropertySource localPropertySource = (PropertySource)iterator.next();
if( localPropertySource instanceof EnumerablePropertySource){
for (String str1 : ((EnumerablePropertySource)localPropertySource).getPropertyNames()){
Matcher matcher = Pattern.compile("mybatis.datasource.config\\D+(\\d+)\\D+").matcher(str1);
if ( matcher.find() ){
set.add( matcher.group(1) );
}
}
}
}
this.integers = new Integer[set.size()];
int i = 0;
for (Object o: set) {
this.integers[i++] = Integer.valueOf( o.toString() );
}
bind(beanDefinitionRegistry);
for (String name: beanDefinitionRegistry.getBeanDefinitionNames()) {
logger.info("bean name :" + name );
}
}
public void bind(BeanDefinitionRegistry beanDefinitionRegistry){
for (Integer i: this.integers) {
bindDataSource(i , beanDefinitionRegistry);
bindSqlSessionFactory(i , beanDefinitionRegistry);
bindMapperScaner(i , beanDefinitionRegistry);
bindTransation(i , beanDefinitionRegistry);
}
}
public void bindTransation(int i , BeanDefinitionRegistry beanDefinitionRegistry){
String tranName = "transactionManager" + i;
RootBeanDefinition transaction = new RootBeanDefinition(DataSourceTransactionManager.class);
transaction.getPropertyValues()
.add("dataSource", new RuntimeBeanReference("datasource" + i ));
if( i == 0 ){
transaction.setPrimary(true);
}
beanDefinitionRegistry.registerBeanDefinition(tranName, transaction);
}
public void bindMapperScaner(int i , BeanDefinitionRegistry beanDefinitionRegistry){
String mapperScanner = this.environment.getProperty(MyBatisAutoConfiguration.PREFIX + "[" + i + "].mapper-scanner");
String basePackage = this.environment.getProperty(MyBatisAutoConfiguration.PREFIX + "[" + i + "].base-package");
String sqlSessionFactoryName = "sqlSessionFactory" + i;
Object clazz = "";
try {
clazz = Class.forName(mapperScanner);
} catch (NullPointerException e){
clazz = MapperScannerConfigurer.class;
} catch (ClassNotFoundException e) {
clazz = MapperScannerConfigurer.class;
}
RootBeanDefinition mapperScannerObject = new RootBeanDefinition((Class) clazz);
mapperScannerObject.getPropertyValues()
.add("basePackage", basePackage)
.add("sqlSessionFactoryBeanName", sqlSessionFactoryName);
if( i == 0 ){
mapperScannerObject.setPrimary(true);
}
beanDefinitionRegistry.registerBeanDefinition("mapperScannerConfigurer" + i, mapperScannerObject);
}
public void bindSqlSessionFactory(int i , BeanDefinitionRegistry beanDefinitionRegistry){
String mapperLocations = this.environment.getProperty(MyBatisAutoConfiguration.PREFIX + "[" + i + "].mapper-location");
String sqlSessionFactoryName = "sqlSessionFactory" + i;
RootBeanDefinition sqlSession = new RootBeanDefinition(SqlSessionFactoryBean.class);
try {
sqlSession.getPropertyValues()
.add("dataSource", new RuntimeBeanReference("datasource" + i ))
.add("vfs", SpringBootVFS.class)
.add("mapperLocations", new PathMatchingResourcePatternResolver().getResources(mapperLocations));
} catch (IOException e) {
logger.error(sqlSessionFactoryName + " bind fail!!!");
}
if( i == 0 ){
sqlSession.setPrimary(true);
}
beanDefinitionRegistry.registerBeanDefinition(sqlSessionFactoryName, sqlSession);
}
public void bindDataSource(Integer paramInt, BeanDefinitionRegistry beanDefinitionRegistry){
String driverClassName = this.environment.getProperty(MyBatisAutoConfiguration.PREFIX + "[" + paramInt + "].driver-class-name");
String url = this.environment.getProperty(MyBatisAutoConfiguration.PREFIX + "[" + paramInt + "].url");
String username = this.environment.getProperty(MyBatisAutoConfiguration.PREFIX + "[" + paramInt + "].username");
String password = this.environment.getProperty(MyBatisAutoConfiguration.PREFIX + "[" + paramInt + "].password");
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(DruidDataSource.class);
if( paramInt==0 ){
rootBeanDefinition.setPrimary(true);
}
rootBeanDefinition.getPropertyValues()
.add("driverClassName",driverClassName)
.add("url",url)
.add("username",username)
.add("password",password)
.add("filters","stat");
beanDefinitionRegistry.registerBeanDefinition("datasource"+paramInt , rootBeanDefinition);
logger.info( String.format("driverClassName %s url %s username %s password %s" , driverClassName,url,username,password ) );
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
for (int i : this.integers) {
DruidDataSource source = (DruidDataSource)configurableListableBeanFactory.getBean("datasource" + i );
logger.info( source.getUrl() );
};
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
}
使用方法:
在启动类上排除myBatis ,jdbc 的自动配置
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class,
DruidDataSourceAutoConfigure.class, JdbcTemplateAutoConfiguration.class})
然后启动即可,项目结构