임대일

스프링(Spring): 스프링 프레임워크, 의존성 주입, @Component, @Autowired, 어노테이션, AOP, 메타 어노테이션 본문

스프링/지식

스프링(Spring): 스프링 프레임워크, 의존성 주입, @Component, @Autowired, 어노테이션, AOP, 메타 어노테이션

limdae94 2024. 7. 8. 21:52

1. 프레임워크

프레임워크(Framework)는 소프트웨어 혹은 애플리케이션 개발을 간단하게 해주는 뼈대이다.

 

프레임워크 장점

  1. 개발에 필요한 최소한의 기능 제공한다.
  2. 애플리케이션 개발에 필요한 시간과 비용을 최소화할 수 있다.

프레임워크 단점

  1. 프레임워크 고유의 사용 방법에 대한 이해가 필요하다.

 

프레임워크와 라이브러리의 정의

프레임워크와 라이브러리는 소프트웨어 개발을 돕는 도구이다. 라이브러리는 특정 기능을 수행하는 코드의 집합으로, 개발자가 필요에 따라 선택적으로 사용할 수 있다. 반면, 프레임워크는 애플리케이션의 뼈대 또는 틀을 제공하며, 개발을 위한 기본적인 형태와 필수 요소를 포함하고 있다. 개발자는 프레임워크가 정한 규칙과 구조 내에서 개발을 진행해야 한다.

 

 

2. 스프링 프레임워크

스프링 프레임워크(Spring Framework)는 자바 개발 환경에서 동적인 웹 사이트를 개발하기 위해 여러 가지 서비스를 제공한다.

 

스프링 프레임워크 구성

스프링 부트는 스프링 프로젝트와 스프링 코어를 포함한다.

 

스프링 부트(SpringBoot)

스프링 애플리케이션을 복잡한 설정 없이 빠르게 작성하는 기능을 제공한다. 

 

 

스프링 프로젝트

  1. Spring MVC: 웹 애플리케이션을 간단하게 생성하는 기능을 제공한다.
  2. Spring Data: 데이터 접근에 관한 기능을 제공한다.
  3. Spring Batch: 배치 처리 기능을 제공한다.
  4. Spring Security: 인증과 인가 기능을 제공한다.

 

스프링 코어

  1. Spring DI: 의존성 주입(Dependency Injection) 기능을 제공한다.
  2. Spring AOP: 관점 지향 프로그래밍(Aspect Oriented Programming) 기능을 제공한다.

3. 의존성 주입

의존성 주입(DI, Dependency Injection)는 '의존하는 부분을 외부에서 주입하는 것'을 의미한다. 

 

예를 들어, 어떤 프로그램에 '사용하는 객체' A 클래스와 '사용되는 객체' B 클래스가 있다고 가정하자. A 클래스에서 B 클래스를 사용하려면 new 키워드를 이용해 B 클래스의 인스턴스를 생성하고 B 클래스의 메서드를 사용한다. 이때 B 클래스에서 구현했던 메서드를 변경하면 그 영향으로 A 클래스에서도 해당 메서드를 변경해야 된다. 이러한 관계를 'A 클래스는 B클래스에 의존한다'라고 합니다.

 

의존 두 가지가 있다. 클래스 의존(구현 의존)인터페이스 의존이다. 지금까지 설명한 new 키워드로 생성되는 클래스가 클래스 의존(구현 의존)이다. 클래스 의존보다 인터페이스 의존이 다방면에서 훨씬 바람직하다. 인터페이스 의존은 다음과 같은 특징이 있다.

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

 

인터페이스 의존 예제

Calculator 인터페이스 안에는 calc 정수 두 개를 입력받는 메서드가 있다. Calculator 인터페이스의 구현 클래스로 AddCalc 는 두 정수의 합을 반환하고, SubCalc 는 두 정수의 차를 반환한다.

package ch03;

public interface Calculator {
    Integer calc(Integer x, Integer y);
}

public class AddCalc implements Calculator {
    @Override
    public Integer calc(Integer x, Integer y) {
        return x + y;
    }
}
package ch03;

public class SubCalc implements Calculator {
    @Override
    public Integer calc(Integer x, Integer y) {
        return x - y;
    }
}

 

