[ 관전지향 프로그래밍 ] AOP (xml설정 )
[ 관점지향 프로그래밍 ]
Aspect Oriented Programming
핵심로직 ( 비즈니스 메서드, CRUD ) + 공통로직 (횡단관심 = conn, pstmt, close, close)
객체지향(OOP)일 경우 안좋은점
DAO를 예로
conn, pstmt, sql, rs, close, close
>> 객체가 수행하다보니 각각의 CRUD에 전부 넣어야하고 DAO마다 존재해야 했음
즉, 코드의 반복이 필수 ( JDBCUtil )
AOP의 목표 -> conn, pstmt, sql, rs, close, close중 횡단관심을 분리시키고
sql, rs 로직만 남기는 것이 목표
각각의 로직에 맞는 코드공간이 생기므로, 응집도가 높아짐 >> 유지보수 용이
AOP는 언제 쓰이는가?
핵심로직 (비즈니스 메서드, CRUD) 에는
공통적으로 들어가는 로직이 존재함
== 공통로직 (횡단관심)
ex) 로깅, 예외처리, 트랜잭션, 보안(인증,인가,허가),...
공통로직 (횡단관심)은 모든 CRUD에 적용되는 것이 아닌 일부에만 적용될 수 있다는 것
ex)
로그 = 모두
아이디체크 = insert & delete
본인인증 = delete
>> 로그, 아이디체크, 본인인증 메서드는 해당되는 로직에만 연결해야 함
이런 공통로직을
어떤 핵심로직에 연결할지 "설정"
>> AOP 설정
>> applicationContext.xml
기존의 방식으론 메서드명 변경했을 경우 코드 자체로 들어와 고쳐야함 ( 유지보수 안좋음 )
AOP설정을 하기위해 jar 파일이 필요한데 pom.xml에 코드를 넣어 생성 할 수 있다 **
( pom.xml 내부 )
pom.xml에 박스안의 코드를 넣고 새로고침하게되면
이클립스 오른쪽 구석에 설치바가 생기며, 모두 채워지게 됐을경우
Maven Dependencies에 설치가 되었는지 확인 할 수 있다
applicationContext.xml 의 Namespaces 에서 aop를 체크해준다
( xml에 aop관련 코드가 추가 됨 - 수기작성해도 가능 )
이후 AOP 설정을 하도록 하자
AOP 용어정리
Advice
공통로직 (횡단관심)
config 태그
AOP를 설정하겠다는 태그
config 태그 바디에 쓰는 태그
1) pointcut 태그
공통로직을 적용할 핵심 로직을 의미
속성
1) expression(표현식)에 어떤 핵심로직인지 알려주어야 함
execution(메서드 시그니처)
>> execution( [*] [com.kim.biz..*Impl.*] [(..)])
[ ] 각각의 의미
아웃풋 [ * ] = 와일드 카드를 사용했지만 타입을 쓰면 된다
AOP설정을 사용할 메소드 타겟 [ com.kim.biz [..] [*lmpl] . [*] ]
ㅡ [..] 패키지 안에있는 모든 폴더라는 뜻
ㅡ [ *Impl ] 위 패키지 안에있는 폴더중 클래스이름이 Impl 로 끝나는 클래스
ㅡ . [ * ] 위 클래스의 모든 메서드
인자 [ (..) ] == 모든 인자
주로 특별한 경우가 아니면 아웃풋 ( * ) 과 인자 ( .. ) 는 픽스임 / 안바뀜 / 보편적임
2) id 어떤 이름으로 부를지
ex)
aPointcut == 모든 핵심 로직
bPointcut == XX 핵심 로직
https://kgvovc.tistory.com/54 표현식공부에 도움될 블로그포스팅
[Spring Core] AOP(Aspect Oriented Programming) - 3편 (Pointcut, execution 지시자, within 지시자, named pointcut)
AOP - 3편 (Pointcut) [Pointcut 표현식] 지금까지 살펴본 코드에서는 Pointcut을 선택하기 위해 'execution(* *..* ServiceImpl.*(..))'과 같은 표현을 사용해 왔다. 이처럼 표현식을 이용한 JoinPoint 선택 기능..
kgvovc.tistory.com
2) aspect 태그
" 결합 "
공통로직(횡단관심) + 포인트컷(핵심로직)
aspect = 언제 메서드를 사용할지 선택가능
종류 | |
aop : after | 핵심로직 수행시 결과에 상관없이 결합 |
aop:after - returning | 핵심로직 수행시 리턴에 성공했을 때 결합 ( void X ) |
aop:after - throwing | 핵심로직 수행시 예외를 던진 후 결합 |
aop : around | 핵심로직 전과 후를 결합 |
aop : before | 핵심로직 수행 전에 결합 |
언제 사용해야하는지는 비즈니스메서드와 어울리는 어드바이스를 결합해서 사용하기 때문에
언제 사용하는것이 타당한지를 목적으로 두는 것 이 좋을 것 같다
속성
method 속성에는 ref에 설정할 객체중 사용할 메서드명을 설정
pointcut-ref="aPointcut" 어떤 포인트컷을 사용할지 설정
>> 타겟한 포인트컷의 메서드가 실행되면 aspect의 실행속성에 맞게 method 실행
aop:around 는 특별한 형식을 띈다
aop:around를 사용할 클래스 ( 공통로직 = Advice 클래스 )
( applicationContext.xml )
aop:around를 사용하기 위해선
사용하는 메소드인자에는 ProceedingJoinPoint 객체가 필수이다
인자의 객체인 pjp.proceed() 메소드에는 수행해야할 포인트컷(비즈니스 로직)을 수행한다
( pjp.proceed() 메서드는 try/catch가 필수지만 클래스에 throws Throwable 을 통해 미뤄둔 것 )
콘솔 결과
BEFORE 로그와 AFTER로그가 비즈니스로직 수행전과 수행후에 나타난것을 볼 수 있다
[ 추가 공부 ]
xml의 설정 순서에 따라 결과가 달라진다 **
1) around 설정이 위에있고 before설정이 아래에 있을 경우
around 설정이 먼저 실행되고
before 설정이 실행된다
2) before 설정이 위에 있고 around 설정이 아래에 있을경우
before 설정이 먼저 실행되고
around 설정이 실행된다
실행순서 이슈로 인해 오류가 발생할 수도 있다라는 생각을 했다
해결방법 & 크게 관련없는 이유
1) 만약 순서이슈로 인해 오류가 발생할만한 코드였다면
설계에서 부터 해당순서를 확실히 했을 것이다
2) 순서를 중요시하는 코드였다 == 코드를 따로따로 사용하지 않고 묶어 놨을 것이다
그래서 따로따로 메서드를 사용하는 일이 없어 순서 이슈에 걸리지 않았을 것이다
결과) 설계에서 순서를 확실히 or 순서를 중요시하는 코드였다면 한 메서드에서 한번에 이루어 지도록
AOP 설정 해석을 말로 풀어보기
aPointcut은 com.kim.biz 안의 폴더중 Impl라고 끝나는 클래스의 모든 메서드를 타겟한 pointcut
bPointcut은 com.kim.biz 안의 폴더중 Impl라고 끝나는 클래스의 중 select 라고 시작하는 메서드를 타겟한 pointcut
첫번째 aspect
사용할 메서드를 가진 logAdvice 클래스를 타겟 ( Advice = 공통로직 / 로그관련 공통로직 클래스를 의미)
aop:before로 aPointcut 관련 메소드가 실행했을경우 그 전에 메서드를 사용하겠다는 의미
사용할 메서드는 printLog / 타겟하는 포인트컷은 aPointcut
aPointcut 은 모든 메서드를 타겟 했기때문에 모든 메서드에 반응하여 printLog를 실행
두번째 aspect
사용할 메서드를 가진 logAdvice 클래스를 타겟
aop:before로 bPointcut 관련 메소드가 실행했을경우 그 전에 메서드를 사용하겠다는 의미
사용할 메서드는 selectLog / 타겟하는 포인트컷은 bPointcut
bPointcut 은 select* 라는 메서드를 타겟 했기때문에 select* 메서드에 반응하여 selectLog를 실행