위클리페이퍼

Jihye Gim·2026년 3월 29일

Codeit SB11

목록 보기
11/22

Q. Spring에서 AOP(Aspect Oriented Programming)가 필요한 이유와 이를 활용한 실제 애플리케이션 개발 사례에 대해 설명하세요.

1. Spring에서 AOP(Aspect Oriented Programming, 관점 지향 프로그래밍)가 필요한 이유

■ "핵심 로직"과 "공통 관심사(부가 기능)"의 분리

  • 실제 애플리케이션을 개발하다 보면, 모든 비즈니스 로직(핵심 코드) 외에도
    • 로깅(로그 남기기)
    • 트랜잭션 관리
    • 보안(권한 체크 등)
    • 예외 처리
      같은 기능이 다양한 곳에 필요해요.
  • 이런 코드(공통 관심사)를 각각의 서비스나 컨트롤러마다 일일이 넣으면
    • 코드가 중복되고
    • 가독성이 크게 떨어지며
    • 수정/업그레이드 시 모든 곳을 찾아서 수정해야 해서 유지보수가 매우 어려워져요.

■ "횡단 관심사(cross-cutting concern)"의 효율적 처리

  • 로깅, 트랜잭션, 보안 등은 여러 코드에 걸쳐서(cross-cut) 적용돼야 하므로
    → 이것을 “횡단 관심사”라고 한다.
  • AOP는 이런 횡단 관심사를 한곳에 분리해서
    • 핵심 비즈니스 로직과 완전히 분리하고
    • 필요한 경우에만 자동으로 적용할 수 있게 해준다.

■ 핵심 로직의 순수성, 재사용성, 유지보수성 향상

  • AOP로 부가기능을 따로 관리하면,
    비즈니스 로직 코드가 심플해져서
    • 개발/테스트가 쉽고
    • 재사용성과 유지보수성이 높아진다.

2. Spring AOP를 활용한 실제 애플리케이션 개발 사례

예시 1. 서비스 메서드에 모든 요청·응답 시간 로깅

  • 모든 서비스 메서드가 동작할 때마다,
    “요청이 언제 들어오고, 결과가 언제 반환되는지(실행 시간, 파라미터, 결과)” 로깅을 남기고 싶다고 가정한다면,
  • 비즈니스 로직 함수마다 System.out.println()을 넣으면 중복 + 유지보수 불편...
  • AOP를 사용하면,
    • 로깅 기능을 한 곳(Aspect)에서 정의하고,
    • 어노테이션, 패키지, 클래스 네이밍 등으로 대상을 설정해서
    • 모든 서비스 메서드 실행 시 자동으로 로그 출력!
@Aspect 
@Component 
public class LogAspect {     

@Around("execution(* com.myapp.service..*(..))")     
public Object logExecutionTime(ProceedingJoinPoint joinPoint) 
throws Throwable {         
	long start = System.currentTimeMillis();         
	Object result = joinPoint.proceed();         
	long end = System.currentTimeMillis();         
	System.out.println("실행시간: " + (end - start) + "ms");         
		return result;     
	} 
}

예시 2. 트랜잭션 관리

  • DB 작업 중 예외가 발생하면 롤백해야 해야한다.
  • 서비스 메서드마다 try-catch문, 트랜잭션 처리 코드를 일일이 넣으면 중복과 실수 위험이 크다.
  • Spring AOP 기반 트랜잭션 관리 (@Transactional):
    • 메서드에 @Transactional만 붙이면,
      스프링이 트랜잭션 시작/커밋/롤백을 자동으로 처리해준다.
    • 실제로 내부적으로는 AOP로 이 기능이 동작한다.

예시 3. 보안(권한 검사)

  • 컨트롤러/서비스 메서드가 호출될 때,
    사전에 사용자 권한 체크를 해야 해요.
  • AOP Aspect에서 권한 확인 로직을 만들고,
    정해진 규칙(어노테이션, 경로 등)에 따라 자동 권한 체크!

3. 요약

  • Spring에서 AOP가 필요한 이유:
    비즈니스 코드와 상관없는 공통 관심사(로깅, 트랜잭션, 보안 등)를 핵심 로직과 분리해서,
    코드 중복 줄이고, 유지보수·테스트·재사용성 모두 높이기 위해서이다.
  • 실제 적용 사례:
    • 모든 서비스 메서드 실행 시간 자동 로깅
    • 트랜잭션 자동 관리
    • 보안(권한 체크) 자동 적용
    • 예외 처리, 감사 로그 등

