πŸ“‹ 3. μŠ€ν”„λ§ DI


μŠ€ν”„λ§μ€ 객체 μ»¨ν…Œμ΄λ„ˆ

BeanFactory

  • 객체 생성과 검색에 λŒ€ν•œ κΈ°λŠ₯ μ •μ˜
  • getBean() : μƒμ„±λœ 객체λ₯Ό κ²€μƒ‰ν•˜λŠ”λ° ν•„μš”ν•œ λ©”μ„œλ“œ
  • 객체 검색 이외에도 싱글톀인지 ν”„λ‘œν† νƒ€μž… λΉˆμΈμ§€ ν™•μΈν•˜λŠ” κΈ°λŠ₯도 있음

AnnotationContext

  • λ©”μ‹œμ§€, profile, ν™˜κ²½ λ³€μˆ˜ 등을 μ²˜λ¦¬ν•  수 μžˆλŠ” κΈ°λŠ₯을 μΆ”κ°€λ‘œ 쩑의

μ˜μ‘΄μ΄λž€?

DIλ₯Ό ν†΅ν•œ 의쑴 처리

μ˜μ‘΄μ΄λž€?

  • ν•œ ν΄λž˜μŠ€κ°€ λ‹€λ₯Έ 클래슀의 λ©”μ„œλ“œλ₯Ό μ‹€ν–‰ν•  λ•Œ μ˜μ‘΄ν•œλ‹€κ³  ν‘œν˜„
  • 변경에 μ˜ν•΄ 영ν–₯을 λ°›λŠ” 관계λ₯Ό 의미

  • DIλŠ” μ˜μ‘΄ν•˜λŠ” 객체λ₯Ό 직접 μƒμ„±ν•˜μ§€ μ•Šκ³ , 의쑴 객체λ₯Ό μ£Όμž…λ°›λŠ” 방식을 μ‚¬μš©
  • DIλ₯Ό 톡해 객체λ₯Ό μ£Όμž…ν•˜λ©΄ μœ μ§€λ³΄μˆ˜μ„±μ΄ 더 μ˜¬λΌκ°„λ‹€.

μŠ€ν”„λ§μ˜ DI μ„€μ •

  • μŠ€ν”„λ§μ€ DIλ₯Ό μ΄μš©ν•΄μ„œ 객체λ₯Ό μ„œλ‘œ μ—°κ²°ν•΄μ£ΌλŠ” 쑰립기이닀.
    • νŠΉμ • νƒ€μž…μ˜ 클래슀만 μƒμ„±ν•˜λŠ” 쑰립기가 μ•„λ‹Œ λ²”μš© 쑰립기이닀.

μ„€μ • 클래슀

@Configuration
public class AppCtx {

    @Bean
    public MemberDao memberDao() {
    	return new MemberDao();
    }
    
    @Bean
    public MemberRegisterService memberRegSvc() {
    	return new MemberRegisterService(memberDao()); // memberDao()	κ°€ μƒμ„±ν•œ 객체λ₯Ό μ£Όμž…
    }
    
    @Bean
    public ChangePasswordService changePwSvc() {
    	ChangePasswordService pwsSvc = new ChangePasswordService();
        pwdSvc.setMemberDao(memberDao());
        return pwdSvc;
    
    }
}
  • @Configuration : μŠ€ν”„λ§ μ„€μ • 클래슀
  • @Bean : ν•΄λ‹Ή λ©”μ„œλ“œκ°€ μƒμ„±ν•œ 객체λ₯Ό μŠ€ν”„λ§ 빈으둜 μ„€μ •
    • λ©”μ„œλ“œ 이름을 빈 객체의 μ΄λ¦„μœΌλ‘œ μ‚¬μš©

μ„€μ • 클래슀만 λ§Œλ“€μ–΄μ„œ λλ‚˜λŠ” 것이 μ•„λ‹Œ, μ„€μ • 클래슀둜 μ»¨ν…Œμ΄λ„ˆλ₯Ό 생성해야 ν•œλ‹€.

ApplicationContext ctx = new AnnotationConfigApplicationContext(AppCtx.class)
  
// ...
MemberRegisterService regSvc = ctx.getBean("memberRegSvc", MemberRegisterService.class)
  • μ»¨ν…Œμ΄λ„ˆλ₯Ό μƒμ„±ν•˜λ©΄ getBean() λ₯Ό μ΄μš©ν•΄ μ‚¬μš©ν•  객체λ₯Ό ꡬ할 수 있음
  • μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆ ctx λ‘œν„° 이름이 β€œmemberRegSvc”인 빈 객체λ₯Ό ꡬ함

DI 방식 - μƒμ„±μž 방식

public class StationService {
    private StationDao stationDao;

    public StationService(StationDao stationDao) {
        this.stationDao = stationDao;
    }
}

DI 방식 - μƒμ„±μž 방식

public class StationService {
    private StationDao stationDao;

    public void setStationDao(StationDao stationDao) {
      this.stationDao = stationDao;
    }
}

@Configuration μ„€μ • 클래슀의 @Bean μ„€μ •κ³Ό 싱글톀

@Configuration
public class AppCtx {

    @Bean
    public MemberDao memberDao() {
    	return new MemberDao();
    }
    
    @Bean
    public MemberRegisterService memberRegSvc() {
    	return new MemberRegisterService(memberDao()); // memberDao()	κ°€ μƒμ„±ν•œ 객체λ₯Ό μ£Όμž…
    }
    
    @Bean
    public ChangePasswordService changePwSvc() {
    	ChangePasswordService pwsSvc = new ChangePasswordService();
        pwdSvc.setMemberDao(memberDao());
        return pwdSvc;
    
    }
}
  • memberDao()λŠ” 맀번 μƒˆλ‘œμš΄ MemberDao 객체λ₯Ό μƒμ„±ν•΄μ„œ λ°˜ν™˜ν•œλ‹€.

그러면 memberRegSvc() κ°€ λ°˜ν™˜ν•˜λŠ” 객체와 changePwSvc()κ°€ λ°˜ν™˜ν•˜λŠ” κ°μ²΄λŠ” μ„œλ‘œ λ‹€λ₯Έ MemberDao 객체λ₯Ό μ‚¬μš©ν•˜λŠ” 것인가?

πŸ™…β€β™€οΈ μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆκ°€ μƒμ„±ν•œ λΉˆμ€ 싱글톀 객체이닀.
@Bean이 뢙은 λ©”μ„œλ“œμ— λŒ€ν•΄ ν•œ 개의 객체만 μƒμ„±ν•˜κ³  이λ₯Ό λ³΄κ΄€ν–ˆλ‹€κ°€, λ™μΌν•œ 객체λ₯Ό λ°˜ν™˜ν•œλ‹€.


두 개 μ΄μƒμ˜ μ„€μ • 파일 μ‚¬μš©ν•˜κΈ°

μŠ€ν”„λ§μ€ ν•œ 개 μ΄μƒμ˜ μ„€μ • νŒŒμΌμ„ μ΄μš©ν•΄μ„œ μ»¨ν…Œμ΄λ„ˆλ₯Ό 생성할 수 μžˆλ‹€.

@Configuration, @Autowired

AppConf1

@Configuration
public class AppConf1 {

	@Bean
	public MemberDao memberDao() {
		return new MemberDao();
	}
	
	@Bean
	public MemberPrinter memberPrinter() {
		return new MemberPrinter();
	}
	
}

AppConf2

@Configuration
public class AppConf2 {
	@Autowired
	private MemberDao memberDao;
	@Autowired
	private MemberPrinter memberPrinter;
	
	@Bean
	public MemberRegisterService memberRegSvc() {
		return new MemberRegisterService(memberDao);
	}
	
	@Bean
	public ChangePasswordService changePwdSvc() {
		ChangePasswordService pwdSvc = new ChangePasswordService();
		pwdSvc.setMemberDao(memberDao);
		return pwdSvc;
	}
	
	@Bean
	public MemberListPrinter listPrinter() {
		return new MemberListPrinter(memberDao, memberPrinter);
	}
	
	@Bean
	public MemberInfoPrinter infoPrinter() {
		MemberInfoPrinter infoPrinter = new MemberInfoPrinter();
		infoPrinter.setMemberDao(memberDao);
		infoPrinter.setPrinter(memberPrinter);
		return infoPrinter;
	}
	
