#참고도서: '스프링 프레임워크 첫걸음' (키노시타 마사아키, 위키북스)

 

03장: 스프링 프레임워크의 핵심 기능 알아보기

 

1.  의존성 주입(DI)

- 의존하는 부분을 외부에서 주입하는 것

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

- '사용하는 객체' 클래스에서 '사용되는 객체' 클래스의 타입을 직접 지정해 버리면 '사용되는 객체' 클래스를 변경할 경우 이를 이용하고 있는 곳을 모두 수정해야 함

- 수정할 부분이 늘어나면 실수가 발행할 위험과 시간이 늘어남

2) 인터페이스 의존

- 참조를 받는 유형으로 사용할 수 있으므로 변수의 이름을 변경하지 않아도 됨

- 인터페이스가 선언된 메서드를 이용하면 클래스가 바뀌어도 메서드명을 변경하지 않아도 됨

- 클래스 의존보다 인터페이스 의존을사용하는 것으로 수정할 곳을 줄일 수 있음

 

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

1) 중심적 관심사(Primary Concern)

- 실현해야 할 기능을 나타내는 프로그램

2) 횡단적 관심사(Crosscutting-Concerns)

- 본질적인 기능은 아니지만 품질이나 유지보수 등의 관점에서 반드시 필요한 기능을 나타내는 프로그램

- 예외처리, 로그 정보 화면이나 파일 등으로 출력 처리, 데이터베이스의 트랜잭션 제어 등

 

3. DI 컨테이너 다섯 가지 규칙

1) 인터페이스를 이용하여 의존성을 만든다

- 의존하는 부분에 인터페이슬르 이용한다는 것

2) 인스턴스를 명시적으로 생성하지 않는다

- 인스턴스 생성에 new 키워드를 사용하지 않는다는 것

3) 어노테이션을 클래스에 부여한다 & 4) 스프링 프레임워크에서 인스턴스를 생성한다

- 인스턴스를 생성하려는 클래스에 인스턴스 생성 어노테이션을 부여한다는 것

- @Controller: 인스턴스 생성 지시, 스프링 MVC를 이용할 때 컨트롤러에 부여

- @Service: 인스턴스 생성 지시, 트랜잭션 경계가 되는 도메인(서비스) 기능에 부여

- @Repository: 인스턴스 생성 지시, 데이터베이스 액세스(리포지토리) 기능에 부여

- @Component: 위 용도 이외의 클래스에 부여

5) 인스턴스를 이용하고 싶은 곳에 어노테이션을 부여한다

- 스프링 프레임워크에 의해 생성된 인스턴스를 이용하는 클래스에 참조를 받는 필드를 선언하고 필드에 @Autowired 어노테이션 부여

 

4. DI 프로그램 만들기

// 인사 인터페이스
public interface Greet {

    // 인사하기
    void greeting();
    
}
// Greet 구현 클래스, 아침 인사 하기
@Component
public class MorningGreet implements Greet{
    @Override
    public void greeting(){
        System.out.println("-------------");
        System.out.println("좋은 아침입니다");
        System.out.println("-------------");
    }
}
//스프링부트 시작 클래스
@SpringBootApplication
public class BookstudyApplication {

    //메인 메서드: 자신의 execute 메서드를 호출하도록 작성
    public static void main(String[] args) {
        SpringApplication.run(BookstudyApplication.class, args)
                .getBean(BookstudyApplication.class).execute();
    }

    //주입하는 곳(인터페이스)
    @Autowired
    Greet greet;

    //실행 메서드
    private void execute(){
        greet.greeting();
    }
}

 

[소스코드 설명]

- 스프링 프레임워크는 기동 시 컴포넌트 스캔에 의해 MorningGreet 클래스에 @Component 어노테이션이 부여되어 MorningGreet 인스턴스가 생성됨

- @Autowired 어노테이션에 따라 MorningGreet 클래스의 인스턴스가 클래스의 greet 필드에 주입되어 실행되면 MorningGreet 클래스의 getting 메서드가 실행됨

 

[요약]

