티스토리 뷰

☠️ Java

어노테이션(annotation)

James Wetzel 2024. 9. 7. 13:11
728x90
반응형

 

 

@Value

@Value 어노테이션을 사용하면 *.properties 에 설정된 키 값을 가져 올 수 있습니다.

// application.properties
spring.application.name=demo

이러한 키/값이 "application.properties 파일" 존재한다면

@Value("${spring.application.name:someDefaultValue}")
private String properties;

application.properties 에 키("spring.application.name") 가 존해하기 때문에
"properties" 는 "demo" 라는 값이 설정됩니다.

만약 
키("spring.application.name") 가 존재하지 않는다면
"properties" 는 "someDefaultValue" 라는 값이 설정됩니다.

 

@ProperySource

내용 준비중...

 

@Scope

Spring Framework에서 객체 인스턴스의 생성과 참조 범위를 설정합니다.

singleton, prototype, request, session, globalSession 등이 있습니다.

@Component
@Scope("prototype")
public class ShoppingCart { ... }

@Scope("prototype")로 설정하면 요청시 마다 빈 인스턴스를 새로 만듭니다.
다시 말해 각 사용자 마다 "ShoppingCart" 객체의 인스턴스를 만들어 준다는 것입니다.

만약 각 사용자 마다 "ShoppingCart" 객체의 인스턴스 만들어 주지 않을 경우
모든 사용자가 동일한 "ShoppingCart" 객체의 인스턴스를 참조하게 됩니다.

왜냐하면 @Scope 은 기본적으로 singleton 이기 때문입니다.

 

 

 

@ComponentSacn 또는 <context:component-scan> 태그

 

<context:component-scan> 태그와 Spring 어노테이션(annotaion)은 밀접한 관계가 있습니다.

이 태그는 Spring의 자동 빈 등록 기능을 활성화하여 특정 패키지에서 어노테이션이 붙은 클래스들을 자동으로 스캔하고,

이를 스프링 컨테이너에 빈으로 등록하는 역할을 합니다.

<context:component-scan base-package="com.example.controller" />
<context:component-scan base-package="com.example.service" />
<context:component-scan base-package="com.example.repository" />

// 루트 패키지를 설정하면, 하위 패키지까지 자동으로 스캔합니다.
<context:component-scan base-package="com.example" />

기본 애너테이션(annotation)

@Component

Spring 컨테이너에 일반 빈을 등록하는 클래스에 사용됩니다.

 

@Service

비즈니스 로직을 처리하는 서비스 클래스에 사용됩니다. 

@Component와 동일한 역할을 하지만 서비스 계층을 의미적으로 나타냅니다.


@Repository

데이터 액세스 계층(DAO)에 사용되며, 예외 처리에 대한 추가적인 기능을 제공합니다.


@Controller

Spring MVC의 컨트롤러 역할을 하는 클래스에 사용됩니다.

 

@RestController

@RequestMapping

@GetMapping

@PostMapping

@PutMapping

@DeleteMapping

 

@RequestBody

package com.example.demo.controller;

import com.example.demo.dto.MemberDto;
import org.springframework.web.bind.annotation.*;

import java.util.Map;

@RestController
public class HomeController {

    @PostMapping("/requestBody")
    public String requestBody(@RequestBody Map<String, String> mapParam) {
        StringBuilder sb = new StringBuilder();

        mapParam.forEach((key, value) -> {
            sb.append(String.format("%s : %s, ", key, value));
        });

        return "requestBodyParam " + sb;
    }

    @PostMapping("/requestBody2")
    public String requestBody2(@RequestBody MemberDto memberDto) {
        return "requestBody2 " + memberDto.toString();
    }

}

 

호출


@PathVariable

package com.example.demo.controller;

import com.example.demo.dto.MemberDto;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@RestController
public class HomeController {

    @GetMapping("/hi/{pathVariable}")
    public String hi(@PathVariable String pathVariable) {
        return "hi " + pathVariable;
    }

    @GetMapping("/hi2/{pathVariable2}/{pathVariable1}")
    public String hi2(
            @PathVariable(value="pathVariable1") String pathVariable1,
            @PathVariable(value="pathVariable2") String pathVariable2
    ) {
        return "hi2 " + pathVariable1 + pathVariable2;
    }
    
}

@RequestParam

package com.example.demo.controller;

import com.example.demo.dto.MemberDto;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@RestController
public class HomeController {

    @GetMapping("/requestParamTest")
    public String requestParamTest(
            @RequestParam String name,
            @RequestParam String email
    ) {
        return "requestParam " + name + email;
    }

    @GetMapping("/requestParamTest2")
    public String requestParamTest2(@RequestParam Map<String, String> mapParam) {
        StringBuilder sb = new StringBuilder();
        mapParam.forEach((key, value) -> {
            sb.append(String.format("%s : %s, ", key, value));
        });

        return "requestParamTest2 " + sb.toString();
    }

    @GetMapping("/classParamTest")
    public String classParamTest(MemberDto memberDto) {
        return "classParamTest " + memberDto.toString();
    }

}
package com.example.demo.dto;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString
public class MemberDto {
    private String name;
    private String email;
    private String organization;
}
http://localhost:8080/hi/james

http://localhost:8080/hi2/path2/path1

http://localhost:8080/requestParamTest?name=james&email=james@ai.com

http://localhost:8080/requestParamTest2?name=james&email=james@ai.com

http://localhost:8080/classParamTest?name=james&email=james@ai.com&organization=org

의존성 주입 관련 애너테이션

@Autowired

타입에 따라 자동으로 빈을 주입합니다. 생성자, 필드, 세터 메서드에 사용할 수 있습니다.


옵션:

required: false로 설정하면 주입할 빈이 없을 경우에도 에러가 발생하지 않습니다.


