接口分析,以简单的mybatis接口为例

2024-06-07 08:48

本文主要是介绍接口分析,以简单的mybatis接口为例,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

关于接口的思考


在所有的框架当中,接口是少数的,实现类是大多数的


所以入手的时候,当我们明白提炼的接口是怎么回事的时候。
那就意味着你差不多读懂了这个框架的一半。


所以我们可以以mybatis几个包的接口来逐个分析
这个框架搭起来的时候它的意图是怎样的。
这样将大大减少我们分析一个框架的工作量


从org.apache.ibatis包开始读起
这里再插一个,接口之所以能代表很多的含义和背后的意图,在于它的无状态特性。
没有数据存储,但是随着新的接口规范的出现,除了常量以外,现在貌似也可以有接口的默认实现。
这样就意味着。接口的重要性,实际上得到进一步的提升。


annatations 注解包
参数注解 arg:
包含了代表的
column String类型 默认空字符""
javaType Class类型 默认是void.class
jdbcType JdbcType类型,默认枚举的UNDEFINED
typeHander Class类型 一看就知道是类型转换器
select String 查询别名?
resultMap String  映射的resultMap别名
name() String  列的名称


AutoMapConstructor 就一个空注解,用来做啥的呢?
自动映射的构造器,注解在构造器上的,因为
@Target({ElementType.CONSTRUCTOR})


CacheNamespace 缓存空间注解,用来注解在类上的,包含:
implementation() Class 指定他的实现类
eviction Class 失效的策略 默认LruCache.class 最少使用的机制
flushInteraval 刷新间隔 long = 0
size() 默认 int = 1024
是否读写 readWrite true
是否阻塞 blocking false 不阻塞
默认的一些属性  properities() 默认{} 返回的是另一个接口 注解Property,这里包含了name 和value的元信息
用来给实现对象准备的。


CacheNamespaceRef 缓存空间引用注解
name 名称
value Class 引用的类 void.class 默认


Case 这个注解有意思,因为他的target为{}
这说明这个直接是用来和其他混合使用的,他不能单独使用。
包含
value  String
type() Class<?>
results Result[] 返回注解
constructArgs() Arg[] 返回注解


用在发那个发上
ConstructArgs 这个注解只有一个方法
vlaue() 返回Arg[] 注解arg[] 数组


Delete 注解 用在方法上
value() String数组


MethodProvider 用在方法上
Type Class<?> 和类
method String 指定方法名称


Flush 用来执行刷新mapper状态
没有方法


Insert
同delete 
String[] value()


InsertProvider 同MethodProvider


Lang
Class<?> value


Many 同case的作用域


select()  这应该是表名
FetchType fetchType() default FetchType.DEFAULT 这是枚举指定
包含了懒加载LAZY EAGER DEFAULT 饥饿加载和默认加载


MapKey 用于方法
value 映射的key


Mapper 用于类 方法 属性 入参
无值


one 同many


Options 用在方法上注解
这个比较多
 内置了一个枚举类FlushCachePolicy
 刷新 statement语句


useCache 是否用缓存 默认true
刷新缓存的策略,默认 FlushCachePolicy.DEFAULT
结果集类型 默认 ResultSetType.FORWARD_ONLY 这是jdbc接口里的


Param注解,用来指定 value 用在入参上
Property 指定属性 name() value() String类型,不能单独使用
结果映射
Result
id()  false
column() ""
javaType  void.class
jdbcType  JdbcType.UNDEFINED
typeHandler() UnknownTypeHandler.class转换处理
One one() default @One;
Many many() default @Many; 一对多注解
ResultMap 注解方法上
value() String[] 数组


Results 注解方法上
id() ""  resultMap的名称
Result[] value  result注解集


ResultType 方法上 value() Class<?>


Select
value() String[] 注解返回数组


SelectKey 注解方法上
String[] statement();
String keyProperty();
String keyColumn() default "";
boolean before();
Class<?> resultType();
StatementType statementType() default StatementType.PREPARED;
这个是枚举,分为回调、预编译和正在进行的语句。
SelectProvider 同上面的


类型辨别注解 Discriminator 方法上
column() 列String
javaType
和jdbcType
转换Hander
Case[] cases()
update 和 updateProvider 同上


binding包,绑定包,这个一看就知道是mapper与接口的绑定
一个绑定异常 BindingException 继承了它自己写的持久化异常
加上序列号,持久化异常继承Ibatsi异常


