본 게시글은 하단 책을 읽고 학습한 내용을 제 생각으로 요약, 정리한 글입니다.
목차
1. IoC/DI - 제어의 역전/의존성 주입1) 프로그래밍에서 의존성이란?2) 의존성을 직접 해결3) 스프링 없이 의존성 주입 1 - 생성자를 통한 의존성 주입 (생성자의 인자 주입으로 의존성을 해결)4) 스프링 없이 의존성 주입 2 - 속성을 통한 의존성 주입5) 스프링을 통한 의존성 주입 - XML 파일 사용6) 스프링을 통한 의존성 주입 - 스프링 설정 파일(XML)에서 속성 주입7) 스프링을 통한 의존성 주입 - @Autowired를 통한 속성 주입2. AOP - Aspect? 관점? 핵심 관심사? 횡단 관심사?1) 스프링에서 AOP란?2) AOP가 필요한 상황3) AOP 적용
1. IoC/DI - 제어의 역전/의존성 주입
1) 프로그래밍에서 의존성이란?
- 의사 코드로 살펴보는 의존성
- 의존성 → 자동차(전체)가 타이어(부분)에 의존함
운전자가 자동차를 생산한다.
자동차는 내부적으로 타이어를 생산한다.
- 의존성: A클래스가 B클래스의 객체를 생성해 사용하는 것.
- A와 B는 의존 관계에 있다.
- A는 B에 의존한다.
- 의존성: 다른 객체를 참조하는 것 ⇒ 객체 참조 변수
2) 의존성을 직접 해결
- 의존성 직접 해결 → 자동차 내부에서 타이어를 직접 생산
- 의사 코드
운전자가 자동차를 생산해 사용한다.
자동차가 내부적으로 타이어를 생산해 사용한다.
- 실제 코드 요약
- Driver 클래스
- Car 클래스
- 실제 코드
Tire.java
KoreaTire.java
AmericaTire.java
Car.java → Tire를 생산하고 사용함: Car는 Tire에 의존함
Driver.java → Car를 생산하고 사용함: Driver는 Car에 의존함
CarTest.java → Driver.java와 같은 역할
- 문제점 & 해결책
- 문제점
- 특정 자동차가 생산될 때
“어떤 타이어를 생산해서 장착할까”를 자동차 스스로가 결정함. - 운전자는
“어떤 자동차를 생산할지”만 결정 할 수 있고, 선택한 자동차에“어떤 타이어를 장착할지”는 결정할 수 없음(유연성 ↓) - 해결책
“어떤 타이어 장착할지”는 자동차가 아니라 운전자가 결정해야 함.- 운전자가 타이어를 생산함. 자동차는 운전자가 생산한 타이어를 건네받아 장착만 함.
- 즉, 의존성을 내부에서 직접 해결하는 게 아니라, 외부에서 주입 받아 해결해야 함.
3) 스프링 없이 의존성 주입 1 - 생성자를 통한 의존성 주입 (생성자의 인자 주입으로 의존성을 해결)
- 의존성 주입 → 자동차 외부에서 생산된 타이어를 자동차에 장착
- 생성자를 통한 의존성 주입 → 생성자의 인자를 통해 타이어 건네 받음.
- 주입의 장점
- Car는 KoreaTire, AmericaTire…등 몰라도 됨. Car는 Tire만 알면 됨.
- 따라서 새로운 타이어 브랜드(ChinaTire…) 얼마든지 생겨도, Car는 알 필요도 없기에 코드를 변경할 필요 없음.(확장성 ↑)
- 의사 코드
- 자동차는 외부(운전자)에서 생산한 타이어를 장착해 사용한다.
- 단, 타이어 장착은 자동차를 생산하는 순간에만 이뤄질 수 있다. 추후 타이어 교체 불가.
운전자가 타이어를 생산한다.
운전자가 자동차를 생산하면서 타이어를 장착한다.
- 실제 코드 요약
- Driver 클래스
- 실제 코드
Car.java → Tire를 주입 받아 사용함.
Driver.java → Tire를 생산함. Car를 생산하면서 생산해둔 Tire를 주입시킴. Car를 사용함.
- 문제점 & 해결책
- 문제점
- 자동차를 생산할 때 한 번 타이어를 장착하면 더 이상 타이어를 교체할 방법이 없음
- 해결책
- 운전자가 원할 때 자동차의 타이어 교체할 수 있어야 함.
- 생성자가 아닌 속성을 통한 의존성 주입으로 해결해야 함.
- 이를 통해 자동차 생산과 타이어 장착을 한 번에 하지 않고 따로 따로 할 수 있게 분리함.
4) 스프링 없이 의존성 주입 2 - 속성을 통한 의존성 주입
- 속성을 통한 의존성 주입 → 속성 접근자 메서드의 인자를 통해 타이어 건네 받음.
- 의사 코드
운전자가 타이어를 생산한다.
운전자가 자동차를 생산한다.
운전자가 자동차에 타이어를 장착한다.
- 실제 코드 요약
- Driver 클래스
- 실제 코드
Car.java → Tire를 주입 받아 사용함.
Driver.java → Tire를 생산함. Car를 생산함. Car에 생산해둔 Tire를 주입시킴. Car를 사용함.
- 문제점 & 해결책
- 문제점
- 타이어 종류 바꾸려면 운전자 코드가 바뀌어야 함.
- 해결책
- 종합쇼핑몰 같은 곳에서 타이어를 구매해오는 형태라면 타이어 바꿀 때 종합쇼핑몰에서 구매하는 타이어의 종류만 바꾸면 되므로 종합쇼핑몰의 코드만 바뀌면 됨.
5) 스프링을 통한 의존성 주입 - XML 파일 사용
- XML 파일 사용한 의존성 주입 → 종합 쇼핑몰(스프링 프레임워크)에서 생산된 타이어를 구매해 자동차에 장착
- 의사 코드
운전자가 종합 쇼핑몰에서 타이어를 구매한다.
운전자가 종합 쇼핑몰에서 자동차를 구매한다.
운전자가 자동차에 타이어를 장착한다.
- 실제 코드 요약
- Driver 클래스
- 실제 코드
Car.java → Tire를 주입 받아 사용함. - 변동 없음
Driver.java → 쇼핑몰에서 Tire와 Car를 구매함. Car에 Tire를 주입시킴. Car를 사용함.
expert002.xml → Tire와 Car 상품을 쇼핑몰에 등록함
- 문제점 & 해결책
- 문제점
- 운전자는 쇼핑몰에서 car와 tire를 사와서 car에 tire를 장착하는데,
- 쇼핑몰에서 파는 tire는 한 종류(KoreaTire)밖에 없음.
- 해결책
- 쇼핑몰에서 tire를 장착한 car를 팔면 됨. 쇼핑몰 내엔 여러 tire 있으니 americaTire, koreaTire 등 여러 종류 타이어 장착 가능.
6) 스프링을 통한 의존성 주입 - 스프링 설정 파일(XML)에서 속성 주입
- XML 파일에서 속성 주입 → 종합 쇼핑몰에서 타이어가 장착되어 판매되는 차를 구매해 사용
- 의사 코드
운전자가 종합 쇼핑몰에서 자동차를 구매 요청한다.
종합 쇼핑몰은 자동차를 생산한다.
종합 쇼핑몰은 타이어를 생산한다.
종합 쇼핑몰은 자동차에 타이어를 장착한다.
종합 쇼핑몰은 운전자에게 자동차를 전달한다.
- 실제 코드 요약
- Driver 클래스
- XML
- 실제 코드
Car.java → Tire를 주입 받아 사용함. - 변동 없음
Driver.java → 쇼핑몰에서 Car를 구매함. Car를 사용함.
expert002.xml → Tire와 Car 상품을 쇼핑몰에 등록함. Car에 Tire를 주입시킴
7) 스프링을 통한 의존성 주입 - @Autowired를 통한 속성 주입
- @Autowired를 통한 속성 주입 →
- 의사 코드 (이전과 동일)
운전자가 종합 쇼핑몰에서 자동차를 구매 요청한다.
종합 쇼핑몰은 자동차를 생산한다.
종합 쇼핑몰은 타이어를 생산한다.
종합 쇼핑몰은 자동차에 타이어를 장착한다.
종합 쇼핑몰은 운전자에게 자동차를 전달한다.
2. AOP - Aspect? 관점? 핵심 관심사? 횡단 관심사?
1) 스프링에서 AOP란?
- 정의)
- 공통 관심 사항(cross-cutting concern)과 핵심 관심 사항(core concern) 분리한 후, 분리한 공통 관심 사항을 원하는 곳에 적용
- 자바의 AOP 구현체: AspectJ, 스프링 AOP
- 관점 지향 프로그래밍(Aspect-oriented Programming)
- 어떤 로직을 기준으로 관점으로 나누어 보고, 그 관점을 기준으로 각각 모듈화하는 프로그래밍 기법
- 여러 클래스, 메서드에 걸쳐서 나타나는 비슷한 코드들(노랑, 파랑, 빨강)이 각 관점의 관심사임
- 관심사(노랑, 파랑, 빨강 코드)를 관점(X, Y, Z) 별로 모듈화함
- 후에 이를 핵심적인 비즈니스 로직에서 재사용함
ex) 그림 - 공통 관심사를 모듈로 분리한 후, 후에 원하는 곳에 공통관심사를 적용함

