一、源码分析概述
目录
2.1、基础支撑层源码分析—日志模块,使用的设计模式:适配器模式、代理模式
3.1、基础支撑层源码分析 数据源模块需求。使用的设计模式:工厂模式
4.1、基础支撑层源码分析 缓存模块需。使用的设计模式:装饰器模式
mybatis架构分析
包分析 详见脑图:java学习/享学架构师课程/03.mybaits/mybatis源码结构.xmind
谈谈设计模式的原则:
- 单一职责原则:一个类或者一个接口只负责唯一项职责,尽量设计出功能单一的接口。
- 依赖倒转原则:高层模块不应该依赖底层模块具体实现,接口高层与底层。既面向接口编程,当实现发生变化时,只需提供新的实现类,不需要修改高层模块代码。
- 开放-封闭原则:程序对外扩展开放,对修改关闭,换句话说,当需求发生变化时,我们可以通过添加新模块来满足新需求,而不是通过修改原来的是现代码来满足新需求。
高级开发:面向接口编程
二、日志模块分析
2.1、基础支撑层源码分析—日志模块,使用的设计模式:适配器模式、代理模式
-
- Mybatis没有提供日志的实现类,需要接入第三方日志组件,但第三方日志组件都有各自的log级别,且各不相同,mybatis统一提供了trace、debug、warn、error四个级别(适配器模式解决)
mybatis中,对应日志组件的实现类,如log4jImpl,就是log4j的适配器。在logging包中。
-
- 自动扫描日志实现,并且第三方日志插件加载优先级如下,slf4j->commonsLogin->Log4J2->Log4j->JdkLog
- 日志的使用要优雅的嵌入到主体功能中(代理模式,动态代理解决)
2.2、适配器模式
适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁,将一个类的接口转换成客户希望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
Target:目标角色,期待得到的接口
Adaptee:适配者角色,被适配的接口
adapter:适配器角色,将源接口转换成目标接口
适用场景:当调用双方都不太容易修改的时候,为了复用现有组件可以使用适配器模式,在系统中接入第三方组件的时候经常被用到。
注意:如果系统中存在过多的适配器,会增加系统的复杂性,设计人员应考虑对系统进行重构。
mybatis中适配器的使用
代理模式那些事:
定义:给目标对象提供一个代理对象,并由代理对象控制对目标对象的引用
目的:
1、通过因考入代理对象的方式来间接访问目标对象,防止直接访问目标对象给系统带来不必要的复杂性;
2、通过代理对象对原有的业务增强;
为什么使用代理模式?
代理模式给我们带来的便利:
作为中介解耦客户端和真实对象,保护真实对象安全;
防止直接访问目标对象给系统带来不必要的复杂性;
对业务进行增强,增强点多样化;(AOP)
Connection代理对象(connectionLogger)能够返回一个prepareStatement的代理对象(prepareStatementLogger),让prepareStatement也具备日志能力打印参数;
prepareStatement的代理对象(prepareStatementLogger)能够返回一个resultSet的代理对象(ResultSetLogger),让resultSet也具备日志打印能力;
simpleExcutor类才是真正访问数据库的类
org.apache.ibatis.executor.SimpleExecutor的doQuery方法
org.apache.ibatis.executor.SimpleExecutor#prepareStatement方法生成Statement
我们可以看到,getConnection(statementLog)方法里是用connection的代理对象connectionLogger进行连接初始化的
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Connection connection = this.getConnection(statementLog);
Statement stmt = handler.prepare(connection, this.transaction.getTimeout());
handler.parameterize(stmt);
return stmt;
}
protected Connection getConnection(Log statementLog) throws SQLException {
Connection connection = this.transaction.getConnection();
return statementLog.isDebugEnabled() ? ConnectionLogger.newInstance(connection, statementLog, this.queryStack) : connection;
}