[스프링 프레임워크 첫걸음] ( 3 / 9 )

박북velog·2023년 3월 21일
0

제 3장. 스프링 프레임워크의 핵심기능 알아보기


3.1 DI 컨테이너 알아보기

3.1.1 의존성 주입

의존성 주입(Dependency Injection)은 '의존하는 부분을 외부에서 주입하는 것' 이다.

의존성 이란 ?

"사용하는 객체 A" 와 "사용되는 객체 B" 가 있다고 가정해보자.

A 클래스에서 B 클래스를 사용하려면 new 키워드를 이용하여 B 클래스의 인스턴스를 생성하고, B 클래스의 메서드를 사용한다. 이때, B 클래스에서 구현했던 메서드를 변경했을 때 A 클래스 역시 해당 메서드를 변경해야한다. 이런 관계에서 'A 클래스는 B 클래스에 의존한다.'

1 ) 클래스 의존 (구현 의존)

  • 사용하는 객체 클래스에서 사용되는 객체 클래스 타입을 직접 지정하면 사용되는 객체 클래스를 변경할 경우 이용하는 있는 곳 모두를 수정해야만 한다.

2 ) 인터페이스 의존

  • 인터페이스는 참조를 받는 유형으로 사용할 수 있으므로 변수의 이름을 변경하지 않아도 된다.
  • 인터페이스가 선언된 메서드를 이용하면 클래스가 바뀌어도 메서드명을 변경하지 않아도 된다.

📝DI 컨테이너의 다섯 가지 규칙

  1. 인터페이스를 이용하여 의존성을 만든다.
  2. 인스턴스를 명시적으로 생성하지 않는다.
    ( 인스턴스 생성에 new 키워드를 사용하지 않는다. )
  3. 어노테이션을 클래스에 부여한다.
  4. 스프링 프레임워크에서 인스턴스를 생성한다.
  5. 인스턴스를 이용하고 싶은 곳에 어노테이션을 부여한다. ( @Autowired )

3.2 어노테이션 역할 알아보기

3.2.1 어노테이션을 세가지 항목으로 설명

  • 어노테이션(annotation)은 주석을 의미하는 영어 표현이다.
  • '@xxx'와 같은 형태로 작성한다.
  • 외부 소프트웨에 필요한 처리 내용을 전달한다.

어노테이션을 사용하여 에러를 출력하거나 프로그램의 동작을 변경하는 등 다양한 액션이 가능하다.

소스 파일필요 처리 내용외부 소프트웨어
@Override오버라이드 메서드의 시그니처 체크자바 컴파일러
@Author도움말 문서 생성JavaDoc
@Component인스턴스 생성스프링 프레임워크
@NotEmpty입력란 체크Validator
@Test테스트 실행JUnit

3.2.2 레이어별로 사용할 인스턴스 생성 어노테이션

복잡한 전체 내용을 한번에 정리해 이해하기보다 계층화를 통해 각 계층별로 대상의 의미를 이해하는 것이 편리하다.

레이어개요
애플리케이션 레이어클라이언트와의 데이터 입출력을 제어하는 레이어 - @Controller
도메인 레이어애플리케이션의 중심이 되는 업무 처리를 수행하는 레이어 - @Service
인프라스트럭처 레이어데이터베이스에 대한 데이터 영속성 등을 담당하는 레이어 - @Repository

상위 3가지 용도 이외의 인스턴스 하위 로직을 처리하는 곳에는 @Component 어노테이션을 클래스에 부여한다.

3.3 관점 지향 프로그래밍 (AOP)

관점 지향 프로그래밍 (Aspect Oriented Programming)

  • 중심적 관심사 : 실현해야 할 기능을 나타내는 프로그램
  • 횡단적 관심사 : 본질적인 기능은 아니지만 품질이나 유지보수 등 관점에서 반드시 필요한 기능을 나타내는 프로그램
    (ex> 예외처리, 로그 정보 화면이나 파일 등으로 출력처리, 데이터베이스의 트랜잭션 제어, ... )

3.3.1 AOP 예제

데이터베이스 액세스 처리에는 예외 발생 시 처리하는 내용이 반드시 포함되어야한다.

스프링 프레임워크에서 제공하는 AOP 기능을 활용하여 '중심적 관심사' 와 '횡단적 관심사' 를 분리하여 프로그램 작성이 가능하다.

  • Advice = 횡단적 관심사의 구현(메서드). 로그 출력 및 트랜잭션 제어 등
  • Aspect = Advice를 정리한 클래스
  • JoinPoint = Advice를 중심적인 관심사에 적용, 메서드(생성자) 실행 전, 메서드 실행 후 등 실행되는 타이밍
  • Pointcut = Advice를 삽입할 수 있는 위치
  • Interceptor = 처리의 제어를 인터셉트하기 위한 구조 또는 프로그램
  • Target = Advice가 도입되는 대상

