스프링 AOP 로그인 체크
AOP(Aspect-Oriented Programming)는 관점 지향 프로그래밍이라고 번역된다.
관점이라는 용어는 개발자들 사이에서 관심사라고 통용되는데 관심사란 개발 시 필요한 고민이나 염두에 두어야 하는 일이라고 생각할 수 있습니다.
예를 들어
- 파라미터가 올바르게 들어왔을까?
- 이 작업을 하는 사용자가 적절한 권한을 가지고 있는 사용자인가?
- 작업에서 발생하는 모든 예외처리는 어떻게 처리해야 할까?
이 정도 고민들을 예로 들 수 있는데,
위와 같은 고민들은 핵심적인 로직은 아니지만, 코드를 온전하게 만들기 위해서는 위 로직이 필요합니다. 그래서 AOP 이전까지는 개발자가 반복적으로 위 고민 처리를 코드에 반영하게 되었는데, 이를 AOP가 개발자의 핵심 비즈니스 로직 컴파일, 실행 이전, 실행 후 결합시켜 처리할 수 있기 때문에, 개발자는 핵심 로직에만 집중하여 개발할 수 있고, 추가적인 예외 처리를 기존 코드의 수정 없이도 제어할 수 있기 때문에 어떤 관심사들과 로직을 결합할 건지 설정하는 것 만으로 개발을 편리하게 할 수 있습니다.
또한 스프링이 AOP를 지원하는 것이 스프링의 가장 중요한 특징 중에 하나로 말하게 된 이유도 별도의 복잡한 설정이나 제약 없이 간편하게 사용할 수 있기 때문에 스프링에서는 AOP가 정말 좋은 기능이다~라고 말할 수 있습니다.
AOP 용어
- target
- 타깃은 부가기능을 부여할 대상이다. 핵심기능을 담은 클래스일 수도 있지만 경우에 따라서는 다른 부가기능을 제공하는 프록시 오브젝트일 수도 있다.
- Advice
- 어드바이스는 타깃에게 제공할 부가기능을 담은 모듈이다. 어드바이스는 오브젝트로 정의하기도 하지만 메소드 레벨에서 정의할 수도 있다.
- Join Point
- 조인 포인트join point란 어드바이스가 적용될 수 있는 위치를 말한다. 스프링의 프록시 AOP에서 조인 포인트는 메서드의 실행 단계뿐이다. 타깃 오브젝트가 구현한 인터페이스의 모든 메서드는 조인 포인트가 된다.
- Poincut
- 포인트컷이란 어드바이스를 적용할 조인 포인트를 선별하는 작업 또는 그 기능을 정의한 모듈을 말한다. 스프링 AOP의 조인 포인트는 메서드의 실행이므로 스프링의 포인트 컷은 메서드를 선정하는 기능을 갖고 있다. 그래서 포인트 컷 표현식은 메서드의 실행이라는 의미인 execution으로 시작하고, 메서드의 시그니처를 비교하는 방법을 주로 이용한다.
- Proxy
- 프록시는 클라이언트와 타깃 사이에 투명하게 존재하면서 부가기능을 제공하는 오브젝트다. DI를 통해 타깃 대신 클라이언트에게 주입되며, 클라이언트의 메서드 호출을 대신 받아서 타깃에 위임해주면서, 그 과정에서 부가기능을 부여한다. 스프링은 프록시를 이용해 AOP를 지원한다.
- Advisor
- 어드바이저는 포인트컷과 어드바이스를 하나씩 갖고 있는 오브젝트다. 어드바이저는 어떤 부가기능(어드바이스)을 어디에(포인트 컷) 전달할 것인가를 알고 있는 AOP의 가장 기본이 되는 모듈이다. 스프링은 자동 프록시 생성기가 어드바이저를 AOP작업의 정보로 활용한다. 어드바이저는 스프링 AOP에서만 사용되는 특별한 용어이고, 일반적인 AOP에서는 사용되지 않는다.
- Aspect
- OOP의 클래스와 마찬가지로 애스펙트는 AOP의 기본 모듈이다. 한 개 또는 그 이상의 포인트컷과 어드바이스의 조합으로 만들어지며 보통 싱글톤 형태의 오브젝트로 존재한다. 따라서 클래스와 같은 모듈 정의와 오브젝트와 같은 실체의 구분이 특별히 없다. 두 가지 모두 애스펙트라고 불린다. 스프링의 어드바이저는 아주 단순한 애스펙트라고 볼 수도 있다
위 용어중에서 어드바이스에는 몇 가지 종류가 있는데 그것도 알아보자
Before | 메서드 실행전에 실행되는 실행 | ||||||
After | 메서드가 정상적으로 실행된 후에 실행 | ||||||
After throwing | 예외를 발생시킬때 적용되는 Advice를 정의 | ||||||
Around | 메서드 실행전,후,예외처리등 모든 시점에서 발생하는 Advice를 정의 |
이제 AOP 를 사용해 보자
먼저 pom.xml 에 의존 설정을 해준다.
pom.xml의 일부
<!-- AOP -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
그다음 라이브러리를 받았으면 context.xml 에 아래와 같이 설정해준다.
name space에 aop를 체크!
그 후 source에 코드 추가!!
<context:component-scan base-package="kr.coo.civ.aop"/>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
이제 설정은 간단하게 끝이 났다.
설정해준 packge경로에 파일을 만들자~
package kr.coo.civ.aop;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
..생략..
@Aspect
@Log4j
@Component
public class ServiceAdvice {
@Pointcut("execution(* kr.coo.civ.MemberController.get*(..)) || execution(* kr.coo.civ.MemberController.set*(..))")
public void memberPoint() {
}
@Pointcut("execution(* kr.coo.civ.MovieController.commentWrite(..))")
public void movieDetailPoint() {
}
@Pointcut("execution(* kr.coo.civ.MoviePaymentController.get*(..)) || execution(* kr.coo.civ.MoviePaymentController.set*(..))")
public void paymentPoint() {
}
@Around("memberPoint() || movieDetailPoint() || paymentPoint()")
public Object sessionCheck(ProceedingJoinPoint pjp) throws Throwable {
HttpSession session = null;
HttpServletRequest request = null;
Object result = null;
String type = pjp.getSignature().getDeclaringTypeName();
for (Object o : pjp.getArgs()) {
if (o instanceof HttpSession) {
session = (HttpSession) o;
} else if (o instanceof HttpServletRequest) {
request = (HttpServletRequest) o;
}
}
if (session.getAttribute("loginInfo") == null) {
session.setAttribute("redirectUrl", request.getServletPath());
return "redirect:/auth/login";
} else {
if (session.getAttribute("redirectUrl") != null) {
session.removeAttribute("redirectUrl");
}
result = pjp.proceed();
}
log.info(result);
return result;
}
}
AOP를 사용해서 로그인체크를 해주었다.
원래 보통의 경우에는 Controller 에는 AOP를 잘 사용하지 않는다고 들었다.
이번 경우는 프로젝트 설계를 aop를 한정하지 않고 계획하다 Controller에 추가하게 되었지만, Controller에 사용할 거면 Intercepter를 사용하라고 하더라
자바 웹개발에서 AOP와 같이 공통적으로 처리해야 할 업무에 사용할 것들이 3가지 있는데 그건 바로
AOP, Intercepter, Filter 이렇게 3가지가 있다.
3가지의 차이점은 그림으로 보여주겠다.
그림으로 보이듯 먼저 필터는 제일 바깥(스프링 컨텍스트 외부)에 위치하여 이름에서 알 수 있듯, 요청과 응답을 거른 뒤 정제하는 역할을 한다. 보통 web.xml에 등록하고, 일반적으로 인코딩 변환 등에 쓰인다.
그리고 Intercepter 인터셉터는 스타크래프트 캐리어에서 나오는 파리밖에 생각이 안났지만, 스프링의 서블릿이 컨트롤러를 호출하기 전 , 후에 컨트롤러에 대한 요청과 응답에 대해 처리하는 역할을 한다. 스프링의 모든 빈객체에 접근할 수 있는 특징이 있고, 여러 개를 사용할 수 있어서 로그인 체크, 권한 체크 등등에 쓰인다.
마지막으로 이번 글의 주인공 AOP 는 위에서 설명했으니 간단하게 말하자면 객체지향의 프로그래밍에서 중복을 줄일 수 없는 코드의 중복을 줄이기 위해 관점에서 바라보고 처리하는 이 AOP는 인터셉터와 필터보다 좀 더 세밀하게 조정하고 싶을 때 로깅, 트랙젝션, 에러 처리 등에서 쓰인다.
AOP 어렵지만 굉장히 쓰임새있어서 실무에서도 거의 필수적으로 쓰일 거 같다.
더 공부해서 잘 쓸 수 있게 해 보자~~