두 정수를 더하는 AddCalc 구현 클래스의 인스턴스를 생성하고 두 정수를 더할 수 있다. 두 정수의 뺄셈을 계산하고 싶으면 인스턴스 생성 부분의 AddCalc 대신 SubCalc 클래스로 return 문에서 계산하는 부호 한 줄만 변경하면 된다.

 

하지만 '의존성 주입'을 사용하면 '사용하는 객체'의 클래스를 수정하지 않아도 된다. 지금까지는 인스턴스를 생성할 때 new 키워드를 사용했지만, 인스턴스 생성과 같은 작업을 프레임워크에 맡길 수 있고 그 역할을 하는 것이 DI 컨테이너이다. 정리하자면 스프링 프레임워크는 임의로 구현한 클래스를 인스턴스로 만들어주는 기능을 제공하는데, DI 컨테이너가 그 기능을 가지고 있다.

  • 의존(Dependency)하는 부분이란 '사용하는 객체'에 '사용되는 객체' 클래스가 작성된 상태이다.(A 클래스에 new B(); )
  • 외부로부터 주입(Injection)이란 '사용하는 객체' 클래스의 밖에서 '사용되는 객체' 인스턴스를 주입하는 것이다.

DI 컨테이너에 의해 인스턴스가 주입된다.

 

 

4. 다섯 가지 규칙

DI 컨테이너에 인스턴스 생성을 맡기고 다음의 규칙을 지키는 것으로 '사용하는 객체' 클래스를 전혀 수정할 필요가 없도록 만들 수 있습니다.

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

 

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

- 의존하는 부분에 인터페이스를 이용하는 것을 의미한다.

 

규칙 2. 인터페이스를 명시적으로 생성하지 않는다.

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

 

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

- '어노테이션을 클래스에 부여한다.'와 '스프링 프레임워크에서 인스턴스를 생성한다.'를 정리해 설명하면, 인스턴스를 생성하려는 클래스에 인스턴스 생성 어노테이션을 부여한다는 것이다. 어노테이션에 대한 자세한 나용은 뒷부분에서 다루지만 여기서는 어떤 표식이라고 생각하자. 예를 들어 @Component를 어노테이션이라고 한다.

인스턴스를 생성할 클래스에 @Component를 설정

 

스프링 프레임워크는 프로젝트를 실행할 때 대상 프로젝트의 모든 패키지를 스캔한다. 대상 프로젝트의 모든 패키지를 스캔을 컴포넌트 스캔(Component Scan)이라고 한다. 

 

 

컴포넌트 스캔의 실행

스프링 프레임워크 프로젝트를 실행하면 모든 패키지를 스캔한다.

 

컴포넌트 스캔 후 스프링 프레임워크는 인스턴스 생성 어노테이션이 부여된 클래스를 추출하고 추출한 클래스의 인스턴스를 생성한다.

 

 

인스턴스를 생성할 대상 클래스를 추출

@Component 어노테이션이 있는 클래스를 추출한다.

 

 

대상 클래스를 인스턴스화

스프링 프레임워크가 A, D 클래스의 인스턴스를 생성한다.

 

인스턴스 생성 어노테이션은 용도별로 다음과 같다.

@Controller 인스턴스 생성 지시. 스프링 MVC를 이용할 때 컨트롤러에 부여
@Service 인스턴스 생성 지시. 트랜잭션 경계가 되는 도메인(서비스) 기능에 부여
@Repository 인스턴스 생성 지시. 데이터베이스 액세스(리포지토리) 기능에 부여
@Component 위 용도 이외의 클래스에 부여

 

 

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

- '인스턴스를 이용하고 싶은 곳에 어노테이션을 부여한다.' 는 @Autowired 부여를 의미한다.

@Autowired는 스프링 프레임워크에서 사용되는 어노테이션 중 하나로, 의존성 주입(Dependency Injection)을 자동으로 처리하기 위해 사용된다. 스프링은 IoC(제어의 역전) 컨테이너를 제공하며, @Autowired는 IoC 컨테이너를 통해 자동으로 의존성을 주입할 때 사용된다.

 

