[Spring] 의존성 주입(Dependency Injection)

[Spring] 의존성 주입(Dependency Injection)

의존성 주입(Dependency Injection)

하나의 객체가 다른 객체의 의존성을 제공하는 테크닉을 보고 의존성 주입(Dependency Injection)이라고 합니다. 객체의 생성과 사용의 관심을 분리하기 위해서 제안된 테크닉입니다. 직접 코드로 보시는게 조금 더 좋을 것 같아서 바로 예제 코드를 보여드리겠습니다.

Member

//단순하게 보여드리기 위해서 에노테이션, import 등의 일부를 생략했습니다 public class Member { private Long id; private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } }

위와 같은 코드의 Member 객체가 도메인에 있다고 가정해 보겠습니다. 이어서, 이러한 멤버를 저장하는 Repository를 보여드리겠습니다.

SpringDataJpaMemberRepository

//단순하게 보여드리기 위해서 에노테이션, import 등의 일부를 생략했습니다 public interface SpringDataJpaMemberRepository extends JpaRepository, MemberRepository { @Override Optional findByName(String name); }

MemberRepository에서 Member라는 객체를 사용하고 있죠? 이러한 것을 보고 의존성이라고 부릅니다! MemberRepository 클래스는 Member 객체 없이는 제 역할을 못하고 있거든요. 자 그럼 Member라는 객체가 있고, 이러한 객체를 저장하는 Repository까지 만들었으니 이를 활용해서 서비스를 제공하는 Service 객체가 있어야 할 것 입니다.

MemberService

//단순하게 보여드리기 위해서 에노테이션, import 등의 일부를 생략했습니다 public class MemberService { Member member1; Member member2; MemberRepository memberRepository = new MemberRepository(); memberRepository.save(member1); memberRepository.save(member2); ... }

위 코드와 같이 서비스를 구현하기 위해서, MemberRepository를 필요로 하고, 결국 MemberRepository 내부에 Member를 주입하게 되는데, 이렇게 되면 각 서비스 모델을 구현할 때 마다 새로운 객체를 만들어서 코드 내부에서 일일히 주입해야하는 불편함이 생기게 됩니다.

또한, A라는 서비스에서 사용한 Repository를 B라는 서비스에서도 사용하기 위해서는 같은 Repository를 주입해야 하는데, 이를 코드로 구현한다고 가정했을 때 만약 서비스의 규모가 엄청 크다면 되게 복잡한 코드를 가질 수 밖에 없습니다.

이러한 점을 해결하고자 제안된 테크닉이 바로 의존성 주입(Dependency Injection)입니다! 위에서의 Service 클래스를 아래와 같이 조금 변경해 보겠습니다.

@Transactional public class MemberService { private final MemberRepository memberRepository; @Autowired public MemberService(MemberRepository memberRepository) { this.memberRepository = memberRepository; } }

차이가 보이시나요? MemberService 객체의 MemberRepository가 외부에서 받아서 저장해 주는 방식으로 코드가 바뀌었습니다! 이러한 것을 보고 Dependency Injection이라고 부릅니다. 또한 MemberService 클래스에서 MemberRepository를 final로 선언하였기 때문에 서비스 내부에서 MemberRepository의 값을 강제로 변경되지 않도록 할 수도 있습니다!

DI 구현 방법

이러한 의존성 주입을 구현하는 데에는 크게 3가지가 있습니다!

Constructor injection(생성자 주입)

Setter Injection (setter 주입)

field Injection (변수를 통한 주입)

가장 선호되는 방법은 가장 위에 있는 **Constructor injection** 방법입니다 Setter Injection의 경우 setter 메소드가 public하게 열려있기 때문에 누구나 접근할 수 있고, 이 때문에 어느곳에서나 메소드의 호출이 가능하기 때문에 권장하지 않고, field Injection이 위에서 소개된 방법인데 일일히 변수를 생성해서 주입하다보면 서비스의 규모가 커졌을 때는 오류를 범하기가 상당히 쉽습니다.

실무에서는 주로 정형화된 컨트롤러, 서비스. 레포지토리 같은 코드는 **Component Scan**을 사용한다고 합니다. 만약 정형화되지 않거나 상황에 따라 변경해야 하는 경우는 자바 코드로 직접 스프링 빈에 등록하여 사용합니다.

from http://hwanld.tistory.com/10 by ccl(A) rewrite - 2021-12-31 13:01:57