MapperMethod 映射方法类
属性 SqlCommand 和方法标记 MethodSignature(包含返回值和入参)
两个分别是sql语句的封装类和执行method的封装类
方法中的两个静态内部类
就一个公开的构造方法,config method 和 mapperInterface
下面是执行方法 execute(sqlSession, args[])
返回Object
这是一个用来通过Switch分流的方法
分别分成 select update delete insert flush刷缓存,
默认就是抛异常,最后返回结果,里面所有的执行最后委托给了sqlSession去执行


MapperProxy 这个是代理类,实现了啥?
jdk的proxy方法代理 InvocationHandler 和序列化,加泛型T
属性
sqlSession
class<T> mapperInterface
Map<Method,MapperMethod> 方法和MapperMethod的缓存
唯一的构造方法就是传入上面的参数。


执行原则就是:
如果是类
Object.class.equals(method.getDeclaringClass())
就以本对象来执行,以及上面的args参数


如果是抽象类,就用另外的方式来执行这个方法。
如果是上面其他以外的,那么就缓存mapperMethod
然后通过mapperMethod.execute去执行。
所以这个是代理方法的执行。


MapperProxyFactory 代理类的生成
属性:
mapperInterface Class
Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>() 
方法对应的MapperMethod缓存


protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }
  这个方法生成了代理类
 
 由公开的方法 public T newInstance(SqlSession sqlSession)
 返回
 
 MapperRegistry 这个类用来存储
 MapperProxyFactory 对应的class 
 Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();


 提供公开的方法,用来通过ClassType返回对应的代理类
 可以增加指定的Mapper
 或者扫描该包的下的Mapper,包里符合ClassType的Mapper接口
 
 
 说好的分析接口,怎么又分析类了????????????
 走偏了,重新分析
 
 分析这个包下的,哦,没有接口
 
 下一个包
 builder中的唯一接口
 InitializingObject
 void initialize() throws Exception; 唯一的方法
 初始化一个实例的含义
 这个没有实现类,所以没用上??
 
 
 cache缓存包
 提供了一个接口
 Cache 缓存接口
 定义了几个常见的方法
 clear()
 getObject(key)
 putObject(key,value)
 removeObject(key)
 
 getId 获得缓存Id
 getSize  缓存尺寸
 getReadWriteLock 读写锁
 
 这个接口厉害了,实现了一大堆的不同缓存实现策略。看看默认使用的LRU吧
 
使用了装饰器模式,在已经实现的缓存中,再包一层
public class LruCache implements Cache {


  private final Cache delegate;
  private Map<Object, Object> keyMap;
  private Object eldestKey;
  
  这个被装饰的实现类
  PerpetualCache 这个类,是它的本来实现
  
  private String id;


  private Map<Object, Object> cache = new HashMap<Object, Object>();
用hashMap存数据,装饰类,就使用了一些淘汰策略、


cursor包,里面就定义了一个Cusor游标,继承Closeable 和 迭代器接口


 isOpen() true说明开始查找了
 isConsumed()  说明查完了
 getCurrentIndex() 得到当前下标,-1表示第一个对象没取到,取到了是0下标
 
 dataSource包,
 这个包的接口就一个 
 DataSourceFactory  数据源工厂
 void setProperties(Properties props) 设置数据源参数
 DataSource getDataSource() 获得数据源
 下面三个实现
 不采用数据连接池的实现 UnpooledDataSourceFactory
 采用数据连接池的实现  PooledDataSourceFactory
 还有一个JNDI的工厂实现 JndiDataSourceFactory
 这个工厂提供的方法就是把dataSource get出来
 而这个dataSource就包含了两种,连接池版本的,和现成创建连接的


 exception包没接口,跳过
 executor包接口,有好几个
 
 最外层:
 Executor 执行者接口
 实现了对数据库的操作
 int update(MappedStatement ms, Object parameter) 语句和参数执行
 查询以及缓存,还有查询的起始及条数,结果转换器,执行的sql
 <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;
 没有缓存的查询
 List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;
 批量结果,执行
 List<BatchResult> flushStatements() throws SQLException;
  提交和回滚
  void commit(boolean required) throws SQLException;
  void rollback(boolean required) throws SQLException;
 创建缓存的key
  CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);
是否有这个缓存
boolean isCached(MappedStatement ms, CacheKey key);
清缓存
void clearLocalCache();
延迟加载
void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType);
获得事务
   Transaction getTransaction();
   关闭,是否强制回滚
   void close(boolean forceRollback);
   设置包装类
   void setExecutorWrapper(Executor executor);


