SpringBoot整合Mybatis自定义 * 不起作用的处理方案
作者:小胖学编程 发布时间:2023-03-19 04:35:14
SpringBoot整合Mybatis自定义 * 不起作用
Mybatis插件生效的方式:
1. 原始的读取mybatis-config.xml文件
该方式和Spring无关,是通过反射的形式创建插件对象,此时会执行org.apache.ibatis.plugin.Interceptor#setProperties方法,以读取配置参数。
mybatis:
mapper-locations: classpath*:/mapping/*.xml
type-aliases-package: com.tellme.pojo
#读取全局配置的地址
config-location: classpath:mybatis-config.xml
在resource目录下配置mybatis的全局配置:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="multipleResultSetsEnabled" value="true"/>
<setting name="useColumnLabel" value="true"/>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="useGeneratedKeys" value="true"/>
<setting name="defaultExecutorType" value="SIMPLE"/>
<setting name="defaultStatementTimeout" value="25000"/>
</settings>
<typeAliases>
<typeAlias alias="Integer" type="java.lang.Integer"/>
<typeAlias alias="Long" type="java.lang.Long"/>
<typeAlias alias="HashMap" type="java.util.HashMap"/>
<typeAlias alias="LinkedHashMap" type="java.util.LinkedHashMap"/>
<typeAlias alias="ArrayList" type="java.util.ArrayList"/>
<typeAlias alias="LinkedList" type="java.util.LinkedList"/>
</typeAliases>
<!--配置的插件名-->
<plugins>
<plugin interceptor="com.xxx.yyy.plugins.PrintSqlInfoInterceptor"/>
</plugins>
</configuration>
2. 与SpringBoot容器整合
网上很多方案说:mybatis自定义 * 上加上@Component注解便可以生效。但是我将自定义 * 放入到Spring容器中,自定义 * 却失效了。
然后找到了springboot配置多数据源后mybatis * 失效文章,说是自定义配置了数据源导致了 * 失效。
2.1 mybatis的自动装载
源码位置:org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
@Configuration
@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
@ConditionalOnBean(DataSource.class)
@EnableConfigurationProperties(MybatisProperties.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class MybatisAutoConfiguration {
private static Log log = LogFactory.getLog(MybatisAutoConfiguration.class);
@Autowired
private MybatisProperties properties;
//会依赖注入Spring容器中所有的mybatis的Interceptor *
@Autowired(required = false)
private Interceptor[] interceptors;
...
@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setVfs(SpringBootVFS.class);
if (StringUtils.hasText(this.properties.getConfigLocation())) {
factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
}
factory.setConfiguration(properties.getConfiguration());
//手动放入到了setPlugins方法中。
if (!ObjectUtils.isEmpty(this.interceptors)) {
factory.setPlugins(this.interceptors);
}
if (this.databaseIdProvider != null) {
factory.setDatabaseIdProvider(this.databaseIdProvider);
}
if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
}
if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
}
if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
factory.setMapperLocations(this.properties.resolveMapperLocations());
}
return factory.getObject();
}
...
}
上面源码中:自动注入了Interceptor[]数组(我们只需将mybatis的自定义 * 对象放入到Spring容器中)。后续放入了sqlSessionFactory中。
但是项目中虽然自定义配置了sqlSessionFactory类,但却未设置factory.setPlugins(this.interceptors);。导致即使将自定义 * 放入到Spring容器,但却不生效。
解决方法,需要手动修改自定义的sqlSessionFactory类。
3. 在mybatis-config.xml配置又放入Spring容器
这种情况下,mybatis自定义 * 会被执行两次。即在mybatis-config.xml配置的 * 会通过反射的方式创建 * ,放入Spring容器的 * 也会被初始化。
源码位置:org.mybatis.spring.SqlSessionFactoryBean#buildSqlSessionFactory
protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
Configuration configuration;
...读取属性中的plugins,即org.mybatis.spring.SqlSessionFactoryBean#setPlugins设置的。
if (!isEmpty(this.plugins)) {
for (Interceptor plugin: this.plugins) {
configuration.addInterceptor(plugin);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Registered plugin: '" + plugin + "'");
}
}
}
...解析xml配置(通过反射创建 * 对象)
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();
}
}
return this.sqlSessionFactoryBuilder.build(configuration);
}
最终会执行到:
private void pluginElement(XNode parent) throws Exception {
if (parent != null) {
for (XNode child: parent.getChildren()) {
String interceptor = child.getStringAttribute("interceptor");
Properties properties = child.getChildrenAsProperties();
//反射创建mybatis的插件。
Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance();
interceptorInstance.setProperties(properties);
configuration.addInterceptor(interceptorInstance);
}
}
}
SpringBoot 自定义Mybatis *
开发过程中经常回需要对要执行的sql加以自定义处理,比如分页,计数等。通过 MyBatis 提供的强大机制,使用插件是非常简单的,只需实现 Interceptor 接口,并指定想要拦截的方法签名即可。
@Intercepts({@Signature(type = Executor.class,method = "query",args = {MappedStatement.class,Object.class, RowBounds.class,ResultHandler.class})})
public class MyPageInterceptor implements Interceptor {
private static final Logger logger= LoggerFactory.getLogger(MyPageInterceptor.class);
@Override
public Object intercept(Invocation invocation) throws Throwable {
logger.warn(invocation.toString());
return invocation.proceed();
}
@Override
public Object plugin(Object o) {
return Plugin.wrap(o,this);
}
@Override
public void setProperties(Properties properties) {
logger.warn(properties.toString());
}
}
我的配置
mybatis:
type-aliases-package: me.zingon.pagehelper.model
mapper-locations: classpath:mapper/*.xml
configuration:
map-underscore-to-camel-case: true
default-fetch-size: 100
default-statement-timeout: 30
在springboot中要给mybatis加上这个 * ,有三种方法,前两种方法在启动项目时不会自动调用自定义 * 的setProperties方法。
第一种
直接给自定义 * 添加一个@Component注解,当调用sql时结果如下,可以看到 * 生效了,但是启动时候并没有自动调用setProperties方法。
第二种
在配置类里添加 * ,这种方法结果同上,也不会自动调用setProperties方法。
@Configuration
public class MybatisConfig {
@Bean
ConfigurationCustomizer mybatisConfigurationCustomizer() {
return new ConfigurationCustomizer() {
@Override
public void customize(org.apache.ibatis.session.Configuration configuration) {
configuration.addInterceptor(new MyPageInterceptor());
}
};
}
}
第三种
这种方法就是跟以前的配置方法类似,在yml配置文件中指定mybatis的xml配置文件,注意config-location属性和configuration属性不能同时指定
mybatis:
config-location: classpath:mybatis.xml
type-aliases-package: me.zingon.pagehelper.model
mapper-locations: classpath:mapper/*.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<package name="me.zingon.pacargle.model"/>
</typeAliases>
<plugins>
<plugin interceptor="me.zingon.pagehelper.interceptor.MyPageInterceptor">
<property name="dialect" value="oracle"/>
</plugin>
</plugins>
</configuration>
可以看到,在启动项目的时候setProperties被自动调用了
前两种方法可以在初始化自定义 * 的时候通过 @Value 注解直接初始化需要的参数。
来源:https://www.jianshu.com/p/5fddb7f67108


猜你喜欢
- 介绍和使用场景1)什么是消息一个事件,需要广播或者单独传递给某个接口2)为什么使用这个配置更新了,但是其他系统不知道是否更新SpringCl
- 前言大家对AOP应该都不陌生, 就算没有用过也肯定听说过,切面编程一直是一个热点的话题,AOP即Aspect Oriented Progra
- filter自定义过滤器 增加了 对验证码的校验package com.youxiong.filter;import com.y
- using System; using System.Drawing; using System.Collec
- http interface从 Spring 6 和 Spring Boot 3 开始,Spring 框架支持将远程 HTTP 服务代理成带
- Java中Filter、Servlet、Listener的学习资料,希望大家喜欢1、Filter的功能filter功能,它使用户可以改变一个
- Java基于对象流实现银行系统的具体代码,供大家参考,具体内容如下系统特点:数据持久化到文件中,系统启动后,加载文件中数据到集合中,相当于做
- 问题是这样的,我用eclipse发送httpclient请求如下没有问题,但是在idea中就返回400,为毛呢???excuse me?pa
- 在C#语言中,DateTime是用来表示时间的类,在C#的DateTime时间类中,提供了好像时间对象加减法操作,可用于某一个时间对象加减
- 1集合的概念把集合看做是一个容器,集合不是一个类,是一套集合框架,框架体系包含很多的集合类,java api提供了集合存储任意类型(基本包装
- MyBatis 是支持普通 SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis 消除了几乎所有的JDBC代码和参数的手工设置以及
- 今天做项目的时候,遇到一个问题,如果我调用某个服务的接口,但是这个服务挂了,同时业务要求这个接口的结果是必须的,那我该怎么办呢,答案是通过h
- 这篇文章主要介绍了SPRING IOC注入方式过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋
- java中字符串转整数及MyAtoi方法的实现 该题虽然和我们正常使
- 本文所述实例实现将一张图片上传到指定的文件夹,然后在窗体上的PictrueBox控件中显示出来。具体功能代码如下:private void
- 一、需求来源app需要支持实现游客模式,启动后直接进入首页菜单,但是进入二级页则自动调用登录页面。总结需求就是父视图拦截子视图的响应事件,思
- 前言最近公司在重构广告系统,其中核心的打包功由广告系统调用,即对apk打包的调用和打包完成之后的回调,需要提供相应的接口给广告系统。因此,为
- Nacos简介Nacos 英文全称为 Dynamic Naming and Configuration Service,是一个由阿里巴巴团队
- 一、select是什么select——>用于选择更快的结果。基于场景理解比如客户端要查询一个商
- 今天学习了Map集合的几种方法,尤其是遍历Map集合感觉尤为重要,所以发出来供大家学习和自己复习以用。众所周知Map集合里存储元素是以键值对