理解Beetlsql源码
理解与springboot结合的Beetlsql源码
首先,我们要引入两个Bean,一个SqlManagerFactoryBean和BeetlSqlScannerConfigurer。
我们再看下这两个类的组件:
SqlManagerFactoryBean的 组件
SqlManagerFactoryBean:是一个工厂bean,用于创建一个叫做SqlManager的对象,这个对象很重要,之后会详细进行讲解。
/**
* BeetlSql数据源,用于封装DataSource的,可以指定主从数据源
*/
BeetlSqlDataSource cs;
/**
* 数据库样式-MySqlStyle、OracleStyle等等,都集成的是DBStyle
*/
DBStyle dbStyle;
/**
* 名称转换样式,顾名思义就是对数据库中的属性进行转换、UnderlinedNameConversion、DefaultNameConversion等等
*/
NameConversion nc;
/**
* 拦截器
*/
Interceptor[] interceptors;
/**
* BeetlSql核心类
*/
SQLManager sqlManager;
/**
* 对指定的路径的md文件进行加载操作
*/
SQLLoader sqlLoader;
BeetlSqlScannerConfigurer组件
BeetlSqlScannerConfigurer:它主要继承了一个接口,叫做BeanDefinitionRegistryPostProcessor的一个后置处理器和设置一个ApplicationContextAware等等。
BeetlSqlScannerConfigurer的基本属性
/**
* 基本包,用于指定在该基本包路径下进行扫描,可以支持;空格,等分割多个包
*/
String basePackage;
String daoSuffix="Dao";
/**
* Spring上下文
*/
ApplicationContext applicationContext;
/**
* Bean名称
*/
String beanName;
BeanNameGenerator nameGenerator;
/**
* sqlManagerFactoryBean名称
*/
String sqlManagerFactoryBeanName;
下面我们深入的讲解下其创建流程和使用流程。
创建流程-即对象的生成流程
1.通过BeetlSqlScannerConfigurer这个后置处理器的postProcessBeanDefinitionRegistry方法
2.利用BeetlSqlClassPathScanner的scan扫描特定的包,然后找出指定后缀的相应的接口,然后往容器中注册BeetlSqlFactoryBean类的工厂bean(即生成相应BeanDefinition),这个工厂bean即在自动注入的时候,通过getObject方法获取相应的对象。
3.其中getObject方法,就是通过SqlManager的getMapper方法获取相应的代理对象(jdk代理)
4.然后其代理执行类为MapperJavaProxy,即实现了InvocationHandler方法
使用流程-即解析sql到发送sql到数据库的整个流程
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Class caller = method.getDeclaringClass();
String methodName = method.getName();
if(methodName.equals("toString")){
return "BeetlSql Mapper "+mapperInterface;
}
SqlResource resource = (SqlResource)this.mapperInterface.getAnnotation(SqlResource.class);
String sqlId = null;
if(resource!=null){
String preffix = resource.value();
String name = method.getName();
sqlId = preffix+"."+name;
}else{
sqlId = this.builder.getIdGen().getId(method.getDeclaringClass(),entityClass, method);
}
MapperInvoke invoke = sqlManager.getMapperConfig().getAmi(caller, methodName);
if (invoke != null) {
//内置的方法,直接调用Invoke
return invoke.call(this.sqlManager, this.entityClass, sqlId, method, args);
} else {
//解析方法以及注解,找到对应的处理类
MethodDesc desc = MethodDesc.getMetodDesc(sqlManager, this.entityClass, method, sqlId);
if (desc.sqlReady.length() == 0) {
invoke = MapperInvokeDataConfig.getMethodDescProxy(desc.type);
Object ret = invoke.call(this.sqlManager, this.entityClass, sqlId, method, args);
return ret;
} else {
invoke = MapperInvokeDataConfig.getSQLReadyProxy();;
Object ret = invoke.call(this.sqlManager, this.entityClass, desc.sqlReady, method, args);
return ret;
}
}
}
其实最终都是调用的是SqlManager的对象。