mybatis Interceptor 적용
mybatis Interceptor 사용하여 실행 쿼리 로깅하기
mybatis Interceptor를 등록하면 DB 쿼리 실행 전/후로 등록한 Interceptor를 수행하여 특정 작업을 할 수 있다. 내 경우에는 실행된 쿼리문을 로깅하는데 사용했다.
설정 방법
mybatis-config.xml 생성
아래와 같은 설정 파일을 생성하고, plugins 밑에 interceptor 클래스를 등록해준다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?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="mapUnderscoreToCamelCase" value="true" />
<setting name="callSettersOnNulls" value="true" />
<setting name="jdbcTypeForNull" value="NULL" />
</settings>
<typeAliases>
<typeAlias alias="sql" type="java.util.HashMap"/>
</typeAliases>
<typeHandlers>
<typeHandler javaType="java.lang.String" jdbcType="CLOB" handler="org.apache.ibatis.type.ClobTypeHandler" />
</typeHandlers>
<plugins>
<plugin interceptor="com.sdp.common.interceptor.MybatisExecuteInterceptor"/>
</plugins>
</configuration>
Interceptor 정의
Interceptor 인터페이스를 구현하고 @Intercepts, @Signature 어노테이션을 붙여준다.
- @Intercepts: Executor 실행 과정 중 가로챌 대상을 정의한다.
- @Signature: mybatis에서 제공하는 Executor와 Intercept 하고자 하는 메서드명을 명시한다.
- type: Executor라는 인터페이스는 mybatis의 xml 파일에 작성된 SQL을 실행
- method: insert/update/delete가 실행되면 Executor의 update 메서드를 호출하며 select는 query메서드를 호출한다. 아래 코드에서는 update와 query를 모두 지정하였기 때문에 모든 쿼리에서 작동하는 것을 알 수 있다.
- args: 공통적으로 MapperStatement 객체가 Object[] 타입의 인덱스 0번에 필수로 저장된다. 여기에 xml 메타정보가 담겨있다.
Interceptor Class 생성 시 Override 되는 메서드에서 주의할 점은 아래와 같이 proceed() 와 Object.wrap()을 반드시 선언해주어야 한다.
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
@Intercepts(
{
@Signature(
type = Executor.class, methos = "update", args = {MappedStatement.class, Object.class}
),
@Signature(
type = Executor.class, methos = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}
)
}
)
public class SqlLogInterceptor implements Interceptor {
private final BatchLogger logger = BatchLogManager.getLogger(this.getClass());
private static final String BATCH_MDC_KEY = "batch";
@Override
public Object intercept(Invocation invocation) throws Throwable {
if(BeanUtil.IsLog()) {
AtomicReference<String> requestBody = new AtomicReference<>(HttpServletUtil.getRequestBody());
AtomicReference<String> batId = new AtomicReference<>("");
JSONParser jsonParser = new JSONParser();
String batchJobMDC = MDC.get(BATCH_MDC_KEY); // MDC 정보 가져옴
String batJobNm = "";
if(batchJobMDC != null) {
batJobNm = batchJobMDC;
}
// ... 중략
logger.batchCo(LogLevel.INFO, batJobNm, sql); // 로깅
}
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
// 아래와 같이 plugin에 등록
return Plugin.wrap(target, this);
}
}
추가로 위처럼 config파일을 따로 작성했다면 SqlSessionFactory에서 setConfigLocation으로 해당 파일 위치를 등록해주어야 한다.
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
@Configuration
@MapperScan(basePackages = {"com.sdp.common", "com.sdp.mapper"}, sqlSessionFactoryRef="sdpSqlSessionFactory" )
public class SdpDataSourceConfig {
@Value("${spring.mybatis.common.config}")
private String mybatisConfig;
@Value("${spring.mybatis.common.mapper}")
private String mybatisMapper;
@Autowired
ApplicationContext applicationContext;
@Bean(name="dataSource", destroyMethod="close")
@Primary
@ConfigurationProperties(prefix="spring.sdp.datasource")
public DataSource sdpDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name="sdpSqlSessionFactory")
@Primary
public SqlSessionFactory sdpSqlSessionFacotry(@Qualifier("dataSource") DataSource sdpDataSource) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(sdpDataSource);
sqlSessionFactoryBean.setConfigLocation(applicationContext.getResource(mybatisConfig));
sqlSessionFactoryBean.setMapperLocations(applicationContext.getResources(mybatisMapper));
return sqlSessionFactoryBean.getObject();
}
@Bean
@Primary
public SqlSessionTemplate sdpSqlSessionTemplate(SqlSessionFactory sdpSqlSessionFactory) throws Exception {
SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(sdpSqlSessionFactory);
sqlSessionTemplate.getConfiguration().setMapUnderscoreToCamelCase(true);
return sqlSessionTemplate;
}
}
This post is licensed under CC BY 4.0 by the author.