티스토리 뷰

spring

day2 class01 스프링AOP

일상다반ㅅㅏ 2018. 12. 26. 21:23

비즈니스 컴포넌트 개발에서 가장 중요한 두 가지 원칙

- 낮은 결합도 유지

- 높은 응집도 유지


의존성 주입(Dependency Injection)을 이용하면 비즈니스 컴포넌트를 구성하는 객체들의 결합도를 떨어뜨릴 수 있어 의존관계를 쉽게 변경할 수 있다.


스프링의 IoC가 결합도와 관련된 기능이라면, 

AOP(Aspect Oriented Programming)는 응집도와 관련된 기능이다.


횡단 관심(Crosscutting Concerns)

- 비즈니스 로직은 아니지만 로깅, 예외, 트랜잭션 처리 같이 메소드마다 공통으로 등장하는 코드

- 공통으로 관리가 되지 않을 시 비즈니스 메소드의 복잡도가 증가하고 유지보수가 어려워 진다.


핵심 관심(Core Concerns) 

- 사용자의 요청에 따라 실제로 수행되는 핵심 비즈니스 로직


그러나

OOP(Object-Oriented Programming) 언에에서는 횡단 관심에 해당하는 공통 코드를 완벽하게 독립적인 모듈로 분리해내기 어렵다.

스프링의 AOP는 이런 OOP의 한계를 해결할 수 있도록 할 수 있다.



1. AOP 적용 전

- 생성자를 이용해 공통 기능을 사용 할 수 있다.

- 하지만 BoardServiceImpl 클래스와 LogAdvice 객체가 소스에서 강하게 결합되어 있다.

- LogAdvice 클래스를 다른 클래스로 변경하거나 printLog메소드의 시그니처가 변경될 경우 유연한 대처를 할 수 없다.

1
2
3
4
5
6
7
8
9
10
// LogAdvice.java
 
package com.springbook.biz.common;
 
public class LogAdvice {
 
    public void printLog() {
        System.out.println("[공통 로그] 비즈니스 로직 수행 전 동작");
    }
}
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// LogAdvice.java
 
import com.springbook.biz.common.LogAdvice;
 
@Service("boardService")
public class BoardServiceImpl implements BoardService {
 
    @Autowired
    private BoardDAO boardDAO;
    private LogAdvice log;
    
    public BoardServiceImpl() {
        log = new LogAdvice();
    }
    
    public void insertBoard(BoardVO vo) {
        log.printLog();
        boardDAO.insertBoard(vo);
    }
    
    public void updateBoard(BoardVO vo) {
        log.printLog();
        boardDAO.updateBoard(vo);
    }
    
    public void deleteBoard(BoardVO vo) {
        log.printLog();
        boardDAO.deleteBoard(vo);
    }
    
    public BoardVO getBoard(BoardVO vo) {
        log.printLog();
        return boardDAO.getBoard(vo);
    }
    
    public List<BoardVO> getBoardList(BoardVO vo) {
        log.printLog();
        return boardDAO.getBoardList(vo);
    }
}
cs



2. AOP 적용

- AOP를 적용하면 BoardServiceImpl 소스와 무관하게 LogAdvice 같은 공통 클래스를 사용 할 수 있으므로 BoardServiceImpl 클래스의 공통 코드를 제거한다.


2.1 AOP 라이브러리 추가

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!-- pom.xml -->
 
<dependencies>
    <!-- 생략 -->
 
    <!-- AspectJ -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>${org.aspectj-version}</version>
    </dependency>    
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.8.8</version>
    </dependency>
 
    <!-- 생략 -->
</dependencies>
cs

2.2 네임스페이스 추가 및 AOP 설정
- 네임스페이스 탭에서 aop를 선택한다.
- 공통 코드의 클래스나 메소드가 변경되었을 경우에는 pointcut-ref나 method를 변경해주면 된다.
- expression 속성에서 정규식처럼 값에 해당하는 클래스를 찾아서 공통코드를 적용해주는 방식인 것 같다. 자세한건 다음 장에서 다루는 것 같다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!-- applicationContext.xml -->
 
<?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:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    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/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
 
    <context:component-scan base-package="com.springbook.biz"></context:component-scan>
    
    <bean id="log" class="com.springbook.biz.common.LogAdvice"></bean>
    
    <aop:config>
        <aop:pointcut id="allPointcut" expression="execution(* com.springbook.biz..*Impl.*(..))"/>
        
        <aop:aspect ref="log">
            <aop:before pointcut-ref="allPointcut" method="printLog"/>
        </aop:aspect>
    </aop:config>
</beans>
cs