본문 바로가기
IT/Spring

Java Framework - Spring (2) : DI / AOP

by uzzing' 2022. 5. 18.

의존성(Dependency) 주입

Dependency Lookup

스프링 컨테이너가 생성한 객체를 컨데이너 외부에서 검색(Lookup)하는 과정

 

Dependency Injection

- 객체 사이의 의존관계를 스프링 설정 파일에 등록된 정보로 컨테이너가 자동 처리

- 의존관계를 변경하고 싶을 때 자바 코드를 수정하지 않고 메타 데이터만 수정하여 유지보수에 좋음

  • Constructor Injection : <bean> 엘리먼트 사이에 <constructor-arg> 사용
  • Setter Injection : 클래스에 setter() 메소드 생성, <bean> 엘리먼트 사이에 <property> 사용
  • Type Injection : @Autowired 사용

Annotation 과 bean 사용

- 유지보수 과정에서 바뀌지 않는 코드라면 주로 annotation 사용하며, 바뀌는 경우가 있다면 bean 으로 등록한다. → 자바소스 건들이지 않고 xml 만 수정하여 적용 가능하기 때문에

- <bean> 등록이 싫으면 class 위에 @Component 작성 → Annotation 을 통해 컨테이너가 객체를 생성함.

 

의존성 주입 관련 어노테이션

  • @Autowired (Type Injection) : 변수 위에 설정하여 해당 타입의 객체를 메모리에서 찾아 자동할당 (Spring)
  • @Qualifier : 특정 이름의 객체를 주입할 때 사용 (거의 사용 x)
  • @Resource (Type Injection) : 위 두개를 결합한 어노테이션 (전자정부표준 프레임워크에서 사용)

 

IoC를 이용한 비즈니스 컴포넌트 개발

  1. VO (Value Object) 클래스 작성
    • 멤버변수 선언
    • getter, setter 생성
  2. DAO (Data Access Object) 클래스 작성
    • Extract Interface 생성 → Service 인터페이스 생성 및 implement 삭제
    • @Repository 추가 (bean 생성이 귀찮다면)
  3. Service 인터페이스 작성
  4. Service 구현 클래스 작성
    • ServiceImpl 구현
    • userDAO 사용
    • @Service 추가 (bean 생성이 귀찮다면)
    • @Autowired 추가 (userDAO가 Repository 참조할 수 있도록)

@Component 어노테이션 구분

  • @Service : 비즈니스 로직을 처리하는 Service 객체 (XXXServiceImpl 에 사용)
  • @Repository : 데이터베이스 연동을 처리하는 DAO 객체 (XXXDAO)
  • @Controller : 사용자 요청을 제어하는 Controller 객체 (XXXController)

 

AOP(Aspect Oriented Programming)

AOP 개념

AOP 이해에 가장 중요한 핵심 개념이 바로 관심분리(Seperation of Concerns) 이다.

  • 핵심관심 (Core Concerns) : 실제로 수행되는 핵심 비즈니스 로직
  • 횡단관심 (Crosscutting Concerns) : 비즈니스 메소드마다 공통으로 등장하는 코드들(로깅, 예외 등)

관심분리의 중요성으로 메소드를 구현할 때 횡단관심의 공통코드만 제거하면, 소스코드가 줄어들며 정책을 바꾸기가 쉽다. 분리된 관심을 적절하게 연결해주는 것이 AOP 의 역할이다.

 

AOP 설정

<aop:config> -- 루트

    <aop:pointcut />

    <aop:aspect />

</aop:config>    

 

AOP 용어

