2万多行MyBatis源码,你知道里面用了多少种设计模式吗?
在MyBatis的解析两万多行的框架源码中,设计模式的源码巧妙使用是整个框架的精华。
MyBatis中主要使用了以下设计模式:工厂模式、解析单例模式、源码建造者模式、解析适配器模式、源码代理模式、解析组合模式、源码装饰器模式、模板模式、策略模式和迭代器模式。
具体来说,工厂模式用于SqlSessionFactory的创建,单例模式用于Configuration的管理,建造者模式用于ResultMap的构建,适配器模式用于统一日志接口,代理模式用于MapperProxy的实现,组合模式用于SQL标签的组合,装饰器模式用于二级缓存操作,模板模式用于定义SQL执行流程,策略模式用于多类型处理器的实现,迭代器模式用于字段解析的实现。
通过运用这些设计模式,MyBatis成功地实现了复杂场景的溯源码证件解耦,并将问题合理切割为若干子问题,以提高理解和解决的效率。
总的来说,MyBatis大约运用了种左右的设计模式,这使得框架在处理复杂问题时能够更加高效和灵活。
学习源码不仅可以帮助我们更好地理解设计模式和设计原则,更能够扩展我们的编码思维,积累实际应用的经验。
希望本文的分享能够帮助到您,同时也推荐您阅读《手写MyBatis:渐进式源码实践》一书,了解更多关于MyBatis的知识。
源码分析Mybatis MapperProxy初始化图文并茂
源码分析Mybatis MapperProxy初始化,本文基于Mybatis.3.x版本,展现作者阅读源码技巧。MapperScannerConfigurer作为Spring整合Mybatis的核心类,负责扫描项目中Dao类,并创建Mybatis的Maper对象即MapperProxy对象。
在项目配置文件中,关注到与Mapper相关的配置信息。源码分析的行文思路如下,可能会比较枯燥,但先给出MapperProxy的创建序列图,有助于理解。
MapperScannerConfigurer类图,实现Spring Bean生命周期相关功能。核心类及其作用简述如下:
BeanDefinitionRegistryPostProcessor负责设置SqlSessionFactory,生成的Mapper最终受该SqlSessionFactory管辖。
ClassPathMapperScanner的scan方法进行扫描动作,具体实现由ClassPathBeanDefinitionScanner的doScan方法和ClassPathMapperScanner的内部方法共同完成。
ClassPathMapperScanner#doScan方法首先调用父类方法,高校校园源码接着配置文件并构建对应的BeanDefinitionHolder对象。对这些BeanDefinitions进行处理,对Bean进行加工,加入Mybatis特性。
MapperFactoryBean作为创建Mapper的FactoryBean对象,其beanClass为MapperFactoryBean,初始化实例为MapperFactoryBean。在实例化时自动获取SqlSessionFactory或SqlSessionTemplate,用于创建具体的Mapper实例。
MapperFactoryBean的checkDaoConfig方法实现Mapper与Mapper.xml文件的关联注册。MapperRegistry负责管理注册的Mapper,核心类图展示了其关键属性和方法。
MapperRegistry#addMapper方法完成MapperProxy的注册,但实际的MapperProxy创建在getMapper方法中,根据接口获取MapperProxyFactory,调用newInstance创建MapperProxy对象。
至此,Mybatis Mapper的初始化构造过程完成一半,即MapperScannerConfigurer通过包扫描,构建MapperProxy。剩余部分,即MapperProxy与*.Mapper.xml文件中SQL语句的关联流程,将在下一篇文章中详细说明。通过MapperProxy对象的创建,为后续SQL执行流程做准备。
更多文章请关注:线报酱
三万字带你彻底吃透MyBatis源码!!
随着互联网的迅猛发展,MyBatis逐渐成为了Java开发者不可或缺的框架技术。许多大厂在面试中偏好问及MyBatis的ctf查看源码底层原理及源码实现,这表明了其在技术栈中的重要性。本文旨在全面解析MyBatis源码,帮助开发者深入理解这一强大的框架。为了方便学习,推荐大家先收藏后仔细研读。
MyBatis源码在封装了JDBC之后,实现了对数据库操作的高级抽象。无论是获取连接、预编译语句、参数封装还是执行SQL,其核心步骤并未改变。
解析过程始于通过`ClassLoader.getResourceAsStream`方法获取配置文件路径。这个过程确保了MyBatis能正确加载配置信息,进而解析XML文件,构建配置中心。
解析XML文件的关键在于`parseConfiguration`和`mapperParser.parse`方法。前者用于解析配置文件中的`Environment`、`Setting`等信息,后者则专注于解析Mapper映射器,将其与工厂类进行绑定。
构建`SqlSessionFactory`的过程涉及解析Mapper映射器,生成`MappedStatement`对象,以及将接口类型与工厂类绑定。最终,`DefaultSqlSessionFactory`被创建,用于管理会话生命周期。
会话的创建通过`openSession`方法完成,该方法实例化了`Executor`来执行SQL。`Executor`的配置则决定了事务管理和执行器类型。同时,axios源码详解`Transaction`的管理分为两种方式,以确保数据的一致性和完整性。
获取Mapper对象时,通过`mapperRegistry.getMapper`方法,该方法从`MapperRegistry`的`knownMappers`中获取接口类型和对应的工厂类。代理对象`MapperProxy`由JDK动态代理生成,用于执行实际的数据库操作。
执行SQL时,调用代理对象的`invoke`方法,进而调用`execute`方法。无论是查询还是其他操作,均遵循此流程。在查询场景下,`selectOne`与`selectList`功能实现相同,仅在参数处理上有所差异。
`MappedStatement`对象负责存储SQL信息,包括执行策略、参数类型等。`CacheKey`的生成则基于`BoundSql`内容,用于缓存结果,提高效率。
通过以上解析,我们可以看到MyBatis源码的简洁与高效。深入理解其结构与机制,不仅有助于提高开发效率,还能增强对数据库操作的理解。总的来说,MyBatis的源码并不复杂,只需耐心研读,两三天内即可掌握其核心。
干掉if else后,代码看起来爽多了!
今天,我们来深入剖析Mybatis框架中的设计模式,看看它如何巧妙地摆脱if/else的困扰,展现其独特魅力!
Mybatis庞大的2万多行源码中,巧妙运用了多种设计模式来优化工程结构,如创建型模式的工厂设计,如SqlSessionFactory的构建。它通过SqlSessionFactory工厂模式,为我们获取会话提供统一接口,每次数据库操作都会通过这个工厂开启新的会话,其中包含了数据源配置、事务处理和SQL执行器的构建。
另外,Configuration作为单例配置类,采用单例模式确保全局唯一,整合了映射、缓存等众多配置,并在SqlSessionFactoryBuilder构建阶段初始化。ErrorContext、LogFactory和Configuration也是采用类似的单例模式,为框架的稳定运行提供支持。
建造者模式在Mybatis中体现在如XMLConfigBuilder等类,通过逐步构建对象,避免了直接设置属性,保持了代码的清晰和可维护性。日志框架的适配则体现了适配器模式,通过统一接口让不同框架能无缝协作,如对Log4j、Log4j2和Slf4J等的适配。
代理模式在MapperProxy的实现中尤为显著,它作为DAO接口的代理,统一了CRUD方法的调用,简化了业务逻辑。此外,组合模式在SQL配置中体现,通过SqlNode接口构建SQL规则树,组合出各种复杂场景。
行为型模式如模板模式和策略模式在Mybatis中也大显身手,BaseExecutor定义了查询和修改的通用流程,而多类型处理器策略模式则通过TypeHandler实现了不同类型数据的处理策略。
迭代器模式在PropertyTokenizer中体现,用于对象关系的解析,提升了代码的灵活性。总之,Mybatis巧妙地运用了约种设计模式,优化了代码结构,使得代码更加简洁和高效。
深入研究源码不仅有助于理解框架工作原理,还能提升技术理解和实践能力,是成为高级工程师和架构师的重要基石。通过学习这些优秀的设计实践,我们可以更好地应对复杂的技术挑战。
深入浅出 MyBatis 的一级、二级缓存机制
深入浅出 MyBatis 的一级、二级缓存机制
缓存机制是提升系统性能的关键手段之一,MyBatis 作为一款优秀的持久层框架,同样提供了缓存支持,分为一级缓存和二级缓存。一级缓存是 SqlSession 级别的缓存,而二级缓存则是 Mapper 级别的缓存。在实际应用中,理解并合理使用缓存可以显著提升系统的响应速度和性能。
一级缓存的作用是存储 SqlSession 执行的 SQL 查询结果,当再次执行相同 SQL 时,如果缓存命中,则直接返回缓存中的数据,避免了重复查询数据库。一级缓存的内部结构通过 DefaultSqlSession 类中的 PerpetualCache 实现,当用户发起查询时,MyBatis 在 Local Cache 中进行查询,如果命中则返回结果,未命中则查询数据库并将结果写入 Cache。
一级缓存的配置默认为 SESSION 级别,但也可以设置为 STATEMENT 级别,以更细粒度地控制缓存范围。通过实验可以直观地观察到一级缓存的效果,比如查询、修改数据库操作对缓存的影响,以及不同 SqlSession 之间的缓存隔离。
一级缓存的工作流程涉及 SqlSession、Executor 和 Cache,其中 Executor 执行 SQL 请求并负责缓存管理,Cache 接口提供缓存的基本操作。通过源码分析,可以深入理解一级缓存的实现细节,包括缓存的创建、查询和刷新机制。
二级缓存的引入是为了实现多个 SqlSession 之间的缓存数据共享,它基于 namespace 进行管理,使得同一个 namespace 下的操作共享缓存。二级缓存的配置需要在全局配置文件中开启,并确保实体类实现 Serializable 接口以支持缓存数据的序列化与反序列化。
通过实验,可以验证二级缓存与一级缓存的差异,比如测试缓存与 SqlSession 的关系、执行 commit 操作对缓存的影响,以及多表查询场景下的缓存问题和解决方案。
二级缓存的工作流程类似于一级缓存,涉及 CachingExecutor、TransactionalCache 等组件,通过装饰器模式实现缓存的管理。源码分析揭示了二级缓存的实现细节,包括缓存的创建、查询、刷新以及与事务的交互。
总结而言,MyBatis 的一级缓存和二级缓存提供了数据缓存功能,有助于提升系统性能,但需要根据实际应用场景合理配置和使用。一级缓存在多个 SqlSession 或分布式环境下可能存在局限性,而二级缓存在多表查询场景中也可能导致脏数据问题。生产环境中通常建议关闭缓存机制,以避免潜在的问题。
为何Mybatis将Integer为0的属性解析成空串?
在一次代码审查中,同事分享了一个有趣的问题:在Mybatis中,Integer类型的age为0时,为什么会解析成空串,导致SQL语句的条件判断失效?
为了解答疑问,作者查阅了Mybatis的源码。首先,从GitHub上的最新版本下载代码,构建测试用例。在SqlSessionFactoryBuilder的构建流程中,经过XMLConfigBuilder解析配置,构建Configuration类,进而生成SqlSessionFactory和SqlSession。执行过程中,mybatis使用SimpleExecutor或CachingExecutor,后者涉及动态代理和拦截器的执行,关键在于DynamicSqlSource和IfSqlNode类。
在IfSqlNode的evaluator.evaluateBoolean方法中,使用了OGNLCache来获取值,而问题出在OGNL表达式对空字符串的处理上。在ASTNotEq类的compareWithConversion方法中,当字符串长度为0时,会被解析为0.0,这不仅影响Integer,也影响Float和Double类型。因此,问题的根源在于OGNL表达式对空字符串的解析规则。
2024-12-23 05:59
2024-12-23 05:39
2024-12-23 05:35
2024-12-23 05:27
2024-12-23 04:22