4. egovframe.go.kr - 전자정부프레임워크

1) eGovFrame의 AOP 설계와 적용 기본 개념
핵심 비즈니스 로직(주업무 코드)과 별개로, 트랜잭션, 로깅, 보안검증, 권한 관리 등 "공통 부가기능" 을 핵심 코드와 분리해서 모듈화 적용하는 기법을 사용했다.
2) eGovFrame에서의 AOP 목표
a. 비즈니스 로직과 부가 concern(관심사)분리
b. 공통코드의 중앙 집중화
c. 유지보수, 테스트 효율성 및 일관성 증대

활용되는 핵심 사례

  1. 트랜잭션 관리
    • 서비스 로직의 메소드 호출 전후에 트랜잭션을 자동으로 시작/커밋/롤백 처리
    • 적용전: 각 서비스 코드에 try-catch-finally로 트랜잭션 컨트롤
    • 적용후: 서비스 메서드에 별도 어노테이션 설정만 하면 AOP가 알아서 트랜잭션 처리
  2. 로깅(logging)
    • 컨트롤러, 서비스, DAO 등 주요 계층의 진입, 종료시험, Exception 발생시 로그 남김
    • 반복/중복 되는 로그코드를 하나의 Aspect로 모아 관리
  3. 권한관리(인증/인가)
    • 로그인, 권한 검증, 세션 정보 검사 등
    • 특정 메서드 실행 전 after/before advice로 접근권한 체킹
  4. 공통 예외처리(Exception Handling)
    • 시스템 모든 영역에서 발생하는 예외를 일괄적으로 포착하여 "관리자에게 알림", "사용자 친화적 에러 메시지 전송" 등 처리 가능

핵심 구조와 예시

(1) Aspect 클래스를 두고 @Aspect, @Component 어노테이션 사용

@Aspect 
@Component 
public class LoggingAspect { 

	@Before("execution(* com.egov.sample..*(..))") 
	public void beforeMethod(JoinPoint joinPoint) { 
	// 메서드 시작 전 실행 
	System.out.println("진입: " + joinPoint.getSignature()); 
	} 
	
	@AfterReturning(pointcut="execution(* com.egov.sample..*(..))", 
			returning="result") 
	public void afterReturning(JoinPoint joinPoint, Object result) { 
	System.out.println("종료: " + joinPoint.getSignature() + " 반환값: " + result); 
		} 
	}

(2) 트랜잭션이나 Role, Exception Advice도 같은 방식으로 구현

  • XML 기반 config <aop:aspectj-autoproxy/>
  • 혹은 JavaConfig방식 @EnableAspectJAutoProxy
    (3) 핵심 인터페이스
  • Aspect: 공통 관심사 단위(Advice + Pointcut)
  • Advice: 실행시점(Before, After, AfterThrowing Around 등)
  • JointPoint: 실행될 대상 메서드/위치
  • Pointcut: Advice가 적용될 범위(메서드/클래스 패턴)

실제 전자정부프레임워크 적용예

  • egovframework.rte.fdl.aop 모듈에서 공통 AOP 지원
    - 대표적으로 EgovAbstractServiceImpl등 여러 Service에서 AOP가 자동 적용
    - 트랜잭션은 Service 계층 메서드에 자동 적용
    - 로깅은 Controller/Service 계층에 Aspect 구현을 붙여서 사용
  • XML 기반 Egov 설정 예시
<aop:aspectj-autoproxy /> 
<bean id="loggingAspect" class="egovframework.example.LoggingAspect"/> <aop:config> 
  <aop:aspect ref="loggingAspect"> 
	  <aop:pointcut id="allServiceOperation" expression="execution(* com.egov..service.*.*(..))"/> 
	  <aop:before pointcut-ref="allServiceOperation" method="beforeMethod"/>   
	</aop:aspect> 
  </aop:config>
  • 실제로 트랜잭션, 보안, 로깅, 공통 에러처리 모두 Aspect화해서 핵심 로직은 깔끔하게, 부가기능은 일괄관리 됨.