以上接口,用一个抽象类实现,然后用缓存类再实现
Executor --> BaseExecutor --> CachingExecutor 喜欢用装饰模式啊


KeyGenerator key生成器接口
生成前动作
void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter);


生成后动作
void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter);


接口的实现三个,
典型的是 查询key的设置,会存储在keyStatement的String[]数组中
全部存储在 MappedStatement这个对象中,而这个对象又会被存在config当中
全局config可以用来继承,然后写下其中的一些方法,取出mybatis的相关信息
能封装yeah!


loader中的接口
ProxyFactory 
void setProperties(Properties properties);
Object createProxy(Object target, ResultLoaderMap lazyLoader, Configuration configuration, ObjectFactory objectFactory, List<Class<?>> constructorArgTypes, List<Object> constructorArgs);
设置属性
和创建代理类
有两个实现,一个的CgLib的实现,一个是字节码增强的实现


WriteReplaceInterface
这个接口还没有用到


parameter中的接口
ParameterHandler
两个方法
获得参数和往ps中设置参数
  Object getParameterObject();
  void setParameters(PreparedStatement ps)throws SQLException;
  有一个default实现类
 
ResultSetHandler 结果处理器
三个方法
根据stmt获得处理后的结果
<E> List<E> handleResultSets(Statement stmt) throws SQLException; 
根据语句得到处理后的游标
<E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;
处理输出的结果参数
void handleOutputParameters(CallableStatement cs) throws SQLException;


有一个默认实现
DefaultResultSetHandler




StatementHandler 接口,用来实现语句的执行
准备语句
Statement prepare(Connection connection, Integer transactionTimeout)throws SQLException;

确定参数
void parameterize(Statement statement)throws SQLException;
批执行 
void batch(Statement statement)throws SQLException;
更新
int update(Statement statement)throws SQLException;
查询
<E> List<E> query(Statement statement, ResultHandler resultHandler)throws SQLException;
查询游标
<E> Cursor<E> queryCursor(Statement statement)throws SQLException;
获得执行语句
BoundSql getBoundSql();
获得参数处理器
ParameterHandler getParameterHandler();
两个实现
BaseStatementHandler

RoutingStatementHandler 这个照样采用了装饰器模式,以上面的Handler为被装饰类




下面是javassit java动态类库,提供了一些工具类
外层两个接口 ClassPath 和 Translator
ClassPath抽象出两个方法
InputStream openClassfile(String s) 根据字符串classFile转换为输入流
URL find(String s) 找url地址
void close() 关闭
这里有一系列的实现,这都是用来加载资源的


Translator 有两个实现,主要是利用动态字节码技术


这个包是工具类


jdbc没接口
lang有两个注解注解 java7版本和java8版本
UsesJava7
UsesJava8


log包中
抽象了log接口
只提供过了 isDebugEnabled 和 isTraceEnabled两个boolean判断
error(s,e)
error(s)
debug(s)
trace(s)
warn(s) 几个方法


根据工厂类,可以更换不同的日志系统


mapping包
DatabaseIdProvider  一个默认实现
SqlSource  三个实现类,不同的sql写法
两个接口
前者提供:
void setProperties(Properties p); 设置参数
String getDatabaseId(DataSource dataSource) throws SQLException; 获得数据源信息


后者提供
BoundSql getBoundSql(Object parameterObject);根据入参获得真正的sql




ognl包


ehhance子包里,
ExpressionAccessor接口
获取对象到上下文
    java.lang.Object get(org.apache.ibatis.ognl.OgnlContext ognlContext, java.lang.Object o);
设置对象
    void set(org.apache.ibatis.ognl.OgnlContext ognlContext, java.lang.Object o, java.lang.Object o1);
设置表达式
    void setExpression(org.apache.ibatis.ognl.Node node);


本地引用
public interface LocalReference {
    java.lang.String getName();


    java.lang.String getExpression();


    java.lang.Class getType();
}


OgnlExpressionCompiler 编译器


OrderedReturn 顺序返回 得到核心表达式,得到最后表达式
    java.lang.String getCoreExpression();


    java.lang.String getLastExpression();


ClassCache缓存接口
setClassInspector 设置class检查器
clear 清空
getSize 获得大小
get(class) 获得某class
put(class object) 存储某class对应的实例


