어노테이션

랏 뜨·2024년 12월 24일

🔎 Overview

  그동안 아무생각 없이 마냥 편리하게 사용해왔던 기능이 있다. @를 붙여서 사용하는 어노테이션이다.

  처음 어노테이션을 접했을 때 정말 말도 안 된다고 생각했다. 구현하기 까다롭고 헷갈리는 것들이 단 한 줄의 코드 추가만으로 구현할 수 있게 되다니, 이 얼마나 좋은 기능인가.
그러다보니 지금까지 아무 생각없이 사용해오기만 했다.

  하지만 이제는 자바와 스프링에 대해서 어느정도 감도 잡았으니 제대로 알고 사용해야 되겠다는 생각이 들어, 이번 포스팅의 주제는 어노테이션으로 정했다.
이 말도 안 되는 기능은 도대체 어떻게 작동되는 것이며, 쓰이는 곳은 얼마나 많을까?


📕 어노테이션

  • 자바에서 코드에 메타데이터를 추가하는 방법
  • 컴파일러 및 런타임에 특정 동작을 지정하거나, 정보를 제공하기 위한 일종의 표시
  • 스프링 프레임워크에서는 어노테이션을 통해 의존성 주입, 요청 매핑, 트랜잭션 관리 등의 작업을 선언적으로 처리할 수 있음
    • 개발자가 직접 로직을 작성하지 않고 원하는 결과를 선언해두기만 하면, 스프링이 이를 자동으로 처리
    • @Bean , @GetMapping , @Transactional ...


📑 어노테이션 정의 방법

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface MyAnnotation() {
	String value() default "default value";
    int number() default 0;
}
  • @interface
    • 새로운 어노테이션을 정의
    • 메타정보를 추가할 때 사용할 것을 의미

  • @Retention(RetentionPolicy.RUNTIME)
    • 이 어노테이션을 런타임까지 사용할 수 있다는 것을 의미
    • 실행 중에도 이 어노테이션의 정보를 읽을 수 있게 해줌

  • @Target({ElementType.METHOD, ElementType.TYPE})
    • 이 어노테이션을 어디에 사용할 수 있는지 정의
    • ElementType.METHOD : 메서드에 이 어노테이션 사용 가능
    • ElementType.TYPE : 클래스에 이 어노테이션 사용 가능

  • String value()
    • 어노테이션에 전달할 값 중 String 타입의 값
    • 사용 시 value를 지정하지 않으면 "default value" 로 사용

  • int number()
    • 어노테이션에 전달할 값 중 int 타입의 값
    • 사용 시 number를 지정하지 않으면 0 사용

🤔 String value() , int number() 에서 사용되는 ( ) 는 무엇일까?

  • 어노테이션 정의에서 메서드처럼 사용되는 부분
  • 어노테이션 속성메서드 형태로 정의하는 것이 문법적 규칙
  • 실제로는 메서드가 아니며, 어노테이션의 속성 또는 을 설정하는 역할
  • String value(String args) , String value(args) 처럼 ( ) 안에 값 하드코딩 불가능


✔️ 어노테이션 사용 방법

@MyAnnotation(value = "Class Annotation", number = 20)
public class MyClass {
	@MyAnnotation(value = "Method Annotation", number = 10)
    public void myMethod() {
    	System.out.println("메서드가 실행되었습니다.");
    }
}
  • @Target 으로 지정한 클래스메서드에 어노테이션 사용 가능
  • 위의 예시의 메서드 같은 경우, 클래스 레벨의 어노테이션이 아닌 메서드 레벨의 어노테이션 값을 사용
    • 어노테이션은 상속되지 않음
    • 즉, 클래스 레벨에 적용된 어노테이션이 메서드 레벨에서 자동으로 상속되거나 적용되지 않음
    • 어노테이션은 각 레벨에서 독립적으로 선언되고 적용
  • value 속성이 어노테이션에 하나만 존재할 경우, 옵션 값으로 지정 시 value = ?? 에서 value =  을 생략할 수 있음
  • 이 어노테이션 정보들은 프로그램 실행 중에도 읽어올 수 있음
    • RetentionPolicyRUNTIME으로 지정해주었기 때문


⌨️ 어노테이션 활용 방법

public class AnnotationProcessor {
	public static void main(String[] args) throws Exception {
    	Class<MyClass> myClass = MyClass.class;
        
        if (myClass.isAnnotationPresent(MyAnnotation.class)) {
        	MyAnnotation annotation = myClass.getAnnotation(MyAnnotation.class);
            System.out.println("value : " + annotation.value());
            System.out.println("number : " + annotation.number());
        }
        
        Method method = myClass.getMethod("myMethod");
        
        if (method.isAnnotationPresent(MyAnnotation.class)) {
        	MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
            System.out.println("value : " + annotation.value());
            System.out.println("number : " + annotation.number());
        }
    }
}

1) Class Annotation 읽어오기

  • Class<MyClass>
    • MyClass 클래스 정보를 가져옴
  • isAnnotationPresent(MyAnnotation.class)
    • MyClassMyAnnotation 어노테이션이 붙어있는지 확인
  • getAnnotation(MyAnnotation.class)
    • MyClass어노테이션 속성에 들어있는 메타데이터 값을 가져옴