총 5가지 중 2가지만 이해하면 된다 - Pointcut, Advice

  1. 조인포인트 : ServiceImpl 에 있는 모든 메소드
  2. 포인트컷
    • 필터링된 조인포인트 / 필터링된 비즈니스 메소드
    • 횡단관심이 내가 원하는 메소드에서만 동작할 수 있도록 하는 것
    • 포인트컷 표현식
      • 리턴타입 + 패키지경로 + 클래스명 + 메소드명 및 매개변수
      • ex) * com.test..*Impl.*(..) / * com.test..board.*Impl.get*(..)
      • 리턴타입 
        • * : 모든 반환형 허용
        • void : 반환형이 void 인 메소드 선택
        • !void : 반환형이 void 가 아닌 메소드 선택
      • 패키지 경로
        • com.test.. : com.test 패키지로 시작하는 모든 패키지 선택
        • com.test..board : com.test 패키지로 시작하면서 마지막이 패키지 명이 board 패키지 선택
      • 클래스명
        • *Impl : 클래스 이름이 Impl로 끝나는 모든 클래스 선택
      • 메소드명 및 매개변수
        • get* : 메소드 이름이 get으로 시작하는 모든 메소드 선택
        • (..) : 매개변수의 개수와 타입에 제약 없음
        • (*) : 반드시 1개의 매개변수를 가지는 메소드만 선택
  3. 어드바이스(Advice)
    • 횡단관심에 해당하는 공통 기능의 코드 자체를 의미
    • 코드 자체를 의미하나 메소드 형태로 작성하기 때문에 메소드를 의미하기도 한다.
    • 5가지 동작시점
      • before
      • after
      • after-returning : 비즈니스 메소드의 리턴값을 받아서 사후처리 가능
      • after-throwing : 예외가 발생하는 순간 동작 및 예외를 받음
      • around : 사전/사후 처리, 클라이언트의 메소드 호출을 가로챔
        • 리턴타입 : Object
        • 매개변수 : ProceedingJointPoint
        • 리턴타입과 매개변수가 위와 같이 정해져 있다. 
  4. 위빙(Weaving)
    • 핵심관심, 횡단관심을 적절히 삽입해주는 것
    • 적절하게 결합되기(Weaving) 을 위해서는 애스팩트와 어드바이저가 필요
  5. 애스팩스(Aspect) or 어드바이저(Advisor)
    • 포인트컷과 어드바이스 연결
    • 위빙이 동작하기 위해서는 반드시 애스팩트 설정이 반드시 필요
    • 애스팩트 = 포인트컷 + 어드바이스 결합
public class LogAdvice {
    public void printLog() {
        System.out.println("[로그] 비즈니스 로직 수행 전 동작");
    }
}
<bean id="log" class="com.test.common.LogAdvice"></bean>
<aop:config>
    <aop:pointcut id="allPointcut" expression="execution(* com.test..*Impl.*(..))"/>
    <aop:pointcut id="getPointcut" expression="execution(* com.test..*Impl.get*(..))"/>
    <aop:aspect reg="log">
        <aop:before pointcut-ref="getPointcut" method="pringLog"/>
    </aop:aspect>
</aop:config>

 

getPointcut 으로 필터링한 비즈니스 메소드가 호출될 때(1), log라는 어드바이스 객체(2)의 printLog 메소드가 실행되는데(3), 이때 printLog 메소드 동작 시점이 <aop:before>(4) 이다. 

 

Advice 매개변수

클라이언트가 호출한 비즈니스 메소드의 정보가 필요하다. 스프링에서 JoinPoint 인터페이스를 제공한다.

  • Signature getSignature() : 호출되는 메소드 시그니처(패키지 경로, 클래스 이름, 메소드 이름, 매개변서, 리턴타입) 정보를 포함하는 Signature 객체를 리턴
  • Object[] getArgs() : 클라이언트가 비즈니스 메소드를 호출할 때 전달한 인자의 목록을 Object 배열로 리턴

주의할 점)

1. before / after / after-returning / after-throwing 어드바이스에서는 JoinPoint 사용하며,

around 어드바이스에서만 ProceedingJoinPoing 를 매개변수로 사용해야한다. 

→ around 에서는 proceed 메소드가 필요하기 때문에

   ProceedingJoinPoint 는 JoinPoin 를 상속 받고, proceed 메소드만 추가했다고 보면된다.

 

2. JoinPoint 와 ProceedingJoinPoing 모두 반드시 첫번째 매개변수로 선언되어야한다.

 

 

 

반응형

댓글