1. 添加打印 SQL 的方式
打印 SQL 的方式有很多,比如有 idea 插件,有 mybatis 拦截器,有代理 datasource, 有代理 driver.
我比较认可的方式就是代理 driver. 这种无任何侵入性。
下面来介绍如何使用 p6spy Driver。
示例代码:
- 使用
BeanPostProcessor
来动态扩展 bean
。 - 判断
bean
是否为 DataSource
类型,并判断开发配置 dev.sql-log.enabled
。 - 根据现有的
driver
配置来创建新的 datasource
,并设置 url
。 - 实际开启,还需要
spy.properties
配置文件
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
| @Slf4j
@Configuration
public class DevDataSourceConfiguration implements BeanPostProcessor, EnvironmentAware {
@Setter
private Environment environment;
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof DataSource && parseBoolean(environment.resolvePlaceholders("${dev.sql-log.enabled:false}"))) {
log.info("已开启日志打印,将使用[P6SpyDriver]");
if (environment.acceptsProfiles(Profiles.of("run"))) {
log.warn("在生产环境一定要关闭配置[dev.sql-log.enabled]");
}
return proxyDataSource((DataSource) bean);
}
return bean;
}
public DataSource proxyDataSource(DataSource dataSource) {
if (dataSource instanceof AbstractRoutingDataSource) {
AbstractRoutingDataSource abstractRoutingDataSource = (AbstractRoutingDataSource) dataSource;
// resolvedDataSources
Field resolvedDataSourcesField = findField(AbstractRoutingDataSource.class, "resolvedDataSources");
makeAccessible(resolvedDataSourcesField);
@SuppressWarnings("unchecked")
Map<Object, DataSource> resolvedDataSources = (Map<Object, DataSource>) getField(resolvedDataSourcesField, abstractRoutingDataSource);
if (resolvedDataSources != null) {
resolvedDataSources.forEach((k, v) -> resolvedDataSources.put(k, convertToProxyDataSource(v)));
}
// resolvedDefaultDataSource
Field resolvedDefaultDataSourceField = findField(AbstractRoutingDataSource.class, "resolvedDefaultDataSource");
makeAccessible(resolvedDefaultDataSourceField);
DataSource resolvedDefaultDataSource = (DataSource) getField(resolvedDefaultDataSourceField, abstractRoutingDataSource);
if (resolvedDefaultDataSource != null) {
ReflectionUtils.setField(resolvedDefaultDataSourceField, abstractRoutingDataSource, convertToProxyDataSource(resolvedDefaultDataSource));
}
return abstractRoutingDataSource;
}
return convertToProxyDataSource(dataSource);
}
public DataSource convertToProxyDataSource(DataSource dataSource) {
if (dataSource instanceof HikariDataSource) {
HikariConfig oldConfig = (HikariDataSource) dataSource;
// jdbc:h2:mem:test to jdbc:p6spy:h2:mem:test
String jdbcUrl = oldConfig.getJdbcUrl();
if (!jdbcUrl.contains("p6spy")) {
jdbcUrl = "jdbc:p6spy" + jdbcUrl.substring(4);
}
HikariConfig newConfig = new HikariConfig();
newConfig.setPoolName("proxy-P6SpyDriver");
newConfig.setDriverClassName("com.p6spy.engine.spy.P6SpyDriver");
newConfig.setJdbcUrl(jdbcUrl);
newConfig.setUsername(oldConfig.getUsername());
newConfig.setPassword(oldConfig.getPassword());
return new HikariDataSource(newConfig);
}
return dataSource;
}
}
|
2. 代码实现位置
github 地址