Spring AOP를 이용한 SQL로깅(?를파라미터로 치환하여 DML로그출력),Spring JDBC로깅,Spring
Framework의 JdbcOperations을 포인트컷으로 해서 모든 SQL에 대해 로깅 충고
1. 로깅을 위한 Aspcet 작성
package onj.board.aop;
import org.slf4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.slf4j.LoggerFactory;
@Aspect
public class LoggingAspect {
private final
Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
// 사전충고
// Spring
Framework의 JdbcOperations을 포인트컷으로 해서 모든 SQL에 대해 로깅 충고가 적용
@Before("execution(*
org.springframework.jdbc.core.JdbcOperations.*(String, ..))")
public void
logBefore(JoinPoint joinPoint) {
logger.info("<<<<<<<<<<<<<<<<<
DAO 로깅 충고 실행");
Object[]
methodArgs = joinPoint.getArgs(), sqlArgs = null;
// 실행시킨 SQL
문장
String statement
= methodArgs[0].toString(); // ? 가 포함된 SQL문
// find the SQL
arguments (parameters)
for (int i = 1,
n = methodArgs.length; i < n; i++) {
Object arg =
methodArgs[i];
if (arg
instanceof Object[]) {
sqlArgs =
(Object[]) arg;
break;
}
}
// '?' 대신 파라미터로
대체
String
completedStatement = (sqlArgs == null ?
statement :
fillParameters(statement, sqlArgs));
logger.info(completedStatement);
}
//SQL문장의 ?를
넘겨주는 파라미터로 대체해서 최종SQL문을 리턴
private String
fillParameters(String statement, Object[] sqlArgs) {
// initialize
a StringBuilder with a guesstimated final length
StringBuilder
completedSqlBuilder = new StringBuilder(Math.round(statement.length() *
1.2f));
int index, //
will hold the index of the next ?
prevIndex =
0; // will hold the index of the previous ? + 1
// loop
through each SQL argument
for (Object
arg : sqlArgs) {
index =
statement.indexOf("?", prevIndex);
if (index
== -1)
break; // bail out if there's a mismatch in # of args vs. ?'s
// append
the chunk of SQL coming before this ?
completedSqlBuilder.append(statement.substring(prevIndex, index));
// append
the replacement for the ?
if (arg
== null)
completedSqlBuilder.append("NULL");
else
completedSqlBuilder.append(":"+arg.toString());
prevIndex
= index + 1;
}
// add the
rest of the SQL if any
if (prevIndex
!= statement.length())
completedSqlBuilder.append(statement.substring(prevIndex));
return
completedSqlBuilder.toString();
}
}
2. XML 설정파일에서
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<aop:aspectj-autoproxy />
<context:component-scan
base-package="onj.board.dao" />
<context:component-scan
base-package="onj.board.service" />
<!--
JdbcTemplate -->
<bean
id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"
p:dataSource-ref="dataSource" />
<!-- wire the
JdbcTemplate into your DAO (Alternatively, you could use autowiring)
-->
<bean id="boardDAO" class="onj.board.dao.BoardDAOImpl"/>
<!-- AOP를
적용하여 DML처리시 로깅을 위한 것 -->
<bean
id="myLogger" class="onj.board.aop.LoggingAspect" />
</beans>
3. DAO 파일에서는 jdbcTemplate을 어노테이션을 이용하여 주입받자.
@Repository("boardDAO")
public class BoardDAOImpl implements BoardDAO {
@Autowired
private
JdbcOperations jdbcTemplate;
.............................
}
이제 Spring JDBC를 통하여 실행되는 모든 SQL문은 로깅이 된다.