컴포넌트 스캔과 자동 의존관계 설정
서비스를 구축하다 보면 동일한 객체 인스턴스를 프로젝트 전역에 걸쳐 공유해야할 경우가 많다. 이 경우 하나의 인스턴스를 생성한 후 어딘가에 저장해두고 다른 코드에서 그 경로를 찾아 import하는 번거로운 작업이 요구된다.
Spring에서는 이러한 의존관계를 자동으로 설정해준다.
@Controller
@Repository
@Service
등의 방법을 통해 해당 클래스를 하나의 객체 인스턴스만 생성하고 프로젝트 전역에 걸쳐 자동으로 공유되도록 구현할 수 있다.
Spring 어플리케이션이 시작되면 초기 단계에서 어플리케이션이 자동으로 어플리케이션의 위치를 기준으로 모든 하위 디렉토리를 스캔하여 이런 annotation이 붙은 클래스들을 찾는다.
이후 찾은 클래스들의 인스턴스를 모두 하나씩 생성한 후 Spring Bean이라는 곳에 등록한다.
이제 이 인스턴스들은 Spring 어플리케이션 전역에 걸쳐 공유될 준비를 마친 것이다.
이제 다른 코드에서 이 인스턴스를 공유받으려면
@Autowired
를 사용한다.
Spring 이 어노테이션이 붙은 코드를 읽고 매개변수로 일치하는 타입의 인스턴스를 넘겨준다. 이때 넘겨주는 인스턴스는 초기에 Spring Bean에 등록되어 전역으로 공유될 준비를 마친 바로 그 인스턴스이다.
이 방식을 통해 직접 import문을 작성하지 않고 인스턴스를 공유할 수 있으며 관리하기 더 수월하다.
아래는 실제 코드 적용 예시이다.
package hello.hellospring.controller;
import hello.hellospring.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class MemberController {
private final MemberService memberService;
@Autowired
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
}
package hello.hellospring.repository;
import hello.hellospring.domain.Member;
import org.springframework.stereotype.Repository;
import java.util.*;
@Repository
public class MemoryMemberRepository implements MemberRepository {
private static Map<Long, Member> store = new HashMap<>();
private static long sequence = 0L;
@Override
public Member save(Member member) {
member.setId(++sequence);
store.put(member.getId(), member);
return member;
}
@Override
public Optional<Member> findById(Long id) {
return Optional.ofNullable(store.get(id));
}
@Override
public Optional<Member> findByName(String name) {
return store.values().stream().filter(member -> member.getName().equals(name)).findAny();
}
@Override
public List<Member> findAll() {
return new ArrayList<>(store.values());
}
public void clearStore() {
store.clear();
}
}
package hello.hellospring.service;
import hello.hellospring.domain.Member;
import hello.hellospring.repository.MemberRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class MemberService {
private final MemberRepository memberRepository;
@Autowired
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
public Long join(Member member) {
validateDuplicateMember(member);
memberRepository.save(member);
return member.getId();
}
private void validateDuplicateMember(Member member) {
memberRepository.findByName(member.getName()).ifPresent(m -> {
throw new IllegalStateException("이미 존재하는 회원입니다.");
});
}
public List<Member> findMembers() {
return memberRepository.findAll();
}
public Optional<Member> findOne(Long memberId) {
return memberRepository.findById(memberId);
}
}
자바 코드로 직접 Spring Bean 등록
컴포넌트 스캔과 자동 의존관계 설정을 이용하지 않고 직접 JAVA코드로 Spring Bean에 등록할 수도 있다.
Spring 어플리케이션의 위치에 SpringConfig 클래스 파일을 만든 다음 다음과 같이 입력한다.
@Configuration
public class SpringConfig {
@Bean
public MemberService memberService() {
return new MemberService(memberRepository());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
}
이제 Spring 어플리케이션이 시작될때 Spring이 이 Config파일을 읽어 내부에 있는 함수들을 실행하게 된다.
각 함수들은 특정 객체를 Spring Bean에 등록하게 된다.
이후 이 내용을 응용한 다음과 같은 코드를 사용하여 간단한 회원 가입 / 조회 기능을 구현할 수 있다.
@GetMapping("/members/new")
public String createForm() {
return "members/createMemberForm";
}
@PostMapping("/members/new")
public String create(MemberForm form) {
Member member = new Member();
member.setName(form.getName());
memberService.join(member);
return "redirect:/";
}
@GetMapping("/members")
public String list(Model model) {
List<Member> members = memberService.findMembers();
model.addAttribute("members", members);
return "members/memberList";
}
package hello.hellospring.controller;
public class MemberForm {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
'WINK-(Web & App) > Spring Boot 스터디' 카테고리의 다른 글
[Spring Boot 스터디] 류건 #3 주차 - 섹션 4, 5 (0) | 2023.07.30 |
---|---|
[Spring Boot 스터디] 한준교 #3 주차 - 섹션 4, 5 (1) | 2023.07.29 |
[Spring Boot 스터디] 조현상 #3 주차 - 섹션 4,5 (0) | 2023.07.27 |
[Spring Boot 스터디] 류건 #2주차 - 섹션 3 "횐님 관리 예제" (1) | 2023.07.21 |
[Spring Boot 스터디] 이정욱 #2 주차 - 섹션3 (0) | 2023.07.21 |