Spring Annotation

양치는 하셨나요·2024년 8월 13일
post-thumbnail

스프링은 이전 스프링 조사를 하며 자세히 다뤘었다. 그런데 Annotation…? 스프링 주석? 이게 무엇인가… 스프링을 이제 막 시작하는 입장에서 감이 잘 안온다.. 프레임워크라는 것의 특성을 생각해본다면 분명 단순 주석의 기능을 하는 것이 아닐텐데..

결국 스프링을 사용하고자 하는 나의 입장으로써 정리를 안하고 넘어갈 순 없으니 한 번 차근차근 정리해본다.


Annotation

위에서 말하듯 단순 의미는 주석이라는 의미를 가지고 있지만 Java에서는 단순 주석의 의미가 아니다. Annotation은 Java 코드에 추가해 사용하는 메타데이터의 일종으로 @기호를 붙여 사용한다.

Annotation을 사용하면 코드가 깔끔해지고 재사용이 가능해지며 아래와 같은 장점을 얻을 수 있다.

  • 컴파일러에게 코드 작성 문법 에러를 체크하도록 정보를 제공
  • 소프트웨어 개발 툴이 빌드나 배치시 코드를 자동으로 생성할 수 있도록 정보를 제공
  • 실행 시 특정 기능을 실행하도록 정보를 제공

Annotation을 사용하기 위한 순서는 아래와 같다.

  1. Annotation을 정의한다.

  2. 클래스에 Annotation을 배치한다.

  3. 코드가 실행되는 중에 Reflection을 이용하여 추가 정보를 획득하여 기능을 실시한다.

    Reflection: 프로그램이 실행 중에 자신의 구조와 동작을 검사하고, 조사하고, 수정하는 것이다. Java에선 컴파일 타임에 인터페이스, 필드, 메소드의 이름을 알지 못해도 실행 중에 클래스, 인터페이스, 필드 및 메소드에 접근할 수 있다.


종류

@SpringBootApplication

Spring Boot를 자동으로 실행시켜준다.

이때 Bean 등록은 2단계로 이뤄진다.

  • @ComponentScan을 통해 Component들을 Bean으로 등록한다.
    • Bean: 스프링 컨테이너에 의해 재사용 가능한 소프트웨어 컴포넌트. → 스프링이 관리하는 자바 객체. 인스턴스화된 객체.
  • @EnableAutoConfiguration을 통해 미리 정의해둔 자바 설정 파일들을 Bean으로 등록한다.
    • Bean은 스프링 IoC 컨테이너에 의해 인스턴스화되어 조립되거나 관리되는 객체
      • IoC: 제어 역전 (이전 스프링 게시물 참고. )

→ 그럼 ComponentScan과 EnableAutoConfiguration은 무엇인가?

@ComponentScan

@ComponentScan은 해당 패키지에서 @Component 어노테이션을 가진 Bean들을 스캔해서 등록하는 것이다.

(@Configuration, @Repository, @Service, @Controller, @RestController 포함)

→ ComponentScan 아래에 다양한 Bean들이 존재하는 이유는 Component의 기능들을 좀 더 세부적으로 명시하고 구조화하여 역할을 구분 짓기 위해서다. 이렇게 구분 짓는다면 추후 유지 보수에 장점이 생긴다.

→ 비즈니스 로직(Service 등)과 DB(Repository 등)의 구분으로 코드 활용과 테스트 용이성을 높일 수 있다.

@EnableAutoConfiguration

AutoConfiguration은 결국 Configuration이다. 즉, Bean을 등록하는 자바 설정 파일이다.

spring.factories 내부에 여러 Configuration 들이 있고, 조건에 따라 Bean을 등록한다.

위의 과정을 순서로 나타내면 아래와 같다.

  1. 메인 클래스(@SpringBootApplication)를 실행
  2. @EnableAutoConfiguration에 의해 spring.factories 안에 들어있는 수많은 자동 설정들이 조건에 따라 적용
  3. 해당 설정에 알맞게 다양한 Bean들이 생성
  4. 스프링 부트 어플리케이션 실행