의존성 주입은 객체 지향 프로그래밍에서 한 객체가 다른 객체를 사용할 때, 이를 외부에서 주입해주는 디자인 패턴 중 하나이다. 스프링에서는 주로 생성자 주입, 세터 주입, 필드 주입 등을 통해 의존성을 주입할 수 있다. @Autowired는 이 중에서 필드 주입을 간단하게 처리하는데 사용된다.

 

정리

  1. 스프링 프레임워크는 임의로 구현한 클래스를 인스턴스화하는 기능을 제공한다.(DI 컨테이너)
  2. 스프링 프레임워크를 사용하는 어플리케이션은 인스턴스를 명시적으로 생성하지 않는다. (new 키워드를 사용하지 않는다.)
  3. 정해진 어노테이션(@Component)을 클래스에 부여하는 것으로 스프링 프레임워크가 인스턴스를 생성한다.
  4. 생성된 인스턴스를 사용하고 싶은 부분에서 필드를 준비하고 어노테이션(@Autowired)을 부여하면 스프링 프레임워크는 인스턴스가 필요한 것으로 판단하고 인스턴스를 주입한다.
  5. 인터페이스를 이용해서 의존성을 만들고 DI를 사용하여 '사용되는 객체' 클래스를 변경하는 경우 '사용하는 객체' 클래스의 수정 없이 변경할 수 있다.
  • @Component: 인스턴스를 생성하기 위한 어노테이션
  • @Autowired: 인스턴스를 주입하기 위한 어노테이션

 

5. @Component, @Autowired

@Component

  • @Component 어노테이션은 해당 클래스를 스프링의 컴포넌트 스캔의 대상으로 지정한다.
  • 컴포넌트 스캔은 스프링이 프로젝트 내에서 자동으로 빈(Bean)을 찾아 등록하는 메커니즘 중 하나이다.
  • 스프링 컨테이너는 @Component 어노테이션이 붙은 클래스를 검색하여 해당 클래스의 인스턴스를 빈으로 등록한다.
@Component
public class MyComponent {
    // 클래스 내용
}

 

 

@Autowired

  • @Autowired 어노테이션은 스프링이 자동으로 빈을 주입할 때 사용된다.
  • @Autowired 어노테이션이 필드, 생성자, 메서드에 사용될 수 있으며, 주입하고자 하는 빈을 찾아서 자동으로 주입해준다.
  • 주입할 빈을 찾는 기준은 타입에 의해 이루어진다.
@Component
public class MyComponentConsumer {

    private final MyComponent myComponent;

    @Autowired
    public MyComponentConsumer(MyComponent myComponent) {
        this.myComponent = myComponent;
    }

    // 나머지 코드
}

 

위의 예제 코드에서 MyComponentConsumer 클래스의 생성자에 @Autowired 어노테이션이 붙어 있다. 이를 통해 스프링은 MyComponent 타입의 빈을 찾아서 자동으로 주입해준다.

 

요약하면, @Component는 클래스를 스프링 빈으로 등록하는 데 사용되고, @Autowired는 스프링이 자동으로 빈을 주입할 때 사용된다. 두 어노테이션을 함께 사용하여 스프링 애플리케이션을 효과적으로 구성할 수 있다.

 

6. @Component 을 확장한 어노테이션 

@Component 어노테이션은 클래스에 사용되는 일반적인 컴포넌트 스캔 대상을 지정하기 위한 어노테이션이다. 주로 클래스 레벨에서 사용되지만, 실제로는 @Component 어노테이션을 확장한 다른 세부 어노테이션이 존재한다. 이들은 특정 용도나 레이어에 맞추어 사용할 수 있다.

 

@Repository

  • 데이터 액세스 레이어에서 사용되는 어노테이션이다.
  • 주로 데이터베이스와의 상호 작용을 담당하는 DAO(Data Access Object) 클래스에 사용된다.
@Repository
public class UserRepository {
    // 데이터 액세스 코드
}
  1.  

 

@Service:

  • 비즈니스 로직을 처리하는 서비스 레이어에서 사용된다.
@Service
public class UserService {
    // 비즈니스 로직 코드
}

 

 

@Controller:

  • 스프링 MVC에서 컨트롤러 클래스를 나타내는 데 사용된다.
@Controller
public class MyController {
    // 컨트롤러 코드
}

 

