Spring
[WIL] 🍃 의존성 주입(DI)과 제어의 역전(IoC) 그리고 스프링 빈(Spring Bean)
- -
반응형
📌 Intro
- 항해99를 시작한지 이제 4주차가 된다. 3주차 주특기 입문에서 처음으로 Spring을 사용해봤다. Spring이 어렵다고 이야기만 들었는데 생각보다 너무 편하다. 하지만 편한만큼 내부적으로 어떻게 동작하는지 잘 이해가가지 않는 단점이 있다. 이제 Spring을 제대로 공부할 시간이 4주차 5주차 2주간의 시간이 남았는데 인프런의 Spring강의를 구매해서 들어볼까 고민중이다.
- Spring에서 중요한 개념 3가지를 한 번 정리해볼까한다.
1. DI(의존성 주입)
의존성 주입( Dependency Injection ) : 하나의 객체가 다른 객체의 의존성을 제공하는 테크닉이다.
- 의존성 주입의 의도는 객체의 생성과 사용의 관심을 분리하는 것이다. 이는 가독성과 코드 재사용을 높혀준다.
- 의존성 주입은 아래와 같은 문제를 해결한다.
- 어떻게 애플리케이션이나 클래스가 객체의 생성 방식과 독립적일 수 있는가?
- 어떻게 객체의 생성 방식을 분리된 구성 파일에서 지정할 수 있는가?
- 어떻게 애플리케이션이 다른 구성을 지원할 수 있는가?
- 프로그램 디자인이 결합도를 느슨하게 되도록하고 의존관계 역전 원칙과 단일 책임 원칙을 따르도록 클라이언트(수신객체)의 생성에 대한 의존성을 클라이언트의 행위로부터 분리하는 것이다.
- 의존성 주입의 기본 단위인 주입은 새롭거나 관습적인 메커니즘이 아니다. "매개변수 전달"과 동일하게 동작한다.
- 서비스를 사용하려는 클라이언트(수신 객체)가 해당 서비스의 구성방법을 알 필요가 없게 하는 것.
- 의존성 주입은 프레임워크가 아닌 디자인 패턴, IoC 방법 중 하나.
- 의존성 주입은 컴파일타임이 아닌 런타임에 종속성을 해결하는 데 사용됨.
- 무언가를 쉽게 교체할 수 있게 만들어준다.
장점
- 모듈들을 쉽게 교체할 수 있는 구조 -> 테스팅이 쉽고 마이그레이션하기도 쉽다.
- 구현할 때 추상화 레이어를 넣고 이를 기반으로 구현체를 넣어주기 때문에 어플리케이션 의존성 방향이 일관되고, 어플리케이션을 쉽게 추론 가능. 👉🏻 모듈 간 관계가 조금 더 명확해짐.
단점
- 모듈들의 분리가 증가 -> 클래스 수 증가 -> 복잡성이 증가됨.
- 복잡성이 증가됨에 따라 약간의 런타임 페널티가 생기기도 한다.
- 종속성은 런타임에서 해결되기 때문에 종속성 오류는 컴파일 시간에 포착할 수 없다.
의존성 주입 사용법
Lombok없이
@Controller
public class MemberController {
private final MemberService memberService;
@Autowired
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
@PostMapping("members/new")
public String create(MemberForm form){
Member member = new Member();
member.setName(form.getName());
memberService.join(member);
return "redirect:/";
}
}
- 클라이언트(수신객체)에 사용할 memberService를 private final 키워드를 사용해 선언.
- 생성자로 의존성 주입 후 해당 메소드 위에 @Autowired 어노테이션 추가
public MemberController(MemberService memberService) { this.memberService = memberService; }
Lombok활용
@RestController
@RequiredArgsConstructor
public class PostController {
private final PostRepository postRepository;
private final PostService postService;
@PostMapping("/posts")
public Post createPost(@RequestBody PostRequestDto requestDto){
Post post = new Post(requestDto);
return postRepository.save(post);
}
}
- 클라이언트(수신객체)에 사용할 postRepository, postService를 private final 키워드를 사용해 선언.
- Controller 클래스 위에 @RequiedArgsConstructor 어노테이션 추가만 해주면 됨.
2. IoC(제어의 역전)
제어의 역전( Inversion of Control ) : 프로그래머가 작성한 프로그램이 재사용 라이브러리의 흐름 제어를 받게 되는 소프트웨어 디자인 패턴을 말한다.
- 제어의 역전은 의존성 주입의 상위 개념이다.
- Spring Container가 필요에 따라 개발자 대신 Bean들을 관리(제어)해주는 행위
- Spring Container는 기본적으로 싱글톤 패턴의 객체 생성을 지향한다.
- 별도로 설정하지 않으면 모든 컨테이너 안의 빈(Bean) 객체는 딱 하나만 생성되어 계속 재사용된다. Why? 내부 데이터가 바뀌지 않는 객체들을 여러 개 생성해서 사용하는 것은 자원 낭비이기 때문이다.
- 그래서 스프링 컨테이너를 싱글톤 관리 컨테이너라고 부르는 사람들도 있는 것 같다.
- 일반적인 상황에서는 개발자가 직접 객체를 제어해야 했다. new 연산자를 통해 객체를 생성하고, 객체의 의존성을 맺어주고, 초기화를 해주고 등등..
- Spring 에서는 xml파일 또는 어노테이션 방식으로 스프링 컨테이너에 Bean(객체)를 등록하기만 하면, 스프링 컨테이너에서 Bean의 생명주기(생성 -> 의존성 설정 -> 초기화 -> 소멸)를 전부 관리해준다.
- 즉, 객체에 대한 제어권이 컨테이너로 역전되기 때문에 제어의 역전이라고 하는 것
- 일반적으로 처음에 배우는 자바 프로그램에서는 각 객체들이 프로그램의 흐름을 결정하고 각 객체를 직접 생성하고 조작하는 작업(객체를 직접 생성하여 메소드 호출)을 했다. 즉, 모든 작업을 사용자가 제어하는 구조였다.
- 예를 들어 A 객체에서 B 객체에 있는 메소드를 사용하고 싶으면, B 객체를 직접 A 객체 내에서 생성하고 메소드를 호출한다.
- 하지만 IOC가 적용된 경우, 객체의 생성을 특별한 관리 위임 주체에게 맡긴다. 이 경우 사용자는 객체를 직접 생성하지 않고, 객체의 생명주기를 컨트롤하는 주체는 다른 주체가 된다.
- 즉, 사용자의 제어권을 다른 주체에게 넘기는 것을 IOC(제어의 역전) 라고 합니다.
장점
- 개발자는 객체 관리에 덜 신경쓸 수 있게 된다.
- 약한 결합을 이용하여 객체 간 의존 관계를 쉽게 변경할 수 있다.
- 결과적으로 코드의 재사용성과 유지보수성을 높인다.
3. Spring Bean(스프링 빈)
스프링 빈(Spring Bean) : Spring IoC 컨테이너가 관리하는 자바 객체를 말한다.
- 우리가 알던 기존의 Java Programming 에서는 Class를 생성하고 new를 입력하여 원하는 객체를 직접 생성한 후에 사용했었다.
- 하지만 Spring에서는 직접 new를 이용하여 생성한 객체가 아니라, Spring에 의하여 관리당하는 자바 객체를 사용한다. 이렇게 Spring에 의하여 생성되고 관리되는 자바 객체를 Bean이라고 한다.
- Spring Framework 에서는 Spring Bean 을 얻기 위하여 ApplicationContext.getBean() 와 같은 메소드를 사용하여 Spring 에서 직접 자바 객체를 얻어서 사용합니다.
3-1 Spring Bean을 Spring IoC Container에 등록하는 방법
- Spring Bean을 Spring IoC Container에 등록하는 방법은 2가지가 있다.
3-1-1 자바 어노테이션(Java Annotation)을 사용하는 방법
- 자바 어노테이션 참고!
- JAVA에서 어노테이션 이라는 기능이 있다. 사전상으로는 주석의 의미이지만 Java 에서는 주석 이상의 기능을 가지고 있다.
- 어노테이션은 자바 소스 코드에 추가하여 사용할 수 있는 메타데이터의 일종이다.
- 소스코드에 추가하면 단순 주석의 기능을 하는 것이 아니라 특별한 기능을 사용할 수 있다.
- 어노테이션 예제
- Java에서는 @Override, @Deprecated 와 같은 기본적인 어노테이션을 제공한다. 아래의 상속 예제에서는 @Override 를 이용하여 상속임을 명시해준다.
public class Parent { public void doSomething() { System.out.println("This is Parent"); } } public class Son extends Parent{ @Override public void doSomething() { System.out.println("This is Son"); } }
- 그럼 실제 Spring에서 어떤 어노테이션을 사용해 Bean 등록할까?
- @Component 어노테이션을 사용해 Bean을 등록한다.
- @Component 어노테이션이 등록되어 있는 경우에는 Spring이 Annotation을 확인하고 자체적으로 Bean으로 등록한다.
- Spring @Component 예제
- 왜 @Component가 없지? 라고 생각할 수 있다. 해당 부분을 확인하기 위해서 인텔리제이를 사용한다면 Ctrl을 누른 상태로 @Controller를 클릭해본다. 그럼 아래와 같은 코드를 확인할 수 있다.
- @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Controller { /** * The value may indicate a suggestion for a logical component name, * to be turned into a Spring bean in case of an autodetected component. * @return the suggested component name, if any (or empty String otherwise) */ @AliasFor(annotation = Component.class) String value() default ""; }
- 위 @Controller 어노테이션 코드에서 @Component가 있음을 확인할 수 있다.
- @Component 어노테이션을 통해 Spring은 해당 Controller를 Bean으로 등록한다.
- @Controller public class MemberController { private final MemberService memberService; @Autowired public MemberController(MemberService memberService) { this.memberService = memberService; } @GetMapping("/members/new") public String createForm(){ return "/members/createMemberForm"; } }
3-1-2. Bean Configuration File에 직접 Bean 등록하는 방법
- @Configuration과 @Bean 어노테이션을 이용하여 Bean을 등록할 수 있다.
- 아래의 예제와 같이 @Configuration을 이용하면 Spring 프로젝트에서의 Configuration 역할을 하는 Class를 지정할 수 있다.
- 해당 파일 하위에 Bean으로 등록하고자 하는 Class에 @Bean 어노테이션을 사용해주면 간단하게 Bean을 등록할 수 있다.
- @Configuration public class SpringConfig { private final DataSource dataSource; private final EntityManager em; @Autowired public SpringConfig(DataSource dataSource, EntityManager em) { this.dataSource = dataSource; this.em = em; } @Bean public MemberService memberService(){ return new MemberService(memberRepository()); } @Bean public MemberRepository memberRepository(){ return new JpaMemberRepository(em); } }
참고자료
의존성 주입
제어의 역전
- https://velog.io/@damiano1027/Spring-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85-%EC%A0%9C%EC%96%B4%EC%9D%98-%EC%97%AD%EC%A0%84
- https://codevang.tistory.com/241
스프링 빈
작성일자 : 2022년 7월 9일
반응형
Contents
소중한 공감 감사합니다