@Component

개발자가 직접 작성한 Class를 Bean으로 등록하기 위한 어노테이션이다.

@ComponentScan선언에 의해 특정 패키지 안의 클래스들을 자동 스캔하여 @Component 어노테이션이 있는 클래스들에 대하여 Bean 인스턴스를 생성한다.

@Component
public class Spring {
	public SpringTalk() {
    	System.out.println("hello");
    }
}

@Component(value="FirstSpring")
public class Spring {
	public SpringTalk() {
    	System.out.println("helloFirstMan");
    }
}

Component에 대한 추가 정보가 없다면 Class의 이름을 카멜 기법으로 변경한 것이 Bean id로 사용된다. 하지만 @Bean과 다르게 @Component는 name이 아닌 value를 이용해 Bean의 이름을 지정한다.

@Bean

사실 이 친구가 제일 먼저 나왔어야 하지 않나 싶기도 하지만 앞서 기본 동작에 관여하는 Annotation이 있기에 그것 먼저 설명했다.

@Bean은 개발자가 직접 제어가 불가능한 외부 라이브러리 등을 Bean으로 만드려할 때 사용되는 어노테이션이다.

→ Spring Container에 의해 관리되는 Bean 객체를 정의하는 메서드를 나타낸다.

Component의 설명과 마찬가지로 @Bean에 아무런 값을 지정하지 않으면 메서드 이름을 카멜 기법으로 변경한 것이 Bean id로 등록된다. (testcase → testCase와 같이. )

id를 지정하고 싶다면 @Bean(name=”notTest”)와 같이 등록 가능하다.

@Autowired

필드, setter 메서드, 생성자에 사용하며 Type에 따라 알아서 Bean을 주입해주는 역할을 한다.

객체에 대한 의존성을 주입시킨다. (이 부분이 가장 중요하다. 스프링을 사용하는 주된 이유와 연결되기 때문이다. )

@Autowired을 사용하면 스프링이 자동적으로 값을 할당한다.

Controller 클래스에서 DAO나 Service에 관한 객체들을 주입 시킬 때 많이 사용한다.

Bean 주입하는 방식

  1. @Autowired

    필드에 직접 주입하는 방식. 가장 직관적이지만 그만큼 세부 조정이 어렵다.

  2. setter

    (런타임에서 의존성을 변경할 수 있다는 장점이 있지만 현실적으로 동작 중 의존성을 변경할 일이 거의 없다고 봐도 되기에 사용하지 않는다. )

  3. 생성자 이용

    스프링에서는 생성자를 통한 방식을 권장한다. 위의 것을 이용하면 강한 의존성으로 인해 제어가 어려울 수 있다고 한다.

@Controller

Spring MVC의 Controller로 사용한다는 의미의 Annotation이다. 클래스 선언을 단순화 시켜준다.

@RestController

Spring에서 Controller 중 View로 응답하지 않는 Controller를 나타내며 method의 반환 결과를 JSON 형태로 반환한다.

@RestController가 적혀있는 Controller의 method는 HttpResponse로 바로 응답이 가능하다.

@ResponseBody 역할을 자동적으로 해주는 어노테이션이다.

  • @Controller와 @RestController의 차이점
    • @Controller

      API와 view를 동시에 사용하는 경우에 사용한다.

      대신 API 서비스로 사용하는 경우는 @ResponseBody를 사용하여 객체를 반환한다.

      view return이 주목적이다.

    • @RestController

      view가 필요 없는 API만 지원하는 서비스에서 사용한다.

      @RequestMapping 메서드가 기본적으로 @ResponseBody 의미를 가정한다.

      data return이 주목적이다.

      → @RestController = @Controller + @ResponseBody

@Service

Service class에서 쓰이는 어노테이션으로, 비즈니스 로직을 수행하는 Class라는 것을 나타내는 용도이다.

@Repository

DAO class에서 쓰이는 어노테이션이다.

  • DAO: Data Access Object의 약자로, DB를 사용하여 데이터의 조회 및 조작하는 기능을 전담하는 객체를 의미한다.

