본문 바로가기

WINK-(Web & App)/Spring Boot 스터디

[2024 Spring Boot 스터디] 김아리 #2 주차

반응형

스프링 빈과 의존관계

컨포넌트 스캔과 자동 의존관계 설정

    • 스프링은 스프링 컨테이너에서 객체를 생성하여 스프링 빈으로 등록한 후 관리한다.
    • MemberController에서 MemberService을 가져와서 사용할 때 매번 new 하면 그때마다 새로운 객체가 생성된다.
    • new 하지 않고 스프링 컨테이너에 객체를 생성한 다음 그 객체를 가져다가 쓰자
    • 컨트롤러 뿐만 아니라 서비스, 리포지토리까지 @Service, @Repository로 스프링 컨테이너에 자동 등록해야 가져다 쓸 수 있다.
    • 그 다음 @Autowired +  생성자 주입하여 컨테이너에 있는 객체를 연결한다.

 컨포넌트 스캔 원리

  • @Component : 이 어노테이션이 있으면 스프링 빈으로 자동 등록한다.
  • 다음 어노테이션도 @Component를 포함하여 스프링 빈으로 자동 등록된다.
    • @Controller
    • @Service
    • @Repository
@Controller
public class MemberController {

    private final MemberService memberService;

    @Autowired
    public MemberController(MemberService memberService) {
        this.memberService = memberService;
    }
}

자바 코드로 직접 스프링 빈 등록

  • 정형화된 컨트롤러, 서비스, 리포지토리 같은 코드는 컴포넌트 스캔 사용
  • 반대로 정형화되지 않거나 상황에 따라 구현 클래스를 변경해야 하면 설정을 통해 스프링 빈으로 등록
  • 우리가 DB를 아직 정하지 않았다는 가상의 시나리오를 갖고 있기 때문에 리포지토리 인터페이스를 구축한 다음, 실제 리포지토리를 구현하였다. 나중에 DB를 정해 그것에 맞는 리포지토리를 만들 때 서비스나 컨트롤러 등 다른 코드는 건들이지 않고 구현하기 위해 스프링 빈으로 등록하는 것이 좋다.(즉, 우리는 리포지토리가 정형화 되지 않은 코드이므로 직접 스프링 빈을 등록한다.)
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SpringConfig {
    @Bean
    public MemberService memberService() {
        return new MemberService(memberRepository());
    }
    @Bean
    public MemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }
}

스프링 컨테이너와 스프링 빈 이미지

스프링은 스프링 컨테이너에 스프링 빈을 등록할 때 하나만 등록해서 공유한다. 따라서 같은 스프링 빈이면 모두 같은 인스턴스다. 이를 싱글톤이라고 한다.

 

회원 관리 예제 - 웹 MVC 개발

등록

@GetMapping("/members/new")
public String createForm() {
    return "/members/createForm";
}
@PostMapping("/members/new")
public String create(MemberForm memberForm) {
    Member member = new Member();
    member.setName(memberForm.getName());

    memberService.join(member);

    return "redirect:/";
}

조회

@GetMapping("/members")
public String view(Model model) {
    List<Member> members = memberService.findMembers();
    model.addAttribute("members", members);
    return "/members/viewMembers";
}

 

스프링 DB 접근 기술

JPA

기존의 반복 코드는 물론이고, 기본적인 SQL도 JPA가 직접 만들어서 실행해준다.

JPA 엔티티 매핑

@Entity
public class Member {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id; // 시스템 상에서 회원 데이터를 구분하는 key

    @Column
    private String name;
    ...

JPA 회원 리포지토리

public class JPAMemberRepository implements MemberRepository{

    private final EntityManager em;

    public JPAMemberRepository(EntityManager em) {
        this.em = em;
    }

    @Override
    public Member save(Member member) {
        em.persist(member);
        return member;
    }

    @Override
    public Optional<Member> findById(Long id) {
        Member member = em.find(Member.class, id);
        return Optional.ofNullable(member);
    }

    @Override
    public Optional<Member> findByName(String name) {
        Member member = em.find(Member.class, name);
        return Optional.ofNullable(member);
    }

    @Override
    public List<Member> findAll() {
        // 기존의 쿼리와 다르게 Member로 부터 받아온 객체를 그대로 사용한다.
        return em.createQuery("select m from Member m", Member.class)
                .getResultList();
    }
}
  • EntityManager : Entity 관리(모든 JPA의 동작은 Entity를 기준으로 돌아간다.)
  • JPA는 기존의 쿼리 형식과 다르게 Member로부터 받아온 객체를 그대로 사용한다.
    (select key, value from Member --> select m from Member (as) m)

서비스 계층에 트랜잭션 추가

import org.springframework.transaction.annotation.Transactional

@Transactional
public class MemberService {}
  • JPA를 통한 모든 데이터 변경은 트랜잭션 안에서 실행해야 한다.

JPA를 사용하도록 스프링 설정 변경

@Configuration
public class SpringConfig {

    private EntityManager em;

    @Autowired
    public SpringConfig(EntityManager em) {
        this.em = em;
    }

    @Bean
    public MemberService memberService() {
        return new MemberService(memberRepository());
    }

    @Bean
    public MemberRepository memberRepository() {
        return new JPAMemberRepository(em);
    }
}

 

스프링 데이터 JPA

  • 인터페이스를 통한 기본적인 CRUD
  • findByName 등 메서드 이름 만으로 조회 기능 제공
  • 페이징 기능 자동 제공

스프링 데이터 JPA 회원 리포지토리

public interface SpringDataJpaMemberRepository extends JpaRepository<Member, Long> , MemberRepository{}

스프링 데이터 JPA 회원 리포지토리를 사용하도록 스프링 설정 변경

@Configuration
public class SpringConfig {
    public MemberRepository memberRepository;

    @Autowired
    public SpringConfig(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    @Bean
    public MemberService memberService() {
        return new MemberService(memberRepository);
    }
}

JPA  제공 클래스

public interface JpaRepository<T, ID> extends ListCrudRepository<T, ID>, ListPagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {}

 

반응형