(Aspect Oriented Programming)
: 로깅, 보안 같은 공통 기능을 분리하여 관리할 수 있도록 만든 프로그래밍 패러다임
→ model과 controller의 감시자
: 부가 기능 코드를 핵심 비즈니스 로직의 코드와 분리하여,
코드의 간결성을 높이고 변경에 유연하고 확장이 가능하도록 하는 것
Aspect
: 흩어진 관심사(공통 기능)를 모듈화한 것
Target
: Aspect를 적용하는 곳, 대상 객체 (Advised Object)
→ model과 controller 클래스, 메서드 등
Advice
: Aspect의 동작을 적은 것 (동작 코드)
Join Point
: AOP가 실행되는 시점 (Advice가 적용되는 시점)
⇒ logging, 로그인 여부 확인 기능을 구현해보자.
<!-- spring Aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.3.25</version>
</dependency>
<!-- 런타임에 동적으로 자바 클래스의 프록시(대리인)를 생성해주는 기능을 제공 -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
<!-- aspectj -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.4</version>
</dependency>
@Aspect
사용 설정AopProc
클래스의 객체로 myAop
를 생성<?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:aop="http://www.springframework.org/schema/aop"
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.3.xsd">
<!-- aspect annotation 사용 설정 -->
<aop:aspectj-autoproxy/>
<!-- aop 객체 생성 -->
<bean id="myAop" class="com.mypack.sample.aop.AopProc"/>
</beans>
: <param-value>
태그 내에 위의 설정파일 등록
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/servlet-context.xml
/WEB-INF/spring/aop-context.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
@Aspect
어노테이션을 사용하여 Aspect 클래스 선언
Advice 작성을 위한 어노테이션 @Around
로 메소드 실행 시점을 기준으로 로직 구현
→ 파라미터 ProceedingJoinPoint
로 타겟 메소드 실행 제어 가능
⇒ 로그인 여부 확인 기능과 로깅 기능의 로직 구현
package com.mypack.sample.aop;
import java.util.Date;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class AopProc {
// 해당 클라이언트 호출 가로채기
@Around("within(com.mypack.sample.controller.*) or within(com.mypack.sample.dao.*.*)")
public Object loggerAop(ProceedingJoinPoint joinpoint) throws Throwable {
// session check
HttpServletRequest req = ((ServletRequestAttributes)RequestContextHolder
.currentRequestAttributes()).getRequest();
if(req != null) {
// 세션에 저장돼있는 로그인 객체 얻기
HttpSession session = req.getSession();
MemberDto login = session.getAttribute("login");
id(login == null) { // 로그인 객체가 없으면 컨트롤러로 이동
return "redirect:/sessionOut.do";
}
}
// logger
// 가로챈 메소드에 대한 정보
String signatureStr = joinpoint.getSignature().toShortString();
try {
// 비즈니스 메소드 실행 후의 결과값
Object obj = joinpoint.proceed();
// 로그 출력
System.out.println("AOP log: " + signatureStr + " 메소드 실행 " + new Date());
// 메소드 실행 결과값 반환
return obj;
} finally {
System.out.println("실행후: " + System.currentTimeMillis());
}
}
}
→ 서블릿에서 controller로 이동 시, sendRedirect()
를 사용하는 대신
"redirect:/login.do"
반환
: 로그아웃 메시지를 출력하는 message.jsp파일로 이동
@GetMapping(value = "sessionOut.do")
public String sessionOut(Model model) {
String sessionOut = "logout";
model.addAttribute("sessionOut", sessionOut);
return "message";
}