<참고:egovframework:rte:fdl:aop:egovrteaopguide [eGovFrame]>


  • 🇶 Spring MVC에서 클라이언트의 요청 처리 흐름을 @Controller와 @RestController의 차이점을 중심으로 각각의 처리 과정과 특징을 포함하여 설명하세오.

공통 처리 흐름

  1. 클라이언트가 HTTP 요청을 보냄 (예: 브라우저에서 /users/1 GET 요청)
  2. DispatcherServlet(스프링의 프론트 컨트롤러)이 요청을 받음
  3. 요청 URL, HTTP 메서드 등으로 어떤 Controller의 어떤 메서드를 실행할지 찾아서 호출
    → 이때, Controller 클래스는 @Controller 또는 @RestController 어노테이션이 붙음
  4. (여기서부터 두 어노테이션의 처리 방식이 달라짐!)
  5. 메서드 반환값 방식과 View 처리(시스템 응답 생성)에서 차이가 나타남

Q. Spring MVC에서 클라이언트의 요청 처리 흐름을 @Controller와 @RestController의 차이점을 중심으로 각각의 처리 과정과 특징을 포함하여 설명하세오.

1. @Controller의 처리 과정과 특징

  • HTML 뷰/템플릿을 반환할 때 주로 사용해요.
  • 컨트롤러 메서드의 반환값(예: "userList" 또는 ModelAndView)은 뷰 이름(템플릿 파일명)으로 해석된다.
  • 스프링이 해당 뷰(템플릿 엔진 파일: jsp, thymeleaf 등)를 찾아서 데이터(Model)와 합쳐 렌더링하고, 최종적으로 HTML로 변환해서 브라우저에 응답
  • REST API처럼 JSON을 내려주려면 반환 객체에 @ResponseBody를 추가해야 한다.

처리 흐름 예시 코드:

@Controller 
public class UserController {     

@GetMapping("/users")     
public String userList(Model model) {         
	List<User> users = userService.findAll();         
	model.addAttribute("users", users);         
	return "users/list"; // 뷰 이름 반환     
	} 
}
  • 위 코드에서 /users 요청 → "users/list.html" 등의 템플릿이 렌더링되어 HTML로 응답된다.

특징

  • 주로 SSR(Server Side Rendering) 웹사이트에서 사용
  • 기본적으로 반환값은 "뷰 이름"(템플릿 경로)로 해석된다.
  • API 응답 본문을 내려주려면 반드시 @ResponseBody 또는 메서드 단위에 @ResponseBody를 붙여야 한다.

2. @RestController의 처리 과정과 특징

  • REST API 서버 제작에 특화
  • @Controller + @ResponseBody가 결합된 특수 어노테이션임
  • 모든 메서드의 반환 객체가 "그대로" HTTP 응답 본문(주로 JSON)으로 직렬화해서 내려감

처리 흐름 예시 코드:

@RestController 
public class UserRestController {     

@GetMapping("/api/users")     
public List<User> list() {         
return userService.findAll();     
	} 
}
  • 위 코드에서 /api/users 요청 → List<User>가 자동으로 JSON으로 변환되어 응답 바디에 담김(뷰 템플릿 없음)

특징

  • 주로 SPA, 모바일 앱의 백엔드 등 클라이언트-서버 데이터 통신 API에서 사용
  • 반환값은 객체(데이터) → 자동 직렬화(Jackson 등 이용하여 JSON, XML 등)
  • 응답 본문에 바로 데이터만 담김(뷰X, 템플릿 렌더링X)

3. 주요 차이점 요약

항목@Controller@RestController
반환값 의미뷰 이름(템플릿 경로)응답 데이터(객체 자체)
활용 목적웹페이지 렌더링REST API, JSON 등 데이터 응답
@ResponseBody메서드별로 직접 붙여줘야 함자동 적용됨(모든 메서드에 포함됨)
반환 예"users/list" (뷰명)User, List 등 객체(→JSON)

결론

  • @Controller는 주로 웹페이지(HTML 뷰) 렌더링에,
  • @RestController는 주로 JSON 등 데이터 응답이 필요한 API 서버에 사용된다는 점이 핵심이다.
profile
Rookie

0개의 댓글