2) Method Annotation 읽어오기

  • myClass.getMethod("myMethod")
    • myClass 에 정의된 myMethod 메서드 정보를 가져옴
  • isAnnotationPresent(MyAnnotation.class)
    • methodMyAnnotation 어노테이션이 붙어있는지 확인
  • getAnnotation(MyAnnotation.class)
    • method어노테이션 속성에 들어있는 메타데이터 값을 가져옴

📚 어노테이션의 종류



1️⃣ 자바 기본 어노테이션

1) @Override

  • 상속받은 부모의 메서드를 재정의했음을 표시
  • @Override 가 지정된 메서드는 반드시 부모에 존재해야 하므로, 오타 등의 문제를 방지
    • 부모에 없으면 컴파일 에러 발생
public Parent {
	public void print();
}

public Child extends Parent {
	@Override
	public void print();
}

2) @Deprecated

  • 해당 메서드나 클래스는 더 이상 사용되지 않음을 표시
  • 너무 오래되어 사장된 기술 등에 사용
  • 코드의 유지 보수에 도움
@Deprecated
public class DeprecatedClass {}

3) @SuppressWarnings

  • 지정된 컴파일러 경고를 무시
  • 불필요한 경고를 억제함으로 코드 가독성 향상
@SuppressWarnings("unchecked")
public class NoWarningClass {}



2️⃣ 스프링 프레임워크 어노테이션

1) @Component

  • 클래스가 스프링의 컴포넌트 스캔에 의해 관리되는 임을 지정
  • 오직 클래스에만 사용 가능
  • 일반적인 빈 정의에 사용
@Comonent
public class Component {}

2) @Controller

  • MVC 패턴에서 컨트롤러 역할을 하는 클래스 지정
  • 웹 요청 처리를 위해 사용
  • @Component 의 일종
@Controller
public class AppController {}

3) @Service

  • 비즈니스 로직을 처리하는 서비스 클래스 지정
  • 비즈니스 계층에서 주로 사용
  • @Component 의 일종
@Service
public class AppService {}

4) @Repository

  • DB 접근 계층임을 지정
  • DB 와 관련된 작업을 하는 클래스에 사용
  • JpaRepository 를 상속받는 경우, @Repository 는 생략 가능
    • JpaRepository@Repository 를 상속받은 인터페이스이기 때문
    • 따라서 JpaRepository 를 상속받은 인터페이스나 클래스는 자동으로 @Repository 로 인식됨
@Repository
public class NewRepository {}

public interface AppRepository extends JpaRepository(App, Long) {}

5) @Autowired

  • 객체 간 의존 관계를 직접 설정하지 않고, 스프링 컨테이너가 자동으로 설정하도록 지정
  • 스프링 빈에서 다른 빈을 주입할 때 사용
  • 의존성을 주입하는, 즉 IoC (의존성 역전) 을 구현하는 핵심 방법 중 하나
    • new() 로 개발자가 객체를 직접 생성하지 않고, 스프링이 자동으로 객체 생성 후 주입
@Controller
public class AppController {
	@Autowired
    private AppService appService;
}

6) @RequestMapping

  • HTTP 요청 URL 을 특정 메서드와 매핑
  • 컨트롤러에서 주로 사용
  • 요청 처리 경로를 간결히 정의 가능
@Controller
@RequestMapping("/api")
public class AppController {
	@RequestMapping("/print", method = RequestMethod.GET)
    public void print() {
    	System.out.println("Hi")
    }
}
  • @GetMapping , @PostMapping 등을 사용하여 method =  지정을 생략할 수 있음


3️⃣ Lombok 어노테이션

☑️ 보일러 플레이트 코드를 줄이고 유지보수성 및 생산성의 향상을 도와주는 어노테이션

1) @Getter / @Setter

  • 클래스의 필드 getter, setter 메서드 자동 생성
@Getter
@Setter
@Entity
public class Student {
	private String name;
    private int age;
}
  • getName() , setName(...) 메서드를 통해 필드 값 조작 가능

2) @Data

  • @Getter , @Setter , @ToString , @EqualsAndHashCode , @RequiredArgsConstructor 를 결합한 어노테이션
  • 클래스 생성을 간소화
@Data
public class Student {
	private String name;
    private int age;
}

3) @SneakyThrows

  • 예외를 명시적으로 처리하지 않고도 메서드 작성 가능
  • 절대 예외가 발생하지 않을 때, 예외 처리 코드 간소화 가능
public class MyClass {
	@SneakyThrows
    public void excMethod() {
    	throw new Exception("error");
    }
}
  • try-catchthrows 를 사용하지 않고도 코드 처리 가능

⭐ 기타 어노테이션

1) @Transactional

  • 메서드나 클래스 단에 트랜잭션 설정 적용
  • DB 작업의 원자성을 보장
    • All Commit or Rollback
  • Proxy 객체를 사용한 Dirty Checking으로 인해 성능 향상
@Transactional	// 이 클래스 내 모든 작업은 하나의 트랜잭션으로 처리
public class Job {}

2) @RestController

  • JSON 같은 RESTFul 응답을 반환하는 컨트롤러 지정
  • REST API 구현 시 사용
  • @Controller@ResponseBody 를 결합한 형태
@RestController
public class RestController {}



📋 그 외에도 많은 어노테이션들이 존재하며, 필요에 따라 찾아가면서 학습하는 것을 권장


참고) OpenAI. (2024).ChatGPT(4o)[Large language model].https://chatgpt.com/

profile
기록

0개의 댓글