ClassCacheInspector 类缓存检查器
 boolean shouldCache(java.lang.Class aClass) 需要被缓存吗
 
 ClassResolver 类接口器 类似于class forName 这个肯定要委托给jdk来
 java.lang.Class classForName(java.lang.String s, java.util.Map map) throws java.lang.ClassNotFoundException;


 ElementsAccessor 这个接口 遍历接口 存取器
 java.util.Enumeration getElements(java.lang.Object o) throws org.apache.ibatis.ognl.OgnlException;


 JavaSource接口 设置到上下文中,或者获取
 String toGetSourceString(OgnlContext ognlContext, Object o);
 String toSetSourceString(OgnlContext ognlContext, Object o);
 
 这里暂不分析了,有比较多的接口
 针对的的是Member Method Node NodeType  PropertyAccessor TypeConverter
 类似,但定义的方法有所不同
 
 parsing包里的 
 
 TokenHandler 占位符处理,这个接口,xml解析相关
 
 plugin扩展包
 Interceptor 解释器接口 形成解释器链
 Intercepts 解释器注解
 Signature 签名注解
 
 责任链模式
 
 
 反射的包 reflectionFactory
 ReflectorFactory 反射工厂
 
 是否缓存,设置缓存,根据classType得到反射类
 其他三个接口方法
 Invoker  包含了执行invoke 和 getType class的类型 两个方法,包含三个实现类
 GetFieldInvoker MethodInvoker SetFieldInvoker 这三个实现类
 ObjectWrapper 定义的方法比较多,主要的是
 get set方法的判断,以及是否是集合的判断,实现类有base 和collectionWrapper类
 
 ObjectWrapperFactory 都是用一个工厂类,来掩蔽构造器细节。
 两个方法,有他的包装类吗,根据元信息返回他的包装类
 boolean hasWrapperFor(Object object);
 ObjectWrapper getWrapperFor(MetaObject metaObject, Object object);
 
 脚本的包 scripting
 LanguageDriver 接口
 ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql);
 SqlSource createSqlSource(Configuration configuration, XNode script, Class<?> parameterType);
 SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType);
用来解析xml中的脚本,获取相应的sql语句


SqlNode 接口 应用动态上下文
boolean apply(DynamicContext context);


session会话包


SqlSessionFactory 工厂 生成sqlSession对象
  SqlSession openSession();得到一个sqlSession对象
  SqlSession openSession(boolean autoCommit);
  SqlSession openSession(Connection connection);
  SqlSession openSession(TransactionIsolationLevel level);


  SqlSession openSession(ExecutorType execType);
  SqlSession openSession(ExecutorType execType, boolean autoCommit);
  SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
  SqlSession openSession(ExecutorType execType, Connection connection);
  Configuration getConfiguration();得到配置类


SqlSession 接口继承了Closeable  默认实现和sqlSessionManager管理类实现代理类

一系列访问数据库的方法 
  <T> T selectOne(String statement);
  <T> T selectOne(String statement, Object parameter);
  <E> List<E> selectList(String statement);
  <E> List<E> selectList(String statement, Object parameter);
  <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds);
  <K, V> Map<K, V> selectMap(String statement, String mapKey);
  <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey);
  <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds);
  <T> Cursor<T> selectCursor(String statement);
  <T> Cursor<T> selectCursor(String statement, Object parameter);
  <T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds);
  void select(String statement, Object parameter, ResultHandler handler);
  void select(String statement, ResultHandler handler);
  void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler);
  int insert(String statement);
  int insert(String statement, Object parameter);
  int update(String statement);
  int update(String statement, Object parameter);
  int delete(String statement);
  int delete(String statement, Object parameter);
  void commit();
  void commit(boolean force);
  void rollback();
  void rollback(boolean force);
  List<BatchResult> flushStatements();
  void close();
  void clearCache();
  Configuration getConfiguration();
  <T> T getMapper(Class<T> type);
  Connection getConnection();
  
  接口 ResultHandler<T> 默认实现和包装类实现
  void handleResult(ResultContext<? extends T> resultContext);处理上下文
  
  接口 ResultContext<T> 有一个默认实现
  T getResultObject();
  int getResultCount();
  boolean isStopped();
  void stop();
  
  
  事务包 transaction
  Transaction 接口 两个实现类
    Connection getConnection() throws SQLException;
void commit() throws SQLException;
    void rollback() throws SQLException;