- 스프링 프레임워크는 임의로 구현한 클래스를 인스턴스화하는 기능을 제공(DI 컨테이너)

- 스프링 프레임워크를 사용하는 애플리케이션은 인스턴스를 명시적으로 생성하지 않음(new 키워드를 사용하지 않음)

- 정해진 어노테이션(@Component)을 클래스에 부여하는 것으로 스프링 프레임워크가 인스턴스를 생성

- 생성된 인스턴스를 사용하고 싶은 부분에서 필드를 준비하고 주석(@Autowired)을 부여하면 스프링 프레임워크가 인스턴스가 필요한 것으로 판단하고 인스턴스를 주입

- 인스턴스를 이용해서 의존성을 만들고 DI를 사용하여 '사용되는 객체' 클래스를 변경하는 경우 '사용하는 객체' 클래스의 수정 없이 변경할 수 있음

 

5. 어노테이션

1) 도메인 주도 설계 레이어

- Application Layer: 클라이언트와 데이터의 입출력을 제어하는 레이어

- Domain Layer: 애플리케이션의 중심이 되는 레이어로서 업무 처리를 수행하는 레이어

- Infrastructure Layer: 데이터베이스에 대한 데이터 영속성 등을 담당하는 레이어

2) 레이어별 인스턴스 생성 어노테이션

- @Controller: 애플리케이션 레이어의 컨트롤러에 부여

- @Service: 도메인 레이어의 업무 처리에 부여

- @Repository: 인프라 레이어의 데이터베이스 액세스 처리에 부여

- @Component: 하위 로직을 처리할 때 사용

 

6. 관점 지향 프로그래밍(AOP, Aspect Oriented Programming)

- 프로그램을 '중심적 관심사'와 '횡단적 관심사' 2개의 요소로 구성되어 있다고 생각

- AOP는 본질적인 기능은 아니나 꼭 필요한 기능인 횡단적 관심사를 분리함으로써 기존 코드를 수정하지 않아도 프로그램 중에 특정 기능(공통 처리)을 추가할 수 있음

1) AOP 고유 용어

- Advice, Aspect, JoinPoint, Pointcut, Interceptor, Target

2) 어드바이스의 다섯 가지 어노테이션 종류

- @Before, @AfterReturning, @AfterThrowing, @After, @Around

3) 포인트컷 식

- 직접 어드바이스를 만드는 경우 패키지, 클래스, 메서드 등 어드바이스 삽입 대상을 조건으로 지정할 수 있음

- 지정하는 조건 방법에는 포인트 컷 사용

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

package me.yuan.bookstudy.used.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;

@Aspect //어드바이스를 기술하는 클래스
@Component  //인스턴스 생성
public class SampleAspect {

    @Before("execution(* me.yuan.bookstudy.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()));
    }

    @After("execution(* me.yuan.bookstudy.used.*Greet.*(..))")      //메서드 실행 후에 호출
    public void afterAdvice(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()));
    }

    @Around("execution(* me.yuan.bookstudy.used.*Greet.*(..))")     //메서드 실행 전후에 호출
    public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        //시작 부분 표시
        System.out.println("=== Arou줌d Advice ===");
        System.out.println("*** 처리전 ***");
        //지정한 클래스의 메서드 실행
        Object result = joinPoint.proceed();
        System.out.println("*** 처리후 ***");
        //반환값을 돌려줄 필요가 있는 경우에는 Object 타입의 반환값을 돌려줌
        return result;
    }
}

 

4) Around Advice와 다른 어드바이스와의 차이

- 인수는 ProceedingJoinPoint 인터페이스 타입을 지정

- 어드바이스 중에서 ProceedingJoinPoint 인터페이스의 proceed() 메서드를 호출

- 어드바이스 적용 대상의 메서드를 임의의 타이밍으로 호출할 수 있으므로 전후로 다양한 처리가 가능

 

7. @Transactional

- 트랜잭션 관리에 사용하는 어노테이션

- 데이터베이스 액세스 처리 메서드가 정상 종료하면 트랜잭션을 커밋하고 예외가 발생하면 롤백

 

 

 

+ Recent posts