DB에 접근하는 method를 가지고 있는 Class에서 쓰인다.

@Value

propertis에서 값을 가져와 적용할 때 사용한다.

@Value("${spring.redis.host}")
private String host;

@RequestHeader

Request의 header값을 가져올 수 있으며, 해당 Annotation을 쓴 메서드의 파라미터에 사용한다.

@Controller                   
@RequestMapping("/user")     
public class UserController {
    @RequestMapping(method = RequestMethod.GET)
    public String getUser(@RequestHeader(value="Accept-Language") String acceptLanguage) {
    }
}

@RequestMapping

@RequestMapping(value=”“)와 같은 형태로 작성, 요청 들어온 URI의 요청과 Annotation value 값이 일치하면 해당 클래스나 메서드가 실행되도록 한다. Controller 객체 안의 메서드와 클래스 등에 적용 가능하다. (위의 코드 예시에서도 볼 수 있다. )

  • 사용 범위
    • Class 단위에 사용하면 하위 메서드에 모두 적용됩니다.
    • 메서드에 적용되면 해당 메서드에서 지정한 방식으로 URI를 처리합니다.

@RequestParam

URL에 전달되는 파라미터를 메소드의 인자와 매칭시켜, 파라미터를 받아서 처리할 수 있는 Annotation으로 Json 형식의 Body를 MessageConverter를 통해 Java 객체로 변환시켜준다.

@Controller
@RequestMapping("/user")
public class UserController {
    @RequestMapping(method = RequestMethod.GET)
    public String getUser(@RequestParam String nickname, @RequestParam(name="old") String age {
        String sub = nickname + "_" + age;
        ...
    }
}

@RequestBody

Body에 전달되는 데이터를 메서드의 인자와 매칭시켜, 데이터를 받아서 처리할 수 있는 Annotation으로, 클라이언트가 보내는 HTTP 요청 본문(JSON 및 XML 등)을 Java 오브젝트로 변환한다.

클라이언트가 body에 json or xml 과 같은 형태로 형태로 값(주로 객체)을 전송하면, 해당 내용을 Java Object로 변환한다.

LOMBOK

개념

자바의 라이브러리 중 하나로 반복되는 메서드를 Annotation을 이용해 자동으로 작성해주는 라이브러리.

@Getter @Setter

Lombok에서 가장 자주 활용한다. @Getter와 @Setter를 클래스 이름 위에 적용시키면 모든 변수들에 적용이 가능하고, 변수 이름 위에 적용시키면 해당 변수들만 적용 가능하다.

  • Getter는 객체에 정의된 모든 변수들에게, Setter는 내가 지정한 변수에게.

@AllArgsConstructor

모든 변수를 사용하는 생성자를 자동완성

  • this.a = a 와 같은 생성자를 자동 완성.

@NoArgsConstructor

어떠한 변수도 사용하지 않는 기본 생성자를 자동완성

  • 생성자를 공백으로 자동 완성.

@RequiredArgsConstructor

특정 변수만을 활용하는 생성자를 자동완성

  • 생성자에 들어가는 변수의 특정 변수 지정.

@ToString

Class 내 모든 필드의 toString 메소드를 자동 생성

@Builder

어느 필드에 어떤 값을 채워야 할지 명확하게 정하여 객체 생성 시점에 값을 채워준다.

  • a라는 변수가 있는 클래스에 Builder를 하고 생성자에 .Builder()를 넣으면 getA와 같은 입력 함수를 자동 생성하고 생성자에 대입한다.

결론

Annotation은 주석이란 의미도 있지만 Java에선 메타데이터를 제공해서 주석 이상의 의미나 기능이 부여되어 코드의 가독성을 올리고 재사용을 줄이는 등의 장점을 가진다.

수많은 Annotation이 있기에 모든 것을 다 기억하기는 어려울 수 있으니 이렇게 정리한 글을 바탕으로 하나씩 기억하고 유용하게 사용해 본다.

profile
프로그래밍을 잘하고 싶어요..

0개의 댓글