- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章深入浅出重构Mybatis与Spring集成的SqlSessionFactoryBean(上)由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
一般来说,修改框架的源代码是极其有风险的,除非万不得已,否则不要去修改。但是今天却小心翼翼的重构了Mybatis官方提供的与Spring集成的SqlSessionFactoryBean类,一来是抱着试错的心态,二来也的确是有现实需要.
先说明两点:
通常来讲,重构是指不改变功能的情况下优化代码,但本文所说的重构也包括了添加功能 。
本文使用的主要jar包(版本):spring-*-4.3.3.RELEASE.jar、mybatis-3.4.1.jar、mybatis-spring-1.3.0.jar 。
下面从Mybatis与Spring集成谈起.
1、集成Mybatis与Spring 。
1
2
3
4
5
6
7
|
<bean id=
"sqlSessionFactory"
p:dataSource-ref=
"dataSource"
class
=
"org.mybatis.spring.SqlSessionFactoryBean"
p:configLocation=
"classpath:mybatis/mybatis-config.xml"
>
<property name=
"mapperLocations"
>
<array>
<value>classpath*:**/*.sqlmapper.xml</value>
</array>
</property>
</bean>
|
集成的关键类为org.mybatis.spring.SqlSessionFactoryBean,是一个工厂Bean,用于产生Mybatis全局性的会话工厂SqlSessionFactory(也就是产生会话工厂的工厂Bean),而SqlSessionFactory用于产生会话SqlSession对象(SqlSessionFactory相当于DataSource,SqlSession相当于Connection).
其中属性(使用p命名空间或property子元素配置):
dataSource是数据源,可以使用DBCP、C3P0、Druid、jndi-lookup等多种方式配置 。
configLocation是Mybatis引擎的全局配置,用于修饰Mybatis的行为 。
mapperLocations是Mybatis需要加载的SqlMapper脚本配置文件(模式).
当然还有很多其它的属性,这里不一一例举了.
2、为什么要重构 。
1、源码优化 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
SqlSessionFactoryBean的作用是产生SqlSessionFactory,那我们看一下这个方法(SqlSessionFactoryBean.java
384
-
538
行):
/**
* Build a {@code SqlSessionFactory} instance.
*
* The default implementation uses the standard MyBatis {@code XMLConfigBuilder} API to build a
* {@code SqlSessionFactory} instance based on an Reader.
* Since 1.3.0, it can be specified a {@link Configuration} instance directly(without config file).
*
* @return SqlSessionFactory
* @throws IOException if loading the config file failed
*/
protected
SqlSessionFactory buildSqlSessionFactory()
throws
IOException {
Configuration configuration;
XMLConfigBuilder xmlConfigBuilder =
null
;
if
(
this
.configuration !=
null
) {
configuration =
this
.configuration;
if
(configuration.getVariables() ==
null
) {
configuration.setVariables(
this
.configurationProperties);
}
else
if
(
this
.configurationProperties !=
null
) {
configuration.getVariables().putAll(
this
.configurationProperties);
}
}
else
if
(
this
.configLocation !=
null
) {
xmlConfigBuilder =
new
XMLConfigBuilder(
this
.configLocation.getInputStream(),
null
,
this
.configurationProperties);
configuration = xmlConfigBuilder.getConfiguration();
}
else
{
if
(LOGGER.isDebugEnabled()) {
LOGGER.debug(
"Property `configuration` or 'configLocation' not specified, using default MyBatis Configuration"
);
}
configuration =
new
Configuration();
configuration.setVariables(
this
.configurationProperties);
}
if
(
this
.objectFactory !=
null
) {
configuration.setObjectFactory(
this
.objectFactory);
}
if
(
this
.objectWrapperFactory !=
null
) {
configuration.setObjectWrapperFactory(
this
.objectWrapperFactory);
}
if
(
this
.vfs !=
null
) {
configuration.setVfsImpl(
this
.vfs);
}
if
(hasLength(
this
.typeAliasesPackage)) {
String[] typeAliasPackageArray = tokenizeToStringArray(
this
.typeAliasesPackage,
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
for
(String packageToScan : typeAliasPackageArray) {
configuration.getTypeAliasRegistry().registerAliases(packageToScan,
typeAliasesSuperType ==
null
? Object.
class
: typeAliasesSuperType);
if
(LOGGER.isDebugEnabled()) {
LOGGER.debug(
"Scanned package: '"
+ packageToScan +
"' for aliases"
);
}
}
}
if
(!isEmpty(
this
.typeAliases)) {
for
(Class<?> typeAlias :
this
.typeAliases) {
configuration.getTypeAliasRegistry().registerAlias(typeAlias);
if
(LOGGER.isDebugEnabled()) {
LOGGER.debug(
"Registered type alias: '"
+ typeAlias +
"'"
);
}
}
}
if
(!isEmpty(
this
.plugins)) {
for
(Interceptor plugin :
this
.plugins) {
configuration.addInterceptor(plugin);
if
(LOGGER.isDebugEnabled()) {
LOGGER.debug(
"Registered plugin: '"
+ plugin +
"'"
);
}
}
}
if
(hasLength(
this
.typeHandlersPackage)) {
String[] typeHandlersPackageArray = tokenizeToStringArray(
this
.typeHandlersPackage,
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
for
(String packageToScan : typeHandlersPackageArray) {
configuration.getTypeHandlerRegistry().register(packageToScan);
if
(LOGGER.isDebugEnabled()) {
LOGGER.debug(
"Scanned package: '"
+ packageToScan +
"' for type handlers"
);
}
}
}
if
(!isEmpty(
this
.typeHandlers)) {
for
(TypeHandler<?> typeHandler :
this
.typeHandlers) {
configuration.getTypeHandlerRegistry().register(typeHandler);
if
(LOGGER.isDebugEnabled()) {
LOGGER.debug(
"Registered type handler: '"
+ typeHandler +
"'"
);
}
}
}
if
(
this
.databaseIdProvider !=
null
) {
//fix #64 set databaseId before parse mapper xmls
try
{
configuration.setDatabaseId(
this
.databaseIdProvider.getDatabaseId(
this
.dataSource));
}
catch
(SQLException e) {
throw
new
NestedIOException(
"Failed getting a databaseId"
, e);
}
}
if
(
this
.cache !=
null
) {
configuration.addCache(
this
.cache);
}
if
(xmlConfigBuilder !=
null
) {
try
{
xmlConfigBuilder.parse();
if
(LOGGER.isDebugEnabled()) {
LOGGER.debug(
"Parsed configuration file: '"
+
this
.configLocation +
"'"
);
}
}
catch
(Exception ex) {
throw
new
NestedIOException(
"Failed to parse config resource: "
+
this
.configLocation, ex);
}
finally
{
ErrorContext.instance().reset();
}
}
if
(
this
.transactionFactory ==
null
) {
this
.transactionFactory =
new
SpringManagedTransactionFactory();
}
configuration.setEnvironment(
new
Environment(
this
.environment,
this
.transactionFactory,
this
.dataSource));
if
(!isEmpty(
this
.mapperLocations)) {
for
(Resource mapperLocation :
this
.mapperLocations) {
if
(mapperLocation ==
null
) {
continue
;
}
try
{
XMLMapperBuilder xmlMapperBuilder =
new
XMLMapperBuilder(mapperLocation.getInputStream(),
configuration, mapperLocation.toString(), configuration.getSqlFragments());
xmlMapperBuilder.parse();
}
catch
(Exception e) {
throw
new
NestedIOException(
"Failed to parse mapping resource: '"
+ mapperLocation +
"'"
, e);
}
finally
{
ErrorContext.instance().reset();
}
if
(LOGGER.isDebugEnabled()) {
LOGGER.debug(
"Parsed mapper file: '"
+ mapperLocation +
"'"
);
}
}
}
else
{
if
(LOGGER.isDebugEnabled()) {
LOGGER.debug(
"Property 'mapperLocations' was not specified or no matching resources found"
);
}
}
return
this
.sqlSessionFactoryBuilder.build(configuration);
}
|
虽然Mybatis是一个优秀的持久层框架,但老实说,这段代码的确不怎么样,有很大的重构优化空间.
2、功能扩展 。
(1)使用Schema来校验SqlMapper 。
1
2
3
4
5
6
7
8
9
10
11
12
|
<!-- DTD方式 -->
<?xml version=
"1.0"
encoding=
"UTF-8"
?>
<!DOCTYPE mapper PUBLIC
"-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"
>
<mapper namespace=
"org.dysd.dao.mybatis.config.IExampleDao"
>
</mapper>
<!-- SCHEMA方式 -->
<?xml version=
"1.0"
encoding=
"UTF-8"
?>
<mapper xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xmlns=
"http://dysd.org/schema/sqlmapper"
xsi:schemaLocation=
"http://dysd.org/schema/sqlmapper http://dysd.org/schema/sqlmapper.xsd"
namespace=
"org.dysd.dao.mybatis.config.IExampleDao"
>
</mapper>
|
初看上去使用Schema更复杂,但如果配合IDE,使用Schema的自动提示更加友好,校验信息也更加清晰,同时还给其他开发人员打开了一扇窗口,允许他们在已有命名空间基础之上自定义命名空间,比如可以引入<ognl>标签,使用OGNL表达式来配置SQL语句等等.
(2)定制配置,SqlSessionFactoryBean已经提供了较多的参数用于定制配置,但仍然有可能需要更加个性化的设置,比如:
A、设置默认的结果类型,对于没有设置resultType和resultMap的<select>元素,解析后可以为其设置默认的返回类型为Map,从而简化SqlMapper的配置 。
1
2
3
4
5
6
7
8
|
<!--简化前-->
<select id=
"select"
resultType=
"map"
>
SELECT * FROM TABLE_NAME WHERE FIELD1 = #{field1, jdbcType=VARCHAR}
</select>
<!--简化后-->
<select id=
"select"
>
SELECT * FROM TABLE_NAME WHERE FIELD1 = #{field1, jdbcType=VARCHAR}
</select>
|
B、扩展Mybatis原有的参数解析,原生解析实现是DefaultParameterHandler,可以继承并扩展这个实现,比如对于spel:为前缀的属性表达式,使用SpEL去求值 。
(3)其它扩展,可参考笔者前面关于Mybatis扩展的相关博客 。
3、重构可行性 。
(1)在代码影响范围上 。
下面是SqlSessionFactoryBean的继承结构 。
从中可以看出,SqlSessionFactoryBean继承体系并不复杂,没有继承其它的父类,只是实现了Spring中的三个接口(JDK中的EventListener只是一个标识)。并且SqlSessionFactoryBean是面向最终开发用户的,没有子类,也没有其它的类调用它,因此从代码影响范围上,是非常小的.
(2)在重构实现上,可以新建一个SchemaSqlSessionFactoryBean,然后一开始代码完全复制SqlSessionFactoryBean,修改包名、类名,然后以此作为重构的基础,这样比较简单.
(3)在集成应用上,只需要修改和spring集成配置中的class属性即可.
以上所述是小编给大家介绍的重构Mybatis与Spring集成的SqlSessionFactoryBean(上),希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我网站的支持! 。
原文链接:http://www.cnblogs.com/linjisong/p/6022245.html 。
最后此篇关于深入浅出重构Mybatis与Spring集成的SqlSessionFactoryBean(上)的文章就讲到这里了,如果你想了解更多关于深入浅出重构Mybatis与Spring集成的SqlSessionFactoryBean(上)的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
Windows 集成 (NTLM) 身份验证和 Windows 集成 (Kerberos) 之间有什么区别? 如何在IIS6中实现这些 w.r.t. MSDN 最佳答案 Kerberos 和 NTLM
Keycloak是一个用 Java 编写的开源身份验证和身份管理解决方案。它提供了一个nodejs适配器,使用它我能够成功地与express集成。这是有效的路由文件: 'use strict'
这是我关于 Bamboo 的第二个问题 ( My First One )。阅读建议信息后我的理解是,我需要一个构建工具,例如 nAnt 或 MSbuild 来编写一个获取源代码并构建它的脚本(我正在开
可用于将第三方应用程序与 jira 4.3 集成的身份验证方案有哪些?显然,从客户那里获取用户名和密码听起来很荒谬。另外,我知道 oauth 身份验证仅适用于版本 5。请告诉我。谢谢。 附注。我不是在
我有一个使用 DDS 的旧版 C++ 应用程序用于异步通信/消息传递。我需要将此应用程序集成到使用 JMS 进行消息传递的 JavaEE 环境中。除了构建独立的 JMS/DDS 桥接模块之外,我还有其
我正在尝试使用 Whatsapp 发送测试消息,但收到此错误消息: "error":{"code":27,"description":"Recipient not available on chann
我想将 photologue 与我的 Django 应用程序集成,并使用它在车辆库存中显示照片......有点像 Boost Motor Group Inc. 提供的内容。我已经集成了该应用程序,所以
我目前正在尝试弄清楚如何与 fujitsu scansnap 扫描仪集成,但没有从 fujitsu 找到有关 fujitsu scansnap 管理器如何调用您的应用程序并将文件发送到您的应用程序的详
在我的项目中,我使用了 9 个(九个)int-ip:udp-inbound-channel-adapter 和一个 jms:inbound-channel-adapter。 Jms 适配器从服务器接收
在我们当前的原型(prototype)中,大多数标准 HTML 控件都被小程序取代,最重要的是表单提交由小程序触发。 有没有一种方法可以像 一样在服务器端调用关联的操作 ? 本文Applet and
是否可以使用 twilio 号码从 whatsapp 发送/接收短信?有人用whatsapp试过twilio吗?我问过客服,如果可能的话,他说,不确定,但很多人都问过这个问题。 最佳答案 万一其他人来
我们办公室中几乎不存在版本控制,这显然导致了很多麻烦。我们想使用SVN和Notepad++进行设置...任何人都对如何实现此目标有任何想法?我已经开始研究并浏览了这个网站: http://www.sw
曾经有提供这种集成的 spring-modules 项目;但是,该项目现已弃用。现在有没有人继续支持这种集成?谢谢。 最佳答案 工作正在进行中。 http://blog.athico.com/sear
我的理解是,根据 http://wiki.dbpedia.org/Datasets,DBpedia 从 YAGO 获取类层次结构,而不是实体。 .但是,类似 http://dbpedia.org/cl
任何人都可以帮助我如何将 OpenCMS 与 Java Spring Web 应用程序集成。已经用谷歌搜索并浏览了很多网站但没有用。所以,请帮助我。 最佳答案 我认为将 SpringMVC 与 Ope
我正在尝试使用新的 migs getaway (MPGS) 我遵循了下一个 url 中的代码 https://ap-gateway.mastercard.com/api/documentation/i
关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 4年前关闭。 Improve thi
我有一个 cmake 项目。我想轻松完成以下操作 搜索光标下任何变量、函数等的声明、定义和引用,这些可能在外部头文件中声明,其路径是在CMakeLists.txt中使用INCLUDE_DIRECTOR
有人能给我指点一下 Objective-C(或 c/c++)库的方向,或者教通过 FTP 上传或下载的教程(Objective-C)吗?最好能展示如何将文件下载到临时目录,然后稍后上传?我不介意针对
集成()给出了非常错误的答案: integrate(function (x) dnorm(x, -5, 0.07), -Inf, Inf, subdivisions = 10000L) # 2.127
我是一名优秀的程序员,十分优秀!