
Spring Framework에서는 DI, IoC, AOP가 3가지는 핵심 도구이다.
AppConfig 예시
public class AppConfig {
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
public OrderService orderService() {
return new OrderServiceImpl(
memberRepository(),
discountPolicy());
}
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
public DiscountPolicy discountPolicy() {
return new FixDiscountPolicy();
return new RateDiscountPolicy();
}
}
AppConfig처럼 객체를 생성하고 관리하면서 의존 관계를 연결해 주는 것을 IoC 컨테이너 또는 DI 컨테이너라 한다.프레임워크 VS 라이브러리
- 제어의 역전은 라이브러리와 프레임워크의 구분 기준이 될수도 있다.
- 프레임워크가 내가 작성한 코드를 제어하고,대신 실행하면 그것은 프레임워크
- 반면에 내가 작성한 코드가 직접 제어의 흐름을 담당하면 그것은 프레임워크가가 아니라 라이브러리
IoC가 필요한 이유?
- 객체를 관리해주는 프레임워크와 내가 구현 하고자 하는 부분으로 역할과 관심을 분리해 응집도를 높이고 결합도를 낮추며, 이에 따라 변경에 유연한 코드를 작성 할 수 있는 구조가 될 수 있기 때문에 제어를 역전한 것이다.
- "스프링 컨테이너에서 객체 Bean을 먼저 생성해두고 생성한 객체를 지정한 객체에 주입하는 방식을 의존성 주입 이라고 한다."
- 제어의 역전을 구현하기 위해 사용하는 방법이 DI
@Controller
public Class MemberController {
@Autowired
MemberService service;
}
@Autowired를 부여하는 방식
- 가장 코드가 짧고 주입하기도 간편하고 보기에도 직관적이지만, 현재 가장 위험성이 많은 방식이다.
- IntelliJ에서 필드 주입 사용하면 Field injection is not recommended이라는 경고 문구가 발생한다.
- 외부에서 접근이 불가능하다는 단점이 존재하는데, 테스트 코드의 중요성이 부각됨에 따라 필드의 객체를 수정할 수 없는 필드 주입은 거의 사용되지 않게 되었다.
- 필드 주입은 반드시 DI 프레임워크가 존재해야 하므로 반드시 사용을 지양
@Controller
public class MemberController{
private MemberService memberService;
@Autowired
public void setmemberService(MemberService memberService){
this.memberService = memberService;
}
}
하지만 실제 개발에서는 의존 관계 주입의 변경이 필요한 상황이 거의 없으며, 수정자 주입을 사용하게 되면 불필요하게 객체의 수정 가능성을 열어두게 되는데, 이는 OOP(객체 지향 프로그래밍)의 5가지 개발 원칙 중에 OCP(Open-Closed Principal, 개방-폐쇄 원칙)를 위반하게 된다.
따라서 수정자 주입이 아닌 생성자 주입을 통해 변경의 가능정을 배제하고, 불변성을 보장하는 것이 좋다.
@Controller
public class MemberController{
private final MemberService memberService;
@Autowired
public MemberController(MemberService memberService){
this.memberService = memberService;
}
}
@Controller
@RequiredArgsConstructor
public class MemberController{
private final MemberService memberService;
}
@RequiredArgsConstructor 로 필드를 포함한 생성자를 포함시켜주고 @Autowired 키워드를 생략해서 더 가독성이 좋은 코드로 사용이 가능
스프링 컨테이너
- ApplicationContext를 스프링 컨테이너라 한다.
- 스프링 컨테이너는 @Configuration이 붙은 AppConfig를 설정(구성) 정보로 사용한다.
- 여기서 @Bean이라 적인 메서드를 모두 호출해서 반환된 객체를 스프링 컨테이너에 등록한다.이렇게 스프링 컨테이너에 등록된 객체를 스프링 빈이라 한다.
- ApplicationContext는 인터페이스다.

new AnnotationConfigApplicationContext(AppConfig.class)
빈 이름
- 빈 이름은 메서드 이름을 사용한다.
- 빈 이름을 직접 부여할 수 도 있다.
- 반드시 항상 다른 이름을 부여


빈(Bean)
- 스프링 컨테이너에 의해 관리되는 재사용 가능한 소프트웨어 컴포넌트이다.
즉, 스프링 컨테이너가 관리하는 자바 객체를 뜻하며, 하나 이상의 빈(Bean)을 관리한다.
스프링 빈(Bean) 사용이유 ?
- 큰 이유는 스프링 간 객체가 의존관계를 관리하도록 하는 것에 가장 큰 목적이 있다. 객체가 의존관계를 등록할 때 스프링 컨테이너에서 해당하는 빈을 찾고, 그 빈과 의존성을 만든다.
스프링 빈(Bean) 등록 방법
Spring Bean을 등록하는 방법은 대표적으로 3가지 정도가 있다.
- xml에 직접 등록
- @Bean 어노테이션을 이용
- @Component, @Controller, @Service, @Repository 어노테이션을 이용
ac.getBeanDefinitionNames() : 스프링에 등록된 모든 빈 이름 조회ac.getBean() : 빈 이름으로 빈 객체(인스턴스) 조회getRole()ROLE_APPLICATION : 일반적으로 사용자가 정의한 빈ROLE_INFRASTRUCTURE : 스프링이 내부에서 사용하는 빈