@Repository, @Service, @Controller 어노테이션들은 모두 @Component를 기반으로 하고 있다. 따라서 @Component를 포함한 이러한 어노테이션들은 모두 클래스에 적용되며, 스프링은 이들 어노테이션이 붙은 클래스를 스캔하여 빈으로 등록한다.

 

결론적으로, @Component 어노테이션은 클래스에 주로 사용되지만, 특정한 역할을 수행하는 다른 어노테이션들을 사용함으로써 클래스를 더 명확하게 나타낼 수 있다.

 

7. @Autowired

@Autowired 어노테이션은 필드, 생성자, 메서드에 모두 사용할 수 있다. 다양한 방식으로 의존성 주입을 수행할 수 있도록 다양한 옵션을 제공한다.

 

필드에 @Autowired 사용

  • 필드 주입은 가장 간단한 형태로, 주입받을 빈을 선언된 필드에 직접 주입한다.
@Component
public class MyComponentConsumer {

    @Autowired
    private MyComponent myComponent;
    // 나머지 코드
}

 

 

생성자에 @Autowired 사용

  • 생성자 주입은 주로 권장되는 방식으로, 빈을 주입받을 생성자를 선언한다.
@Component
public class MyComponentConsumer {

    private final MyComponent myComponent;

    @Autowired
    public MyComponentConsumer(MyComponent myComponent) {
        this.myComponent = myComponent;
    }
    // 나머지 코드
}

 

 

메서드에 @Autowired 사용

  • 메서드 주입은 일반적으로 setter 메서드에 사용되며, 주입받을 빈을 설정하는 메서드에 @Autowired를 사용한다.
@Component
public class MyComponentConsumer {

    private MyComponent myComponent;

    @Autowired
    public void setMyComponent(MyComponent myComponent) {
        this.myComponent = myComponent;
    }
    // 나머지 코드
}

 

주입할 빈을 설정하는 메서드에 @Autowired를 사용하는 경우, 메서드의 이름은 중요하지 않다. 메서드 이름에 따라 주입이 결정되는 것이 아니라, 메서드의 매개변수 타입을 기준으로 주입이 이루어진다.

 

따라서 @Autowired는 필드, 생성자, 메서드 등 다양한 위치에서 사용할 수 있다. 선택적으로 사용할 수 있는데, 주로 생성자 주입을 권장하며 필드나 메서드 주입은 특별한 경우에 사용될 수 있다.

 

 

8. 어노테이션 역할 알아보기

어노테이션을 간단히 설명하면 다음 세 가지 항목이 된다.

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

어노테이션을 사용하면 에러를 출력하거나 프로그램의 동작을 변경하는 등 다양한 것을 할 수 있다.

소스 코드에 작성된 각 어노테이션은 외부 소프트웨어에서 필요한 처리 내용을 전달한다.

 

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

 

어플리케이션을 만들 때는 레이어를 나누는 것이 좋다. 이때 레이어(Layer)는 '층'의 의미로, 계층 구조로 되어 있는 각 층을 의미한다. 쉽게 이야기하면 복잡한 전체 내용을 한 번에 정리해 이해하지 말고 계층화하여 각 계층별로 대상의 의미를 이해하는 것이다. 다음 세 레이어는 '도메인 주도 설계(Domain-Driven Desgin)'에서 설명한 내용이다.

어플리케이션 레이어
(Application Layer)
클라이언트와의 데이터 입출력을 제어하는 레이어다.
@Controller
도메인 레이어
(Domain Layer)
어플리케이션의 중심이 되는 레이어로서 업무 처리를 수행하는 레이어다.
@Service
인프라스트럭처 레이어
(Infrastructire Layer)
데이터베이스에 대한 데이터 영속성(Persistence Context) 등을 담당하는 레이어다.
@Repository

 

 

인스턴스 생성 어노테이션은 각 레이어별로 구분된다.

@Controller 어플리케이션 레이어의 컨트롤러에 부여
@Service 도메인 레이어의 업무 처리에 부여
@Repository 인프라 레이어의 데이터베이스 엑세스 처리에 부여

 

 

레이어별 인스턴스 생성 어노테이션 사용 예(주요 처리)

클라이언트 요청 처리 흐름도

 

 