void close() throws SQLException;
Integer getTimeout() throws SQLException;

  TransactionFactory 接口 两个对应的实现类
    void setProperties(Properties props);
Transaction newTransaction(Connection conn);
Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit);

  type包
Alias 类注解 value

MappedJdbcTypes 类注解
注解 JdbcType[] value
includeNullJdbcType() false

MappedTypes 注解类
Class<?>[] value()

TypeHandler类型处理接口 base抽象实现,调用的留给子类去实现,不同的数据类型对应不同的处理方法
void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
T getResult(ResultSet rs, String columnName) throws SQLException;
T getResult(ResultSet rs, int columnIndex) throws SQLException;
T getResult(CallableStatement cs, int columnIndex) throws SQLException;
 
  这上面不同的数据类型对应到不同的处理器,数组的,bob的等等。
  
  
  

这篇关于接口分析,以简单的mybatis接口为例的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1038705

相关文章

MyBatis中$与#的区别解析

《MyBatis中$与#的区别解析》文章浏览阅读314次,点赞4次,收藏6次。MyBatis使用#{}作为参数占位符时,会创建预处理语句(PreparedStatement),并将参数值作为预处理语句... 目录一、介绍二、sql注入风险实例一、介绍#(井号):MyBATis使用#{}作为参数占位符时,会

mybatis执行insert返回id实现详解

《mybatis执行insert返回id实现详解》MyBatis插入操作默认返回受影响行数,需通过useGeneratedKeys+keyProperty或selectKey获取主键ID,确保主键为自... 目录 两种方式获取自增 ID:1. ​​useGeneratedKeys+keyProperty(推

MyBatis-Plus 中 nested() 与 and() 方法详解(最佳实践场景)

《MyBatis-Plus中nested()与and()方法详解(最佳实践场景)》在MyBatis-Plus的条件构造器中,nested()和and()都是用于构建复杂查询条件的关键方法,但... 目录MyBATis-Plus 中nested()与and()方法详解一、核心区别对比二、方法详解1.and()

SpringBoot+Redis防止接口重复提交问题

《SpringBoot+Redis防止接口重复提交问题》:本文主要介绍SpringBoot+Redis防止接口重复提交问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不... 目录前言实现思路代码示例测试总结前言在项目的使用使用过程中,经常会出现某些操作在短时间内频繁提交。例

springboot下载接口限速功能实现

《springboot下载接口限速功能实现》通过Redis统计并发数动态调整每个用户带宽,核心逻辑为每秒读取并发送限定数据量,防止单用户占用过多资源,确保整体下载均衡且高效,本文给大家介绍spring... 目录 一、整体目标 二、涉及的主要类/方法✅ 三、核心流程图解(简化) 四、关键代码详解1️⃣ 设置

spring中的ImportSelector接口示例详解

《spring中的ImportSelector接口示例详解》Spring的ImportSelector接口用于动态选择配置类,实现条件化和模块化配置,关键方法selectImports根据注解信息返回... 目录一、核心作用二、关键方法三、扩展功能四、使用示例五、工作原理六、应用场景七、自定义实现Impor

MyBatis ResultMap 的基本用法示例详解

《MyBatisResultMap的基本用法示例详解》在MyBatis中,resultMap用于定义数据库查询结果到Java对象属性的映射关系,本文给大家介绍MyBatisResultMap的基本... 目录MyBATis 中的 resultMap1. resultMap 的基本语法2. 简单的 resul

MybatisPlus service接口功能介绍

《MybatisPlusservice接口功能介绍》:本文主要介绍MybatisPlusservice接口功能介绍,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友... 目录Service接口基本用法进阶用法总结:Lambda方法Service接口基本用法MyBATisP

Mybatis的分页实现方式

《Mybatis的分页实现方式》MyBatis的分页实现方式主要有以下几种,每种方式适用于不同的场景,且在性能、灵活性和代码侵入性上有所差异,对Mybatis的分页实现方式感兴趣的朋友一起看看吧... 目录​1. 原生 SQL 分页(物理分页)​​2. RowBounds 分页(逻辑分页)​​3. Page

MyBatis Plus 中 update_time 字段自动填充失效的原因分析及解决方案(最新整理)

《MyBatisPlus中update_time字段自动填充失效的原因分析及解决方案(最新整理)》在使用MyBatisPlus时,通常我们会在数据库表中设置create_time和update... 目录前言一、问题现象二、原因分析三、总结:常见原因与解决方法对照表四、推荐写法前言在使用 MyBATis