어드바이스내용어노테이션
Before Advice중심적 관심사가 실행되기 '이전' 횡단적 관심사를 실행@Before
After Returning Advice중심적 관심사가 '정상적으로 종료된 후' 횡단적 관심사를 실행@AfterReturning
After Throwing Advice중심적 관심사로부터 '예외가 던져진 후' 횡단적 관심사를 실행@AfterThrowing
After Advice중심적 관심사의 '실행 후' 횡단적 관심사를 실행 (정상 종료나 예외 종료 등 결과와 상관은 없다.)@After
Around Advice중앙적 관심사 호출 전후에 횡단적 관심사를 실행@Around

3.3.2 포인트컷 식

직접 어드바이스를 만드는 경우 패키지, 클래스, 메서드 등 어드바이스 삽입 대상을 조건으로 지정할 수 있다. 지정하는 조건 방법에는 포인트컷 식을 사용한다.

'execution' 지시자의 구문

  • execute(반환값 패키지.클래스.메서드(인수))

포인트컷 식은 와일드카드를 이용하여 유연하게 적용 범위 지정이 가능하다.

  • *(애스터리스크) : 임의의 문자열을 나타내고, 패키지를 나타낼 때는 임의의 패키지 한 계층을 나타낸다. 메서드의 인수에서는 한 개의 인수를 나타내 반환값으로도 이용할 수 있다.
  • ..(점 두개) : 패키지를 나타내는 경우 0개 이상의 패키지를 나타낸다. 메서드의 인수를 표현하는 경우 0개 이상의 임의의 인수를 나타낸다.
  • +(플러스) : 클래스명 뒤에 기술해 클래스와 그 서브 클래스 및 구현 클래스 모두를 나타낸다.

3.3.3 AOP프로그램 만들기

1. build.gradle 수정하기

AOP 를 사용하기 위해 build.gradle 에
implementation 'org.springframework.boot:spring-boot-starter-aop'
를 추가한다.

2. AOP 클래스 생성하기

어드바이스를 기술하는 클래스에 @Aspect 어노테이션과 인스턴스 생성을 위한 @Component 어노테이션을 부여한다.

3. Before Advice 작성

인수로 JoinPoint를 전달하고 메서드에 @Before 부여
어노테이션의 인수에 포인트컷 식인 execution(패키지.클래스.메서드(인수))

@Before("execution(* com.example.demo.chapter03.used.*Greet.*(..))")
public void beforeAdvice(JoinPoint joinPoint) {
	// 시작 부분 표시
    System.out.println("==== Before Advice ====");
    // 날짜 출력
    System.out.println(new SimpleDateFormat("yyyy/MM/dd").format(new java.util.Date()));
    // 메서드 이름 출력
    System.out.println(String.format("메서드:%s", joinPoint.getSignature().getName()));
    }

4. After Advice 작성

인수에 같이 JoinPoint를 전달하고 메서드에 @After를 부여
지정방법은 Before Advice와 유사하다.

@After("execution(* com.example.demo.chapter03.used.*Greet.*(..))")
public void beforeAdvice(JoinPoint joinPoint) {
	// 시작 부분 표시
    System.out.println("==== After Advice ====");
    // 날짜 출력
    System.out.println(new SimpleDateFormat("yyyy/MM/dd").format(new java.util.Date()));
    // 메서드 이름 출력
    System.out.println(String.format("메서드:%s", joinPoint.getSignature().getName()));
    }

5. Around Advice 작성

인수에 ProceedingJoinPoint 를 전달하고, 메서드에 @Around 를 부여한다.

@Around("execution(* com.example.demo.chapter03.used.*Greet.*(..))")
public Object beforeAdvice(ProceedingJoinPoint joinPoint) throws Throwalbe {
	// 시작 부분 표시
    System.out.println("==== Around Advice ====");
    System.out.println("----  처리 전  ----");
    // 지정한 클래스의 메서드 실행
    Object result = joinPoint.proceed();
    System.out.println("----  처리 후  ----");
    // 반환값을 돌려줄 필요가 있는 경우에는 Object 타입의 반환값을 돌려준다.
    return result;
    }

❓Around Advice 가 다른 어드바이스와 다른 점

  • 인수는 ProceedingJoinPoint 인터페이스 타입을 지정한다.
  • 어드바이스 중에서 ProceedingJoinPoint 인터페이스의 proceed() 메서드를 호출한다.
  • 어드바이스 적용 대상의 메서드를 임의의 타이밍으로 호출할 수 있으므로 전후로 다양한 처리가 가능하다.
  • 반환값을 돌려줄 필요가 있는 경우는 Object 타입으로 반환값을 돌려준다.

6. 트랜잭션 관리

트랜잭션 관리에는 @Transactional 어노테이션을 사용한다. 어노테이션을 부여하여 데이터베이스 액세스 처리 메서드가 정상 종료하면 트랜잭션을 커밋하고, 예외가 발생하면 롤백한다.

3.4 Spring Initializr 알아보기

Spring Initializr의 이점

스프링 부트에서 프로젝트를 시작할 때 통합 개발 환경(IDE)에 의존하지 않는 프로젝트를 만드는 방법은 Spring Initializr 에서 프로젝트를 만들고 사용 중인 통합 개발 환경에서 해당 프로젝트를 가져와서 사용한다.

https://start.spring.io/ 에 접속해서 설정 후 사용 가능하다.

profile
느리지만 끝까지 해보자구

0개의 댓글