2016년 7월 26일 화요일

Spring AOP를 이용한 SQL로깅(?를파라미터로 치환하여 DML로그출력),Spring JDBC로깅 - 스프링실무교육학원


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


댓글 없음:

댓글 쓰기