@Qualifier

@Autowired와 함께 사용되어, 동일한 타입의 빈이 여러 개 있을 경우 특정 빈을 명시적으로 선택할 때 사용됩니다.


@Inject

자바 표준 애너테이션(JSR-330)으로 타입을 기준으로 주입을 처리한다.


@Resource

자바 표준 애너테이션(JSR-250)으로 이름을 기준으로 주입을 처리한다.

@Autowired & @Qualifier를 합한 것과 같으므로 대상이 명확합니다.

 

@Primary

다수의 동일한 타입이 존재할때 주입시 우선권을 가진다.


트랜잭션 관련 애너테이션
@Transactional

메서드나 클래스에 트랜잭션을 적용합니다. 트랜잭션의 시작과 종료를 자동으로 처리하며, 예외 발생 시 자동으로 롤백됩니다.


속성:
propagation: 트랜잭션의 전파 규칙을 설정합니다. (예: REQUIRED, REQUIRES_NEW)
isolation: 트랜잭션의 격리 수준을 설정합니다.
readOnly: true로 설정하면 읽기 전용 트랜잭션이 됩니다.
rollbackFor: 롤백할 예외 유형을 지정합니다.


AOP(Aspect-Oriented Programming) 관련 애너테이션
AOP는 횡단 관심사를 분리하기 위해 사용되며, 주로 메서드 실행 전후에 부가 작업을 추가합니다.

@Aspect

AOP 기능을 제공하는 클래스에 사용됩니다.


@Before

지정된 메서드 실행 전에 수행할 작업을 정의합니다.


@After

지정된 메서드 실행 후에 수행할 작업을 정의합니다.


@Around

지정된 메서드 실행 전후에 수행할 작업을 정의합니다.


@AfterReturning

메서드가 정상적으로 종료된 후 수행할 작업을 정의합니다.


@AfterThrowing

예외가 발생한 경우 수행할 작업을 정의합니다.


REST

@RestController

 

@ResponseBody

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

    @GetMapping("/greet")
    @ResponseBody
    public String greetUser(@RequestParam(value = "name", defaultValue = "World") String name) {
        return "Hello, " + name + "!";
    }
}

@PathVariable

 

Controller

@ModelAttribute

@Controller
public class UserController {

    @GetMapping("/register")
    public String showForm(Model model) {
        model.addAttribute("user", new User());
        return "registerForm";
    }

    @PostMapping("/register")
    public String registerUser(@ModelAttribute("user") User user, Model model) {
        // user 객체에 폼 데이터가 바인딩됨
        model.addAttribute("message", "User registered successfully");
        return "result";
    }
}

@RequestParam(name="", required=true)

@ExceptionHandler

 

 

@RequiredArgsConstructor

@RequiredArgsConstructor
final 필드나, @NonNull 이 붙은 필드를 기준으로 생성자를 생성한다.


@RequiredArgsConstructor
public class UserService {
    
    private final UserRepository userRepository; // final 필드
    private final NotificationService notificationService; // final 필드
    
    @NonNull
    private LoggingService loggingService; // NonNull 필드
}

 

 

@PostConstruct

`@PostConstruct`는 Java에서 객체가 생성되고 의존성 주입이 완료된 후 초기화를 수행할 때 사용하는 어노테이션입니다. 
`@PostConstruct`가 붙은 메서드는 빈(bean)이 초기화될 때 자동으로 호출되며, 
Spring에서는 주로 빈의 초기 설정을 수행하거나 리소스를 준비하는 데 사용됩니다.

### 동작 방식

- **위치**: `@PostConstruct`는 클래스 내 메서드에 사용됩니다.
- **실행 시점**: 빈이 생성되고 의존성 주입이 끝난 후 자동으로 호출됩니다.
- **의미**: 빈의 초기 설정을 목적으로 하며, Spring 컨테이너가 메서드를 관리하는 객체가 사용할 준비가 완료되었음을 의미합니다.

### 예제 코드

아래는 `@PostConstruct`를 사용해 초기화 작업을 수행하는 예제입니다.

```java
import jakarta.annotation.PostConstruct;
import org.springframework.stereotype.Component;

@Component
public class DataInitializer {

    private final DataService dataService;

    public DataInitializer(DataService dataService) {
        this.dataService = dataService;
    }

    @PostConstruct
    public void init() {
        System.out.println("Initializing data...");
        dataService.loadData();
    }
}
```

위 코드에서 `@PostConstruct`가 붙은 `init()` 메서드는 `DataInitializer` 빈이 생성되고 
`dataService`가 주입된 후 호출됩니다. 이 메서드는 데이터를 로드하는 초기화 작업을 수행합니다.

### 주요 사용 용도

1. **리소스 초기화**: 데이터베이스 연결, 파일 로드 등 애플리케이션 구동 시 필요한 리소스를 초기화합니다.
2. **기본 설정 로드**: 애플리케이션이 시작될 때 불러와야 하는 기본 데이터를 로드합니다.
3. **환경 설정 확인**: 주입된 의존성을 확인하거나 환경 설정 값을 검증합니다.

### 주의 사항

- `@PostConstruct`는 한 번만 호출되므로, 여러 번 호출해야 하는 로직에는 적합하지 않습니다.
- 메서드는 반환 값이 `void`여야 하고, 예외를 던지지 않도록 설계하는 것이 좋습니다.
- Spring의 라이프사이클에 따라 빈 초기화 시점에서만 호출되므로, 이후 호출이 필요하다면 별도의 메서드로 분리해야 합니다.

`@PostConstruct`를 활용하면 Spring 빈의 초기화 과정에서 필요한 로직을 명확하고 직관적으로 구현할 수 있습니다.
728x90
반응형