2015년 7월 14일 화요일

Spring AOP를 이용한 SQL로깅(?를파라미터로 치환하여 DML로그출력),Spring JDBC로깅,Spring Framework의 JdbcOperations을 포인트컷으로 해서 모든 SQL에 대해 로깅 충고

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문은 로깅이 된다.


댓글 없음:

댓글 쓰기