- 용어)
- Concern
- 관심사
- 코드 = 공통 관심사(횡단 관심사) + 핵심 관심사
- Aspect
- 관점
- 흩어진 공통 관심사를 묶어서 모듈화한 하나의 모듈
- Aspect = Point Cut들 + Advice들
- Target
- Aspect가 가지고 있는 Advice가 적용되는 대상(클래스, 메서드)
- Point Cut
- Aspect 적용 위치 지정자
- 스프링 → 공통 관심사를 적용할 타깃 클래스의 타깃 메서드 지정자
- Join Point
- Aspect 적용이 가능한(Point cut의 후보가 되는) 모든 지점
- Join Point Point cut
- Advice
- 조언, 충고
- Pointcut에 언제, 무엇을 적용할지 정의한 메서드
- 장점)
- 핵심 관심사항과 공통 관심 사항을 분리함
- 핵심 관심 사항을 깔끔하게 유지할 수 있음.
- 원하는 적용 대상을 선택할 수 있음
- 변경이 필요하면 공통 로직 하나만 변경하면 됨
- 단일 책임 원칙 적용
2) AOP가 필요한 상황
- 예시
- 상황) 모든 메서드의 호출 시간을 측정하고 싶음
- 문제)
- 회원 가입, 회원 조회에 시간을 측정하는 기능은 핵심 관심 사항이 아님
- 시간을 측정하는 로직은 공통 관심 사항임.
- 시간을 측정하는 로직과 핵심 비즈니스 로직이 섞여 있어 유지 보수가 어려움
- 시간을 측정하는 로직을 별도의 공통 로직으로 만들기 매우 어려움
- 시간을 측정하는 로직을 변경할 때 모든 로직을 찾아가면서 변경해야 함
- 해결) AOP(Aspect Oriented Programming) 사용
- 공통 관심 사항(cross-cutting concern) vs 핵심 관심 사항(core concern) 분리
코드) 각 메서드에 시간 측정 코드 넣음
3) AOP 적용
- AOP 패키지 만들기
hello.hellospring.aop
- TimeTraceAop 클래스 만들기
TimeTraceAop.java
- @Aspect 붙이기
- 에러) @Aspect 임포트가 안됨
- 해결)
- aop 의존성 추가하기 위해 build gradle에
implementation 'org.springframework.boot:spring-boot-starter-aop'추가 - 추가하고 build.gradle을 수정한 후 reload버튼을 클릭
reload 버튼 위치
build.gradle 수정 후 좌측에 Gradle 창 열면 코드 좌측 상단에 자동으로 함께 뜸

- 코드 작성
main/java/hello.hellospring.aop/TimeTraceAop.java
- 스프링 빈으로 등록하기
1) @Component 붙여서 컴포넌트 스캔
main/java/hello.hellospring.aop/TimeTraceAop.java
2) 스프링 빈에 등록해서 쓰기
main/java/hello.hellospring/SpringConfig
- 공통 관심사를 어디에 적용할지 타겟팅 @Around
- 적용 대상 변경
- ex) service에만 적용
main/java/hello.hellospring.aop/TimeTraceAop.java
@Around("execution(* hello.hellospring.service..*(..))")- 기존에 적어둔 시간 측정 코드 주석 처리하고 원래대로 되돌리기
main/java/hello.hellospring.service/MemberService.jav
- 회원 목록 들어가서 시간 측정 결과 확인
