웹 개발

XML 파일로 AOP 적용하기

_KH_ 2025. 4. 24. 09:21

[문제]

1. around
   board S_ALL
   member S_ALL
   수행시간을 비교하는 공통로그를 호출

2. before, after
   회원가입 전후로 로그 출력
   before >> 메서드명을 출력
   after >> 인자를 출력(누가 가입했는지 출력)

3. returning, throwing
   로그인한 회원이 관리자라면,
   관리자가 로그인했습니다. 라고 출력
   만약 일반회원이 로그인했다면
   예외 발생
   그리고 그 예외가 발생했음을 알리는 공통로그를 출력

 

공통적인 기능 즉, 횡단 관심이므로 따로 Advice로 분리하는데 

모든 문제가 다 로그를 출력하는 공통적인 역할을 하기 때문에 하나의 클래스로 작성했다.

→ 코드의 응집도 향상.

 

1. LogAdvice

package com.example.biz.common;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.util.StopWatch;

import com.example.biz.member.MemberVO;
// 모두 로그를 출력하는 메서드이므로 하나의 클래스 안에 작성 
public class LogAdvice {

	// 1-1. s-all 수행시간을 비교하는 공통로그
	public Object timeLog(ProceedingJoinPoint pjp) {

		Object obj = null;

		StopWatch sw = new StopWatch();
		// 필요 시에는 new 해도 ok

		// 서비스 시작
		sw.start();

		try {
			obj = pjp.proceed();
		} catch(Throwable e) {
			e.printStackTrace();
		}
		sw.stop(); // 시간 측정 끝

		Long time = sw.getTotalTimeMillis();
		System.out.println("수행 시간 : ["+time+"]");

		return obj;
	}

	// 2. 회원가입 전후로 로그 출력(before, after)
	// 2-1. before
	public void beforeLog(JoinPoint jp) {

		String methodName = jp.getSignature().getName();
		System.out.println("메서드 시그니쳐 출력 : ["+methodName+"]");
	}

	// 2-2. after
	public void afterLog(JoinPoint jp) {
		Object[] args = jp.getArgs();
		System.out.println("인자 출력 : [");
		for(Object arg : args) {
			System.out.println(arg);
		}
		System.out.println("]");
	}

	//3-1. returning
	/*public void returningLog(Object returnObj) {
		   if (returnObj instanceof MemberVO membervo) {
		        if ("ADMIN".equals(membervo.getMrole())) {
		            System.out.println("관리자가 로그인했습니다.");
		        } else {
		            System.out.println("일반회원 로그인!");
		        }
		    }
		}*/
	
	// 3-1. returning
	public Object returningLog(ProceedingJoinPoint pjp) throws Throwable {
		Object obj = null;
		
		try {
			obj = pjp.proceed();
			
			if(obj instanceof MemberVO) { // 타입 확인
				MemberVO vo = (MemberVO) obj; // 다운캐스팅
				if(vo.getMrole().equals("ADMIN")) { 
					System.out.println("관리자가 로그인 했습니다.");
				} else { // 관리자가 아닌 경우 예외 발생
					throw new IllegalArgumentException("일반회원 로그인!");
				}
			}
		} catch (IllegalArgumentException e) { // 예외처리
			System.out.println("일반회원 로그인 예외처리");
			return null;
		}
		return obj;
	}
	
	
	// 3-2. throwing
	public void throwingLog(JoinPoint jp, Exception exceptObj) {
		if(exceptObj instanceof IllegalArgumentException) { // 예외라면
			System.out.println("일반회원 로그인! 예외 발생!");
		} else {
			System.out.println("확인되지 않은 예외");

		}
	}
}

 

2. applicationContext.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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
           http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

	<context:component-scan base-package="com.example.biz.board.impl" />
	<context:component-scan base-package="com.example.biz.member.impl" />
	<context:component-scan base-package="com.example.biz.common"/>
	
	<!-- 1. 빈(Bean) 등록 -->
	<bean id = "LogAdvice" class="com.example.biz.common.LogAdvice"/>
	
	<!-- 2. AOP 설정 -->
	<aop:config>
	<!-- 문제 1 : 포인트컷 -->
	<aop:pointcut id="timeAround" expression="execution(* com.example.biz..*ServiceImpl.get*List(..))"/>
	<!-- 문제 2 : 포인트컷 -->
    <aop:pointcut id = "join" expression="execution(* com.example.biz.member.impl.MemberServiceImpl.insert(..))"/>
	<!-- 문제 3 : 포인트컷 -->
	<aop:pointcut id = "login" expression="execution(* com.example.biz.member.impl.MemberServiceImpl.getMember(..))"/>

		<aop:aspect ref="LogAdvice">
			<!-- 문제 1 : 애스택트 - AROUND -->
			<aop:around method = "timeLog" pointcut-ref = "timeAround"/>
			<!-- 문제 2: 애스팩트 - BEFORE/AFTER -->
			<aop:before method = "beforeLog" pointcut-ref="join"/>
			<aop:after method = "afterLog" pointcut-ref="join"/>
			<!-- 문제 3 : 애스팩트 - RETURNING/THROWING -->
			<aop:around method="returningLog" pointcut-ref="login"/>
			<aop:after-throwing method = "throwingLog" pointcut-ref ="login" throwing = "exceptObj"/>
			</aop:aspect>
	</aop:config>
</beans>

 

자꾸 applicationContext.xml에서 xsd 파일들을 인식못했는데.. 

Eclipse는 기본적으로 외부 사이트 접속해서 XSD 파일을 자동으로 다운받지 않는다.

따라서 [preference] → [XML catalog]에 들어가서 [Download external resources like referenced DTD, XSD]를 체크해주었더니 해결.

 

'웹 개발' 카테고리의 다른 글

Eclipse와 VSCode  (0) 2025.04.26
Map 등을 DI 할 수는 없을까?  (0) 2025.04.25
AOP  (0) 2025.04.23
이메일 API 코드를 Spring Boot로 변환할 때 경고 처리  (0) 2025.04.22
JSP/Servlet → Spring Boot 이관 중 배운 점  (0) 2025.04.21