티스토리 뷰
IoC
제어의 역전(Inversion of Control)?
- 나 자신이 제어권을 가지고 있지 x, 나 이외의 누군가가 의존성에 대한 제어권을 가지고 있다.
- 어떤 객체가 사용하는 의존 객체를 직접 만들어서 사용하는게 아니라 주입 받아서 사용하는 것을 말한다.
1. 의존성에 대한 제어권
일반적인 경우
"내가 쓸 놈은 내가 만들어 쓸게"
class OwnerController {
private OwnerRepository repository = new OwnerRepository();
}
- OwnerController가 OwnerRepository를 생성한다.
- 의존성에 대한 제어권 => 본인(OwnerController)
IoC : 역전된 경우
"내가 쓸 놈은 이 놈인데... 누군가 알아서 주겠지"
class OwnerController {
private OwnerRepository repo;
public OwnerController (OwnerRepository repo) {
this.repo = repo;
}
}
OwnerController가 생성될 때 누군가가 OwnerRepository 객체를 준다.
- 의존성에 대한 제어권 => 누군가(IoC Container)
class OwnerControllerTest { public void create() { OwnerRepository repo = new OwnerRepository (); OwnerController controller = new OwnerController(repo); } }
OwnerControllerTest가 OwnerRepository를 생성해서 이를 OwnerController에 주입해준다.
- 의존성에 대한 제어권 => OwnerControllerTest
IoC의 장점
- 제어권을 자신이 아닌 별도의 IoC 컨테이너에게 넘김으로서 객체가 자신이 사용할 대상의 생성이나 선택에 관한 책임으로부터 자유로워진다.
- 인터페이스 기반으로 깔끔한 설계가 가능하고 유연성이 증가하며, 확장성이 좋아진다.
2. 애플리케이션 컨텍스트
ApplicatonContext = IoC 컨테이너 = Spring 컨테이너
스프링에서는 ApplicationContext를 IoC 컨테이너라고 한다. 간단히 Spring 컨테이너라고 한다.
public interface ApplicationContext
extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
//...
}
역할
BeanFactory
: 빈 생성 및 의존성 관리(ListableBeanFactory, HierarchicalBeanFactory)MessageSource
: 메시지 소스 처리 기능(i18n)ApplicationEventPublisher
: 이벤트 발행 기능ResourceLoader
: 리소스 로딩 기능 (ResourcePatternResolver)
3. 스프링 빈
스프링 IoC 컨테이너가 관리하는 객체를 빈(bean)이라고 한다. 따라서 IoC 컨테이너에 등록하지 않은 객체는 스프링 빈이라고 할 수 없다.
- 예시
- OwnerController(
@Controller
), OwnerService(@Service
), OwnerRepository(@Repository
)는 IoC 컨테이너에서 관리하는 빈(bean)이다. - Owner(Entity로서의 Owner)는 빈(bean)이 아니다.
- OwnerController(
빈 설정
빈에 대한 정의를 담고 있다.
- 이름 또는 id
- 클래스
- 스코프
- 생성자 아규먼트(construct)
- 프로퍼티(setter)
- 등등
스프링 빈의 장점
- 의존성 관리
- 스코프
- 싱글톤 : 하나
- 프로토타입 : 매번 다른 객체
- 라이프사이클 인터페이스 : 빈이 만들어졌을 때 부가작업을 하고 싶을 경우 사용한다.
/* 초기화 메서드. 빈이 생성되고 DI 작업을 마친다음 실행된다. */
@PostConstruct
public void postConstruct() {
System.out.println("=================");
System.out.println("Hello");
}
스프링은 스프링 IoC 컨테이너에 스프링 빈을 등록할 때, 기본으로 싱글톤으로 등록한다.(유일하게 하나만 등록해서 공유) 따라서 같은 스프링 빈이면 모두 같은 인스턴스다. 설정으로 싱글톤이 아니게 설정할 수 있지만, 특별한 경우를 제외하면 대부분 싱글톤을 사용한다.
빈을 등록하는 방법
- Component Scanning
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
// ...
}
스프링 부트에서는 @SpringBootApplication
라는 애노테이션을 사용하는데 이 애노테이션 안에 컴포넌트 스캔을 할 수 있는 @ComponentScan
이 있다.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
// ...
}
@ComponentScan
은 스캔할 패키지와 애노테이션에 대한 정보를 담고 있다. 실제 스캐닝은 ConfigurationClassPostProcessor라는 BeanFactoryPostProcesser에 의해 처리된다.
@Component
: 이 애노테이션이 있으면 컴포넌트 스캔을 통해 스프링 빈으로 자동 등록된다. 아래 애노테이션들은@Component
를 확장했기 때문에 컴포넌트 스캔 대상이 된다.@Repository
@Service
@Controller
/* Component Scan 방식으로 스프링 빈(MemberService) 등록 */ @Service public class MemberService { private final MemberRepository memberRepository; public MemberService(MemberRepository memberRepository) { this.memberRepository = memberRepository; } }
직접 xml이나 자바 설정 파일에 등록
- xml 설정 방식은 최근에는 잘 사용하지 않는다.
- 자바 설정파일에서 빈 등록시
@Bean
애노테이션을 붙여야한다.@Bean
은@Configuration
안에 정의해야 한다.
/* 자바 설정파일로 스프링 빈(MemberService) 등록 */ @Configuration public class SpringConfig { @Bean public MemberService memberService() { return new MemberService(memberRepository()); } @Bean public MemberRepository memberRepository() { return new MemoryMemberRepository(); } }
실무에서는 주로 정형화된 컨트롤러, 서비스, 리포지토리** 같은 코드는 컴포넌트 스캔을 사용한다.
정형화되지 않거나, 상황에 따라 구현 클래스를 변경해야 하면 설정을 통해 스프링 빈으로 등록한다.
빈을 가져오는 방법
@Autowired
IoC 컨테이너가 연관된 객체를 찾아서 메소드나 생성자를 통해 주입해준다. (수동적)- 객체 의존관계를 외부에서 넣어주는 것 => DI(Dependency Injection), 의존관계 주입
@Service
public class MemberService {
private final MemberRepository memberRepository;
@Autowired
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
}
ApplicationContext
의getBean()
IoC 컨테이너에게 연관된 객체를 요청해서 받는다. (능동적)- 객체 의존관계를 스스로 검색해서 넣어주는 것 => DL(Dependency Lookup),의존관계 검색
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
MemberService memberService = ctx.getBean(MemberService.class);
}
+ @Autowired를 생략해도 되는 경우
어떤 빈에
- 생성자가 오직 하나만 있고
- 파라미터로 받는 타입(매개변수 타입)의 빈이 존재한다면
@Autowired
애노테이션을 생략해도 의존성을 주입해준다. (스프링 4.3)
- 파라미터로 받는 타입(매개변수 타입)의 빈이 존재한다면
public class MemberService {
private final MemberRepository memberRepository;
//@Autowired
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
}
@Autowired를 통한 DI는 스프링이 관리하는 객체(빈)에서만 동작한다. 스프링 빈으로 등록하지 않고 내가 직접 생성한 객체에서는 동작하지 않는다.
@Autowired / @inject를 어디에 붙일까?
- 생성자
- 이 클래스에 반드시 필요한 객체다 => 생성자
- 의존관계가 실행중에 동적으로 변하는 경우는 거의 없으므로 생성자 주입을 권장한다.
- 필드
- Setter가 없다 => 필드
- Setter
- Setter가 있다 => Setter
참고자료
- 스프링 프레임워크 입문
- 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
'Spring' 카테고리의 다른 글
Spring Boot 3 + Hibernate 6 에서 SQL 로깅 설정하기 (0) | 2025.01.18 |
---|---|
Spring Retry (0) | 2025.01.12 |
JDK 다이나믹 프록시와 CGLIB 프록시 (0) | 2022.05.19 |
[Spring] AOP(Aspect Oriented Programming) 정리 (0) | 2020.10.03 |
- Total
- Today
- Yesterday
- tcp커넥션
- 엔티티와값객체
- jpa 쿼리 로그
- github actions components
- mysql 이모지
- csv 라이브러리
- 도메인구성요소
- spring boot3 쿼리 로그
- AOP
- 콜레이션변경
- CGLIB프록시
- online ddl
- 문자집합변경
- utf8mb3
- http커넥션
- 콜레이션
- mysql 온라인 ddl
- read timeout
- 쿼리 파라미터 바인딩
- hibernate 쿼리 로그
- github actions 기초
- opencsv
- csv to bean
- 코프링
- 이모지입력오류
- spring retry
- 4Way Handshake
- TCP연결
- file
- github actions 구성요소
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |