참고 도서 : 스프링5 프로그래밍 입문 - 최범균 저 |
ch03. 스프링 DI
<객체 의존과 의존 주입(DI) >
-의존 : 객체 간 의존 -의존 주입 : 의존하는 대상을 주입하는 것 //결국 객체 의존 위해서 의존 주입을 하는 것 |
#[객체 의존]
: 한 클래스 내부에서 다른 클래스 객체를 생성 후 -> 그 클래스의 메소드를 활용하는 것
import java.time.LocalDateTime;
public class MemberRegisterService { //회원 가입 처리 클래스
//필드
private MemberDao memberDao = new MemberDao(); //(1) 직접 의존 객체 생성
//메소드
public void regist(RegisterRequest req) { //회원 등록 메소드
//이메일로 회원 데이터 조회
Member member = memberDao.selectByEmail(req.getEmail());
if(member != null) { //기존 데이터에 이미 존재하는 이메일이면 예외처리
throw new DuplicateMemberException("dup email"+ req.getEmail());
}
//기존 데이터에 존재하지 않는 이메일이면 DB에 삽입
Member newMember = new Member(req.getMail(),req.getPassword(),req.getName(),LocalDateTile.now());
memberDao.insert(newMember);
}
}
-이 클래스 내부에서는 DB 처리를 위해 (외부의) MemberDao클래스를 new 연산자로 직접 생성한 뒤, 해당 클래스의 메소드를 사용즉, 객체 의존 상태에 있다. 이 경우, 기존 클래스 객체 생성 시 -> 내부에서 사용된 의존 객체도 함께 생성된다. |
#[의존 주입]
<의존 객체 주입> : 서로 다른 두 객체를 조립하는 것
(1) 클래스 내부에서 직접 의존 객체 생성 : new 연산자로 직접 생성하는 방법
- 재사용 X, 코드 변경 시 불편함
(2) DI 방식 이용하여 의존 객체 생성 : 의존 객체를 전달받는 방법
- 재사용 O, 코드 변경 유연함
① 클래스 내부에 생성자(의존 객체) 인수로 넣어서 선언 : 생성자를 통해 의존 객체를 주입 받는 것 : 기존 클래스의 객체 생성 시 인수로 의존 객체를 넣어서 생성 |
② 클래스 내부에서 set_(의존 객체) 인수로 넣어서 선언 : Setter()메소드 통해 의존 객체를 주입 받는 것이다. |
[DI 장점 : 의존 객체 변경의 유연함]
(1) 직접 의존 객체 생성할 경우
-> 의존 객체 변경 시, 번거롭게 직접 new로 생성해줬던 의존 객체 모두 고쳐주어야 함
(2) DI방식 이용하여 의존 객체 생성
-> 의존 객체 변경 시, 생성자/Setter 의 인수로 넘겨주는 의존 객체 타입만 변경
-> 즉, 의존 객체 주입하는 코드 한 부분만 변경
//DI 의존 주입 코드
MemberDao memberDao = new MemberDao(); //의존 객체 생성 -> 이 부분만 수정하면 됨
MemberRegisterService regSvc = new MemberRegisterService(memberDao);
//기존 객체 생성자에 의존객체 주입
ChangePasswordService pwdSvc = new ChangePasswordService(memberDao);
//기존 객체 생성자에 의존객체 주입
[객체 조립기]
-의존 객체 주입해주는 코드만 모아놓은 클래스
-의존 객체 생성 후 기존 객체에 의존 객체 주입 기능 제공
*의존, DI, 조립기에 대해 먼저 알아본 이유는 ‘스프링’이 DI를 지원하는 조립기이기 때문 !!!!!!!!!!!!!!!!!!!!1 |
...! Spring 진짜 시작 ...! |
[스프링의 DI 설정] : [ 스프링 설정 클래스 작성 -> 스프링 컨테이너 생성 -> getBean() ]
- 스프링 = DI를 지원하는 범용 객체 조립기 (사용할 객체를 빈 객체로 등록해서 의존 객체로서 사용) |
① 스프링 설정 클래스 생성: ‘설정 정보’ 작성 | @Configuration
: 스프링이 어떤 객체를 생성하고 의존 어떻게 주입할지 정의한 정보 : 이 클래스 내부에서 @Bean 애노테이션을 토대로 해당 메소드가 생성한 객체를 스프링 빈 객체로 설정한다. 즉, 사용할 의존객체를 빈 객체로 설정 |
② 스프링 컨테이너 생성 : 설정 클래스를 이용 -> 스프링 컨테이너 생성
: 설정 정보를 토대로 실질적으로 객체 생성하고 의존 객체 주입하는 역할은 스프링 컨테이너가 하므로, AnnotationConfigApplicationContext 클래스로 스프링 컨테이너 생성 //이 클래스 객체 생성자 인수로 설정클래스를 넣어준다. //설정 파일로부터 생성할 객체와 의존 주입 대상을 정한다. |
③ getBean() 이용
> 사용할 빈 객체 가져옴 : 위에서 생성했던 스프링 컨테이너 속에서 getBean() 하여 빈 객체를 구함 |
[스프링의 DI 방식]
① 생성자 DI 방식
: 빈 객체 생성 시점에 모든 의존 객체가 주입된다.
- 스프링 설정 클래스에서 생성자를 이용하여 의존 객체를 주입하기 위한 DI 설정해둔 @Bean 메소드 대상으로 getBean() 호출 시-> 빈 객체 생성 시점에 의존 객체 주입됨
@Bean
public MemberRegisterService memberRegSvc() {
return new MemberRegisterService(memberDao()); //생성자 인수에 의존 객체 주입 설정
}
- 의존 객체 2개 이상인 경우에도 동일하게 주입 설정 코드 작성하면 됨
@Bean
public MemberListPrinter listPrinter() {
return new MemberListPrinter(memberDao(), memberPrinter());
//생성자 인수에 의존 객체 주입 설정
}
② Setter 메소드 DI 방식
: 세터 메서드 이름을 통해 주입되는 의존 객체 정보 집작 가능
-자바빈 규칙: Stter메소드 파라미터 1개
//Setter() 이용 -> 의존 객체 주입받는 코드
public void setMemberDao(MemberDao memberDao) {
this.memDao - memberDao;
}
//Setter() 이용 -> 의존 주입 설정 코드
@Bean
public MemberBerInfoPrinter infoPrinter() {
MemberInfoPrinter infoPrinter = new MemberInfoPrinter();
infoPrinter.setMemberDao(memberDao());
return infoPrinter;
}
[빈으로 등록한 객체의 기본 데이터 타입 값 설정]
두 개의 int 값 필드를 갖던 클래스를 빈 객체로 설정할 때 값 설정 가능 자바빈에서는 Getter,Setter를 이용해서 프로퍼티를 정의한다. |
//빈 등록할 객체
public class VersionPrinter {
//필드
private int majorVersion;
private int minorVersion;
//...
//Setter()
public setMajorVersion(int majorVersion) {
this.majorVersion = majorVersion;
}
public setMinorVersion(int minorVersion) {
this.minorVersion = minorVersion;
}
}
---------------------------------------------------------------------
//스프링 설정 클래스
@Configuration
public class AppCtx {
...
@Bean
public VersionPrinter versionPrinter() {
VersionPrinter versionPrinter = new VersionPrinter();
versionPrinter.setMajorVersion(5); //빈 객체의 기본 데이터값 설정
versionPrinter.setMinorVersion(0); //빈 객체의 기본 데이터값 설정
return versionPrinter;
}
}
[스프링과 싱글톤]
-스프링 컨테이너가 생성한 빈은 싱글톤 객체 -스프링 컨테이너는 @Bean 메소드에 대해 한 개의 객체만 생성한다. -즉, 다른 설정 메소드에서 동일한 @Bean 메소드를 여러 번 호출하더라도 항상 같은 객체를 리턴한다는 것. -그러므로 스프링이 런타임에 생성한 설정 클래스의 메소드가 매번 새로운 객체를 생성 X - 대신 한 번 생성한 객체를 보관했다가 이후에 동일 객체를 리턴한다. |
[두 개 이상의 설정 (클래스) 파일 사용]
-스프링 개발 시 수백 개 이상의 빈을 설정하게 되는데, 관리하기 쉽게 영역별로 설정 파일을 나누는 일 多 -스프링은 한 개 이상의 설정 파일을 이용해서 컨테이너를 생성할 수 있다. |
① @Autowired 애노테이션
- 스프링의 자동 주입 기능을 위한 것 - 스프링 빈에 의존하는 다른 빈을 자동 주입하고 싶을 때 사용 - 다른 설정 파일에 정의한 빈을 필드에 할당시킴. -> 필드에 할당받은 것을 이용해서 내부에 필요한 빈을 주입하면 된다. - 스프링 컨테이너는 @Configuration 설정 클래스 내부를 전체적으로 스프링빈으로 등록하기 때문에, 필드에 붙인 @Autowired 대상도 자동적으로 빈으로 등록함 |
@Autowired
private MemberDao memberDao; //외부 다른 설정 파일에 정의된 빈을 필드에 할당
@Autowired
private MemberPrinter memberPrinter;
...
@Bean
public MemberListPrinter listPrinter() {
return new MemberListPrinter(memberDao, memberPrinter);
//필드에 할당받은 빈을 주입
② @import 애노테이션
- 함게 사용할 설정 클래스를 지정함 @import(AppConf2.class) - 배열을 이용해서 두 개 이상의 설정 클래스도 지정 O @import( { AppConf1.class, AppConf2.class } ) |
[getBean() 메소드의 사용]
- 컨테이너.getBean( 빈 이름, 빈 타입); - 존재하지 않는 빈 이름 사용 시 오류 - 지정 타입 옳지 않으면 오류 - 해당 타입의 빈 객체가 한 개만 존재할 경우, 빈 이름 지정 없이 빈 타입만으로도 빈 구할 수 있다. : getBean(빈 타입) |
[주입 대상 객체가 모두 빈 객체일 필요는 없다]
-스프링 설정 클래스에서 주입할 객체에는 빈 등록 없이 일반 객체로 생성하여 주입도 O * 차이는 ? : 스프링 컨테이너가 객체를 관리하는지 여부 - 빈으로 등록하지 않은 일반 객체의 경우, 스프링 컨테이너로 getBean() 해도 구할 수 X - 스프링 컨테이너는 객체 관리를 오직 빈으로 등록된 객체를 대상으로만 기능 적용 O (자동 주입, 관리, 빈 객체 생성 등) |
'Web(웹)_관련 공부 모음 > [개념]_스프링 5 프로그래밍' 카테고리의 다른 글
ch06. 빈 라이프사이클과 범위 (0) | 2022.01.27 |
---|---|
ch05. 컴포넌트 스캔 (0) | 2022.01.26 |
ch04. 의존 자동 주입 (0) | 2022.01.26 |
ch02. 스프링 시작 (0) | 2022.01.24 |
ch01. 스프링 기본 설명 (0) | 2022.01.24 |