	@Bean
	public VersionPrinter versionPrinter() {
		VersionPrinter versionPrinter = new VersionPrinter();
		versionPrinter.setMajorVersion(5);
		versionPrinter.setMinorVersion(0);
		return versionPrinter;
	}
}

  • @AutoWired : μŠ€ν”„λ§μ˜ μžλ™ μ£Όμž… κΈ°λŠ₯. μŠ€ν”„λ§ μ„€μ • 클래슀 ν•„λ“œμ— ν•΄λ‹Ή μ–΄λ…Έν…Œμ΄μ…˜μ„ 뢙이면 ν•΄λ‹Ή νƒ€μž… λΉˆμ„ μ°Ύμ•„μ„œ ν•„λ“œμ— ν• λ‹Ήν•œλ‹€.
    • AppConf2의 memberDao ν•„λ“œμ—λŠ” AppConf1 ν΄λž˜μŠ€μ—μ„œ μ„€μ •ν•œ 빈이 ν• λ‹Ήλœλ‹€.
  • μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆλŠ” AppConf2 객체λ₯Ό 빈으둜 λ“±λ‘ν•˜κ³  @AutoWired κ°€ 뢙은 λŒ€μƒμ— λŒ€ν•΄ μ•Œλ§žμ€ λΉˆμ„ μžλ™μœΌλ‘œ μ£Όμž…ν•œλ‹€.

μ„€μ • ν΄λž˜μŠ€κ°€ μ—¬λŸ¬κ°œμΌ λ•Œ μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆλ₯Ό μƒμ„±ν•˜λŠ” 방법은?

ctx = new AnnotationConfigApplicationContext(AppConf1.class, AppConf2.class)
  • AnnotationConfigApplicationContext의 μƒμ„±μžμ˜ μΈμžλŠ” κ°€λ³€ μΈμžμ΄λ‹€.

@Import μ–΄λ…Έν…Œμ΄μ…˜ μ‚¬μš©

  • ν•¨κ»˜ μ‚¬μš©ν•  μ„€μ • 클래슀λ₯Ό 지정
@Configuration
@Import({AppConf2.class})
public class AppConfImport {

	@Bean
	public MemberDao memberDao() {
		return new MemberDao();
	}
	
	@Bean
	public MemberPrinter memberPrinter() {
		return new MemberPrinter();
	}
}
  • μ§€μ •ν•œ ν΄λž˜μŠ€λ„ ν•¨κ»˜ μ‚¬μš©ν•˜κΈ° λ•Œλ¬Έμ— μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆλ₯Ό 생성할 λ•Œ AppConfi2λ₯Ό 지정할 ν•„μš”κ°€ μ—†λ‹€.

getBean()

VersionPrinter versionPrinter = ctx.getBean("versionPrinter", VersionPrinter.class)
  • 첫번째 μΈμžλŠ” 빈의 이름
  • λ‘λ²ˆμ§Έ μΈμžλŠ” 빈의 νƒ€μž…
  • 빈의 이름을 μ§€μ •ν•˜μ§€ μ•Šκ³  νƒ€μž…λ§ŒμœΌλ‘œ λΉˆμ„ ꡬ할 μˆ˜λ„ μžˆλ‹€.
    • λŒ€μ‹  ν•΄λ‹Ή νƒ€μž…μ˜ 빈 객체가 ν•œ 개만 μ‘΄μž¬ν•΄μ•Όν•œλ‹€.

μ£Όμž… λŒ€μƒ 객체λ₯Ό λͺ¨λ‘ 빈 객체둜 μ„€μ •ν•΄μ•Όν•˜λ‚˜?

πŸ™…β€β™€οΈ μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆκ°€ 객체λ₯Ό κ΄€λ¦¬ν•˜λŠ”μ§€ μ—¬λΆ€λ§Œ λ‹€λ₯Ό 뿐이닀.
참고둜 μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆλŠ” μžλ™ μ£Όμž…, 라이프사이클 관리 λ“± 객체 생성 외에도 객체 관리λ₯Ό μœ„ν•œ λ‹€μ–‘ν•œ κΈ°λŠ₯을 μ œκ³΅ν•œλ‹€.