inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

백엔드 코틀린 개발하기 2주차 모르는 개념 정리

언니복이
0

Domain 개발하기

데이터 초기화

@Component // 스프링 빈으로 등록

📌 @Component란?

@ComponentSpring Framework에서 빈(Bean)으로 등록하기 위한 기본적인 애너테이션입니다.
즉, Spring이 해당 클래스를 자동으로 스프링 컨테이너(IOC 컨테이너)에 등록하도록 해줍니다.

🚀 @Component 사용 방법

@Component
class MyService {
    fun doSomething() {
        println("MyService is working!")
    }
}
@Service
class SomeClass(private val myService: MyService) {
    fun execute() {
        myService.doSomething()
    }
}

Spring에서는 @Component 외에도 특정한 목적에 맞는 다른 애너테이션들이 있습니다.

애너테이션 설명 @Component 가장 기본적인 빈 등록 애너테이션 @Service 비즈니스 로직을 처리하는 클래스에 사용 @Repository 데이터베이스 작업(DAO, Repository)에 사용 @Controller Spring MVC 컨트롤러(웹 요청 처리)에 사용

💡 실제 동작은 동일하지만, 역할에 맞게 애너테이션을 사용하는 것이 가독성과 유지보수성을 높이는 데 도움이 됩니다.

📌 @Component를 어디서 쓰면 좋을까?

사용하면 좋은 경우

다른 애너테이션을 쓰는 것이 좋은 경우

🔥 결론

@PostConstructSpring에서 빈(Bean)이 생성된 후 자동으로 실행되는 메서드를 지정하는 애너테이션입니다.

즉, 스프링 컨테이너가 해당 빈을 생성하고 의존성 주입(DI)이 완료된 후 한 번 실행되는 초기화 메서드를 정의할 때 사용된다.

🚀 @PostConstruct 기본 사용 예시

@Component
class MyService {

    @PostConstruct
    fun initializeData() {
        println("MyService 초기화 중...")
        // 초기 데이터 설정 로직
    }
}

실행 흐름:

  1. MyService스프링 컨테이너에 의해 빈(Bean)으로 생성됨.

  2. 의존성 주입(DI)이 완료됨.

  3. @PostConstruct가 붙은 initializeData() 메서드가 자동 실행됨.

💡 @PostConstruct의 주요 특징

  1. Spring Bean이 생성된 후, 단 한 번만 실행됨.

  2. 의존성 주입이 완료된 후 실행되므로, 다른 빈을 사용할 수 있음.

  3. 애플리케이션이 실행될 때 한 번만 초기화해야 하는 작업에 적합.

🎯 @PostConstruct가 유용한 경우

사용 예시 설명 초기 데이터 설정 DB에서 기본 데이터를 불러오거나, 캐시를 로딩할 때 외부 API 연동 애플리케이션 시작 시 특정 API와 통신해야 할 때 리소스 초기화 특정 설정 파일을 읽거나, 초기 환경을 세팅할 때

📌 데이터 초기화 예시

@Service
class DataService(private val repository: MyRepository) {

    @PostConstruct
    fun initializeDatabase() {
        if (repository.count() == 0L) {
            repository.saveAll(listOf(MyEntity("데이터1"), MyEntity("데이터2")))
            println("초기 데이터 삽입 완료")
        }
    }
}

데이터베이스에 초기 데이터를 넣어야 할 때 유용함.

주의할 점

비동기 작업 (@Async)과 함께 사용하면 안 됨

@Bean
fun initRunner() = ApplicationRunner {
    println("애플리케이션 실행 후 초기화 코드 실행")
}

🔥 결론

Spring Data JPA의 saveAll() 메서드는 비어있는 리스트(List<T>)를 전달해도 오류 없이 실행되도록 설계되어 있다.

즉, achievements 리스트가 비어있다면 아무런 데이터도 저장되지 않고, 그냥 정상적으로 메서드가 종료된다.

🚀 saveAll() 동작 방식

achievementRepository.saveAll(emptyList()) // 데이터가 없어도 실행됨

내부적으로 실행되는 로직

🎯 saveAll()이 실행될 때 두 가지 경우

1⃣ 데이터가 있을 때

val achievements = listOf(
    Achievement(name = "Level 1", score = 10),
    Achievement(name = "Level 2", score = 20)
)
achievementRepository.saveAll(achievements) // DB에 저장됨

2⃣ 데이터가 없을 때

val emptyList = emptyList<Achievement>()
achievementRepository.saveAll(emptyList) // 아무 일도 일어나지 않음

🔥 결론

saveAll(emptyList())는 아무런 데이터도 저장하지 않고 그냥 종료되도록 설계됨.
데이터가 없을 경우에도 오류 없이 정상 동작함.
Spring Data JPA는 이런 경우를 고려하여 예외를 던지지 않음.

📌 즉, 데이터가 없어도 saveAll()이 실행되지만, 실제로 DB에는 아무런 변경이 일어나지 않는 것! 🚀

 

Kotlin에서 fun의 의미

Kotlin에서 fun 키워드는 함수를 정의할 때 사용되는 키워드
Java의 public List<Skill> findAllByIsActive(boolean isActive)와 같은 역할을 한다.

🚀 fun findAllByIsActive(isActive: Boolean): List<Skill>

// select * from skill where is_active = :isActive
fun findAllByIsActive(isActive: Boolean): List<Skill>

설명

🔹 사용 예시

val activeSkills: List<Skill> = skillRepository.findAllByIsActive(true)
println(activeSkills) // 활성화된 스킬 목록 출력

🚀 fun findByNameIgnoreCaseAndType(name: String, type: SkillType): Optional<Skill>

// select * from skill where lower(name) = lower(:name) and type = :type
fun findByNameIgnoreCaseAndType(name: String, type: SkillType): Optional<Skill>

설명

🔹 사용 예시

val skill: Optional<Skill> = skillRepository.findByNameIgnoreCaseAndType("java", SkillType.PROGRAMMING)

if (skill.isPresent) {
    println("Skill found: ${skill.get()}")
} else {
    println("Skill not found")
}

🔥 결론

  1. Kotlin에서 fun은 함수 선언 키워드.

  2. findAllByIsActive(isActive: Boolean): 활성화된(is_active) 데이터를 리스트로 반환.

  3. findByNameIgnoreCaseAndType(name, type): 대소문자 구분 없이 특정 이름과 타입을 가진 데이터를 조회.

  4. Spring Data JPA는 메서드 이름을 기반으로 자동으로 SQL을 생성하여 실행함. 🚀

 

회고

사실 왕복 3시간 거리 회사를 다니고 지금 커피챗, 친구들 만나기, 스터디 2개까지 해서 솔직히 버거워서 밀렸음 그래도 일단 과제를 내고자 하는 의지로 내는 중...

답변 0