Dependency Injection
Spring Container
에 저장된 객체를 가져오는 방식이다.
javax.inject.Inject
- 타입(class)이 일치하는 객체를 찾아서 가져온다.
- 동일한 타입(class)의 객체가 2개 이상 있다면 이름(id)이 일치하는 객체를 가져온다.
- 타입(class)과 이름(id)이 일치하는 Bean이 없는 경우 오류가 발생한다.
- 가져올 객체의 이름(id)을 지정하기 위해서
@Named(javax.inject.Named)
를 사용할 수 있다.필요한 디펜던시
<dependency> <groupId>javax.inject</groupId> <artifactId>javax.inject</artifactId> <version>1</version> </dependency>
javax.annotation.Resource
- 이름(id)이 일치하는 객체를 찾아서 가져온다.
- 동일한 이름(id)을 가진 객체가 없으면 오류가 발생한다.필요한 디펜던시(Javax Annotation API)
<dependency> <groupId>javax.annotation</groupId> <artifactId>javax.annotation-api</artifactId> <version>1.3.2</version> </dependency>
org.springframework.beans.factory.annotation.Autowired
@Inject
기반의 Spring Annotation이다. (타입 기반)
- 타입(class)이 일치하는 객체를 찾아서 가져온다.
- 동일한 타입(class)의 객체가 2개 이상 있다면 이름(id)이 일치하는 객체를 가져온다.
- 타입(class)과 이름(id)이 일치하는 Bean이 없는 경우 오류가 발생한다.
- 가져올 객체의 이름(id)을 지정하기 위해서
@Qualifier(org.springframework.beans.factory.annotation.Qualifier)
를 사용할 수 있다.
<bean>
태그@Configuration
+@Bean
@Component
- 클래스 레벨의 Annotation
@Component
가 추가된 클래스는 자동으로 Spring Container에 객체로 저장된다.- Controller의
@Controller
와 Service의@Service
와 DAO의@Repository
는 모두@Component
를 가지고 있다.
- 필드에 주입하기
- 생성자에 주입하기
- Setter 형식의 메소드에 주입하기
┌-- Spring Container --┐
│ BoardDto boardDto1 │
│ BoardDto boardDto2 │
└----------------------┘
@Autowired
가 명시된 필드로 Bean을 가져옴- 모든 필드마다
@Autowired
를 명시해야 함- IoC Container에 생성된 Bean이 없어도 코드 작성 시 NULL 여부를 체크하지 않아서 위험할 수 있음
- 코드 작성 시 순환 참조 여부를 미리 확인할 수 없음
@Autowired private BoardDto boardDto1; // Spring Container에 BoardDto 타입의 객체가 2개가 있으므로 이름이 일치하는 boardDto1 객체를 가져온다. @Autowired private BoardDto boardDto2; // Spring Container에 BoardDto 타입의 객체가 2개가 있으므로 이름이 일치하는 boardDto2 객체를 가져온다. @Autowired @Qualifier(value="boardDto1") // 가져올 객체 이름을 boardDto1으로 지정한다. private BoardDto b1; @Autowired @Qualifier(value="boardDto2") // 가져올 객체 이름을 boardDto1으로 지정한다. private BoardDto b2;
@Autowired
가 명시된 세터의 매개변수로 Bean을 가져옴- 세터에
@Autowired
를 한 번만 명시하면 모든 매개변수로 Bean을 가져오기 때문에 편리함- Field Injection처럼 IoC Container에 생성된 Bean이 없어도 코드 작성 시 NULL 여부를 체크하지 않아서 위험할 수 있음
- 코드 작성 시 순환 참조 여부를 미리 확인할 수 없음
private BoardDto boardDto1; private BoardDto boardDto2; @Autowired public void setBean(BoardDto boardDto1, BoardDto boardDto2) { // Spring Container에 저장된 객체를 매개변수로 가져온다. this.boardDto1 = boardDto1; this.boardDto2 = boardDto2; }
- 생성자(Generate constructor using field)를 만들면 생성자의 매개변수로 Bean을 가져옴
@Autowired
를 명시할 필요가 없음
private BoardDto boardDto1; private BoardDto boardDto2; @Autowired // 스프링 4 이후 생략 가능 public BoardController(BoardDto boardDto1, BoardDto boardDto2) { // Spring Container에 저장된 객체를 매개변수로 가져온다. this.boardDto1 = boardDto1; this.boardDto2 = boardDto2; }
- Constructor Injection에 잘못된 부분이 있는 경우 컴파일 오류가 발생함
- 3가지 DI 방식 중 가장 안전한 방식
Controller의 Constructor Injection 예시
- 클래스 레벨 애노테이션
@Component
가 명시된 클래스는 자동으로 Bean으로 등록됨@Component
가 명시된 클래스를 찾기 위해서는 반드시 미리 컴포넌트를 찾을 위치를 등록해야 하는데,
이를 Component Scan이라고 함- Spring Legacy Project는
servlet-context.xml
에 Component Scan이 등록되어 있어 별도의 설정이 필요 없고,- Spring Boot Project는
@SpringBootApplication
에 Component Scan이 포함되어 있어 별도의 설정이 필요 없다.- 스프링에서 가장 권장하는 Bean 생성 방식이다.
Component Scan
@Component의 계층 구조
Annotation | 의미 |
---|---|
@Component | • 스테레오 타입의 최상의 객체 |
@Controller | • 요청과 응답을 처리하는 Controller 클래스에서 사용 |
• Spring MVC 아키텍처에서 자동으로 Controller로 인식됨 | |
@Service | • 비즈니스 로직을 처리하는 Service 클래스에서 사용 |
• Service Interface를 구현하는 ServiceImpl 클래스에서 사용 | |
@Repository | • 데이터베이스 접근 객체(DAO)에서 사용 |
• 데이터베이스 처리 과정에서 발생하는 예외를 변환해주는 기능을 포함함 |
- 보안 문제를 방지
- final field의 값은 반드시 채워줘야 한다.
- field에 final 처리 시 생성자만 사용 가능해진다.
- 생성자
@Autowired
는 스프링 버전4 이상부터 생략이 가능하다.- 생성자는 Lombok Annotation으로 대체 가능하다.
@RequiredArgsConstructor
: final field 전용 생성자 Annotation(필수주입)- 오류발생 여부 처리 유무의 존재만 다를 뿐
@AllArgsConstructor
와 동일하게 사용 가능하다.
@Autowired
는@Inject
의 스프링화 라고 볼 수 있다.@Component
: 직접 만든 클래스에 사용하는게 편리하고, 가져오는 것들(만들어져 있는 클래스들)은 객체화 시킬 때
(1)<bean>
태그
(2)@Configuration
+@Bean
(3)@Component
방식을 사용순서
- 스프링 컨테이너에 담아두기(저장) 👉
Component
- 스프링 컨테이너에서 가지고 오기 👉
Autowired
- 생성자와 Setter에
@Autowired
를 붙여서 작동하는 방식: 실제로는 매개변수로 주입된다.- 월컴 페이지를 담당하는
Controller
와 실제 기능을 담당하는Controller
는 따로 생성하기
@RequestMapping()
메소드- 클래스 레벨 Annotation
- 공통된 Mapping 값이 모든 메소드에서 반복으로 요청될 때 사용한다.
- 해당 값이 모든 메소드의 요청에 자동으로 삽입된다.
- value만 있을때
value=
는 생략 가능하다.예)
// "/blog"로 시작하는 요청을 처리하는 컨트롤러가 된다. @RequestMapping("/blog") // == @RequestMapping(value="/blog")