레이어별 인스턴스 생성 어노테이션 설명(보조 처리)

@Component @Controller, @Service, @Repository의 용도 이외의 인스턴스 생성 대상 클래스에 부여

 

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

 

10. 커스텀 어노테이션

직접 커스텀 어노테이션을 생성할 수 있다. 커스텀 어노테이션을 만들 때는 java.lang.Annotation 인터페이스를 상속하고 생성한다. 또한 커스텀 어노테이션을 정의할 때는 전용 자바 파일을 생성할 필요가 있다.

 

 

11. 관점 지향 프로그래밍

관점 지향 프로그래밍(AOP, Aspect Oriented Programming)은 프로그램이 중심적 관심사와 횡단적 관심사 이 두 가지 요소로 구성된다고 생각하는 관점을 갖는다.

 

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

AOP를 간단히 설명하면 공통 등의 '횡단적 관심사'를 추출하고 프로그램의 여러 곳에서 호출할 수 있게 설정함으로써 개발자는 실현해야 할 기능인 '중심적 관심사'에만 집중해서 개발하면 되는 구조이다.

 

 

12. 관점 지향 프로그래밍의 기초 지식

데이터베이스 엑세스 처리에는 예외 발생 시 처리하는 내용이 반드시 포함되어야 한다. 예외 처리를 하지 않으면 프로그램이 중지되고 자바의 경우 예외 처리를 프로그램에 포함하지 않으면 컴파일에 실패한다.

데이터베이스 쿼리 예외 발생 유무 상황

 

 

다수의 데이터베이스 엑세스 처리 코드를 작성하다 보면 예외 처리의 내용은 항상 동일하지만, 예외 처리는 필수이므로 항상 작성해야 한다. 예외 처리를 포함하면 프로그램 코드가 증가하고 복잡해진다. 구현하고 싶은 프로그램은 데이터베이스의 엑세스 처리이며, 예외 처리는 구현하고 싶은 프로그램에서 부수적인 내용에 해당 된다.

 

코드의 복잡성을 줄이기 위해 '구현하고 싶은 프로그램=중심적 관심사', '부수적 프로그램=횡단적 관심사'로 분리하여 프로그램을 작성해야 한다. 스프링 프레임워크에서 제공하는 AOP 기능을 활용하여 '중심적 관심사'와 '횡단적 관심사'를 분리하여 프로그램을 쉽게 만들 수 있다.

 

자세한 사용법을 설명하기 전, AOP의 고유 용어에 대해 학습하자.

용어 내용
어드바이스(Advice) 횡단적 관심사의 구현(메서드).
로그 출력 및 트랜잭션 제어 등을 의미한다.
애스펙트(Aspect) 어드바이스를 정리한 것(클래스)이다.
조인포인트(JoinPoint) 어드바이스를 중심적 관심사에 적용하는 타이밍이다.
메서드(생성자) 실행 전, 메서드(생성자) 실행 후 등 실행되는 타이밍이다.
포인트컷(PointCut) 어드바이스를 삽입할 수 있는 위치.
예를 들어, 메서드 이름이 get으로 시작할 때만 처리하는 조건을 정의할 수 있다.
인터셉터(Interceptor) 처리의 제어를 인터셉트하기 위한 구조 또는 프로그램이다. 스프링 프레임워크에서는
인터셉트라는 매커니즘으로 어드바이스를 중심적 관심사에 추가한 것처럼 보이게 한다.
타깃(Target) 어드바이스가 도입되는 대상을 말합니다.

 

 

AOP의 구조

스프링 프레임워크에서는 '인터셉터'라는 메커니즘을 사용하여 횡단적 관심사(어드바이스)를 중심적 관심사(타깃)에 추가하는 것처럼 보일 수 있다.

인터셉터를 활용하여 어드바이스를 타깃에 삽입하는 것처럼 보이게 동작한다.

 

 

어드바이스 종류

스프링 프레임워크가 제공하는 중심적 관심사에 적용하는 어드바이스는 실행 제어 내용별로 다섯 가지 종류가 있다. 각 어노테이션 사용 방법에 대해서는 정리하지 않고 넘어가자.

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

 

 

AOP 공통 기능

스프링 프레임워크에서는 여러 가지 공통 기능을 AOP로 제공한다. 가장 대표적으로, 트랜잭션을 관리하는 @Transactional 어노테이션은 클래스나 메서드에 부여하여 이용할 수 있다. 트랜잭션 관리에는 @Transactional 어노테이션을 통해 데이터베이스 엑세스 처리 메서드가 정상 종료하면 트랜잭션을 커밋하고 예외가 발생하면 롤백한다. @Transactional 어노테이션은 예외가 발생하면 롤백을 한다고 이해하고 자세한 설명은 다음에 학습하자. 

 

@Transactional

 

13. AOP 사고방식

예를 들어, 프로그램 개발 중에 동작 상황을 확인하기 위해 여러 크래스에 System.out.println 을 사용해 '디버깅 로그'를 출력한다고 가정해 보자. 각 클래스의 메서드에 System.out.println 을 입력해야 하기 때문에 이 작업은 생각만 해도 엄청나게 피곤한 작업이 될 것이다.

또한 프로그램 작성이 완료됐을 때는 모든 '디버깅 로그'를 삭제해야 한다. 이런 다수의 클래스에 공통으로 필요한 처리를 '횡단적 관심사'라고 앞에서 설명했다.

만일 여러 클래스의 메서드에 System.out.println 문을 자동으로 넣어주는 기능이 있고, 또한 필요가 없어졌을 때는 모두 자동으로 삭제해주는 기능이 있으면 편리할 것이다. 이 같은 생각이 'AOP 사고방식' 이다.

 

14. AOP 정리

  1. AOP 에서는 프로그램을 2개의 요소인 중심적 관심사와 횡단적 관심사로 구성되어 있다고 생각한다.
  2. 중심적 관심사란 구현해야 할 기능을 나타내는 비즈니스 로직을 말한다.
  3. 횡단적 관심사란 본질적인 기능은 아니지만 품질이나 유지보수 등의 관점에서 꼭 필요한 기능을 나타내는 프로그램을 말한다.
  4. AOP에서는 횡단적 관심사를 분리함으로써 기존 코드를 수정하지 않아도 프로그램 중에 특정 기능(공통 처리)을 추가할 수 있다.
  5. 스프링 프레임워크는 다양한 공통 기능을 AOP에서 제공한다.

 

15. 메타 어노테이션

커스텀 어노테이션을 생성하는 경우에도 어노테이션을 사용한다. 커스텀 어노테이션에 정의를 추가하는 어노테이션을 '메타 어노테이션(Meta Annotation)'이라고 한다. 커스텀 어노테이션을 만들 때만 사용하는 특수 어노테이션이다.

다음과 같은 4종류의 메타 어노테이션을 소개한다.

 

@Target
커스텀 어노테이션이 무엇을 대상으로 하고 있는지 선언하기 위해 사용한다. 어노테이션을 클래스에 부여할지, 메서드에 부여할지, 변수에 부여할지 등을 결정한다. 어노테이션을 부여할 장소는 상수(constant)로 지정한다.

ElementType 요소 추가할 대상
ElementType.ANNOTATION_TYPE 어노테이션
ElementType.CONSTRUCTOR 생성자
ElementType.FIELD 필드
ElementType.METHOD 메서드
ElementType.PACKAGE 패키지
ElementType.PARMETER 인수
ElementType.TYPE 클래스, 인터페이스(어노테이션, enum 포함)

 

 

@Retention
컴파일할 때나 프로그램을 실행할 때 '어노테이션'의 정보를 보관 및 유지하는 유효 범위를 결정하기 위해 사용한다.
@Retention은 유효 범위별로 세 개의 상수를 제공한다.

상수 내용
SOURCE 소스가 유효한 범위이다. 컴파일할 때 어노테이션 정보가 삭제된다.
CLASS 클래스 파일은 유효하지만 JVM에는 읽어 들이지 않는다.(기본값)
RUNTIME 실행 중일 때 JVM에서 참조할 수 있는 가장 넓은 유효 범위이다.

 

@Documented
지정된 어노테이션을 Javadoc API 문서를 출력할 때 표시되게 한다.

 

@Inherited
지정한 어노테이션을 부여한 클래스를 상속하면 하위 클래스도 그 어노테이션을 부여한 것으로 설정한다.