잡동사니

[Spring] AOP기반 SQL Logging 본문

IT/Java

[Spring] AOP기반 SQL Logging

yeTi 2018. 8. 8. 12:23

안녕하세요. yeTi입니다.

오늘은 Spring에서 AOP를 활용하여 SQL Log를 확인해보려고 합니다.


설치 환경

- Spring Boot  : 1.5.4.RELEASE

- Mybatis : 1.3.2


1. Aspect에 다음과 같이 구현합니다.

- @Around("execution(* org.apache.ibatis.session.SqlSession.*(String, ..))")

public Object logBefore(ProceedingJoinPoint pjp) throws Throwable {

Object[] methodArgs = pjp.getArgs(), sqlArgs = null;

String statement = null;

// SQL ID

String sqlId = methodArgs[0].toString();

// find the SQL arguments (parameters)

for (int i = 1, n = methodArgs.length; i < n; i++) {

Object arg = methodArgs[i];

if (arg instanceof HashMap) {

@SuppressWarnings("unchecked")

Map<String, Object> map = (Map<String, Object>) arg;

// ? 가 포함된 SQL문

statement = ((SqlSessionTemplate)pjp.getTarget()).getConfiguration().getMappedStatement(sqlId)

.getBoundSql(map).getSql();

sqlArgs = new Object[map.size()];

Iterator<String> itr = map.keySet().iterator();

int j = 0;

while(itr.hasNext()) {

sqlArgs[j++] = map.get(itr.next());

}

}

break;

}

// '?' 대신 파라미터로 대체

    String completedStatement = (sqlArgs == null ? 

    statement : fillParameters(statement, sqlArgs));

    

    Object result = pjp.proceed();

    

    log.info(completedStatement);

    

    return result;

}


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. Spring의 CGLIB 프록시를 사용하도록 설정합니다.

- application.yml에 다음을 추가합니다.

- spring.aop.proxy-target-class: true

Comments