Spring DI: Spring DI Container, XML 기반 설정

호수·2023년 3월 8일
0

Spring

목록 보기
2/5
post-thumbnail

DI 💉
의존 주입
Dependency Injection
1. 의존: 한 클래스가 다른 클래스의 메서드를 실행 하는 것을 뜻한다.
2. 주입: 의존 하는 객체를 직접 생성하지 않고 의존 객체를 전달 받는 방식
💡DI(Dependency Injection)란?
■의존 관계 주입을 의미
■오브젝트 간의 의존 관계를 만드는 것
■스프링 프레임워크는 런타임시 사용할 객체들의 의존 관계를 부여한다
■객체 간의 결합도를 낮춘다
응집도↑ 결합도↓

– 객체지향프로그램은비즈니스로직을수행하기위해상호협력
(의존)하는 객체들로 구성됨
▪ 각 객체는 다른 객체를 이용 (의존 객체 필요)
– 의존성 주입은 객체 외부에 존재하는 assembler(container)가 실행시간(run-time)에 객체들 사이의 의존관계를 파악하고 의존객체를 제공해 주는 것을 의미
▪ 객체 생성 시점에 의존 객체를 객체에게 전달 (Bean Wiring)
Inversion of Control (IoC)
✓객체가 의존 객체를 직접 생성하거나 찾을 필요 없음
– 객체들간의 의존관계는 XML파일이나 Java설정클래스, annotation 등을 통해 설정 가능
▪ Assembler(container)가 설정 내용을 참조하여 DI 수행
– 객체들간의 결합도(coupling)를낮춤으로써테스트및수정용이, 재활용성 향상

예 1: MemberDao 인터페이스를 이용하는 Service 클래스들
▪ 두 Service 객체는 MemberDao 인터페이스를 구현한 객체에 의존
✓MemberDaoMap 또는 MemberDaoMySQL 객체
▪ MemberDaoMap 객체와 의존 관계 생성 및 메소드 호출

– 예 2: MemberDao 클래스를 이용하는 Service 클래스들
▪ MemberDao 클래스의 객체뿐만 아니라 MemberDao의 자식이나 자손 클래스의 객체도 참조 가능

💡DI필요성
구현방법1: 의존하는 객체를 직접 생성
구현방법2: Factory클래스 이용
구현 방법 3: Dependency Injection 이용

– 구현방법1:의존하는객체를직접생성

public class MemberRegisterService { // 또는 ChangePasswordService private MemberDao memberDao = new MemberDao();
... }

– 구현방법 2: Factory 클래스 이용

public class MemberRegisterService {
private MemberDaoFactory factory = MemberDaoFactory.newInstance();
private MemberDao memberDao = factory.newMemberDao();
... }
  • factory클래스를 따로 만들고 거기에 있는 dao(newInstance)를 호출해서 사용
    *MemberDaoFactory 클래스 안에 newInstance)메소드, 그 안에
    newMemberDao()메소드
    장점)
    -수정 필요 시 factory클래스만 수정
    단점)
    -객체마다 factory클래스를 구현해야 함
    -factory객체에 대한 타이트한 의존 관계 형성

– 구현 방법 3: Dependency Injection 이용
▪ 외부에 존재하는 Assembler가 객체(예: MemberDao)를 생성한 뒤 그것에 의존 하는 객체(예: MemberRegisterService)에게 전달함
✓ MemberRegisterService 클래스는 의존 객체를 전달받기 위한 생성자 (constructor)나 setter method를 정의
✓의존 객체를 직접 생성하거나 찾기 위한 코드는 불필요

객체 조립기(Assembler)
DI를 활용하면 객체 생성에 사용할 클래스를 변경하기 위해 객체를 주입하는 곳만 변경하면 되는 것이라고 우리는 알고 있습니다. 하지만 DI를 활용해서 클래스를 작성했더라도 그 객체를 main메서드에서 주입하는 것보다 의존 객체를 주입하기 위한 클래스를 따로 작성하는 것이 관리차원에서 더 효율적인 관리가 됩니다. 이 때 의존 객체를 주입하기 위한 이 클래스를 조립기라고 표현합니다

public class Assembler {
private MemberDao memberDao;
private MemberRegisterService regSvc; private ChangePasswordService pwdSvc; public Assembler() {
}

// memberDao 객체 생성 regSvc = new MemberRegisterService(memberDao);
memberDao = new MemberDao();
// MemberRegisterService 객체 생성 및 memberDao 객체 전달(DI)
pwdSvc = new ChangePasswordService(); // ChangePasswordService 객체 생성
pwdSvc.setMemberDao(memberDao); // memberDao 객체 전달(DI) }
public MemberDao getMemberDao() { return memberDao; }
public MemberRegisterService getMemberRegisterService() { return regSvc; } public ChangePasswordService getChangePasswordService() { retun pwdSvc; }
}
public class MainForAssembler { // test program public static void main(String[] args) {
Assembler assembler = new Assembler(); // assembler 객체 생성 // assembler로부터 MemberRegisterService 객체를 구함
MemberRegisterService regSvc = assembler.getMemberRegisterService(); RegisterRequest req = new RegisterRequest(...); // 등록 정보(DTO) 생성 regSvc.regist(req); // MemberRegisterService 호출 및 등록 정보 전달
// assembler로부터 ChangePasswordService 객체를 구함 ChangePasswordService pwdSvc = assembler.getChangePasswordService(); pwdSvc.changePassword(...); // ChangePasswordService 호출 및 정보 전달
} }

Assembler 생성자에서 MemberRegisterService 객체는 MemberDao 객체를 주입받고, ChangePasswordService는 setter을 통해 주입받음

💡Spring Container
-org.springframework.beans.factory.BeanFactoryinterface 또는 그 sub-interface(예: ApplicationContext)를 구현
– 객체(bean)들의life-cycle관리및assembler역할수행 ▪객체들을생성및초기화 ▪DI를통해객체들사이의의존관계형성org.springframework.beans.factory.BeanFactoryinterface 또는 그 sub-interface(예: ApplicationContext)를 구현
–객체(bean)들의life-cycle관리및assembler역할수행
▪객체들을생성및초기화
▪DI를통해객체들사이의의존관계형성행

💡 Spring의 DI 지원
1. XML을 이용한 객체 생성 및 의존 관계 설정 (appContext.xml)
2. Annotation을 이용한 설정
3. Java code를 이용한 설정 (JavaConfig)

  1. XML을 이용한 객체 생성 및 의존 관계 설정 (appContext.xml)
    <appContext.xml>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="..." xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- MemberDao 타입 객체 생성 -->
<bean id="memberDao" class="spring.MemberDao" />
<!-- MemberRegisterService 타입 객체 생성 -->
<bean id="memberRegSvc" class="spring.MemberRegisterService">
<constructor-arg> <!-- 생성자를 이용한 MemberDao 객체 주입 --> <ref bean="memberDao" />
</constructor-arg>
</bean>
... </beans>

▪ Test program

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
public class MainForSpringXML {
public static void main(String[] args) {
XML 설정 파일을 이용하는 Container 생성
ApplicationContext context
= new GenericXmlApplicationContext("classpath:appContext.xml");
MemberRegisterService regSvc
= context.getBean("memberRegSvc", MemberRegisterService.class);
RegisterRequest req = new RegisterRequest(...);
regSvc.regist(req); “memberRegSvc” 객체를 반환
ChangePasswordService pwdSvc
= context.getBean("changePwdSvc", ChangePasswordService.class);
pwdSvc.changePassword(...);
... }
}

Spring Container가 생성 및 실행하는 코드참조
MemberDao memberDao = new MemberDao();
MemberRegisterService memberRegSvc = new MemberRegisterService(member2D7ao);
어떤 객체를 생성하고(spring.MemberService, spring.MemberRegisterService, etc)어떤 객체를 주입할 것인지(spring.MemberDao)를 정의해야 한다.
따라서,

<bean id="memberDao" class="spring.MemberDao"></bean> 

이라는 코드를 통해 주입을 될 bean 객체를 생성한다.
이 코드를 자바로 변환하면 아래와 같다. spring.MemberDao memberDao=new spring.MemberDao();

그리고

<bean id="memberRegSvc" class="spring.MemberRegisterService">
<constructor-arg ref="memberDao" />
  </bean>

이 코드를 통해 어떤 객체에 넣을 것인지를 정의하고 생성한다.
이 코드를 자바로 변환하면 아래와 같다.
spring.MemberRegisterService memberRegSvc=new spring.MemberRegisterService(memberDao);

아래의 소스를 보면 bean 태그 안에 constructor-arg 태그 또는 property 태그를 사용한 것을 볼 수 있다.
constructor-arg 태그는 계속해서 꺼내먹을 아이들, property 태그는 한 번만 꺼내먹을 아이들이라고 생각하면 된다.
[규칙은 id값과 class값을 bean태그에 속성으로 넣어줍니다.
id는 bean의 식별자이고, class는 실질적인 class입니다.
DI를 할 때 생성자의 방식이라면 를 Setter라면 태그로 주입하고,
주입할 bean객체는 ref="<id명>"으로 입력합니다.]

의존성 주입 방법??
그렇다면 어떻게 이 의존성을 주입할 수 있을까? 생각할 수 있는 간단한 방법은 다음과 같다.
객체 생성 시 생성자의 매개변수로 의존성 주입
객체 생성 후 메서드(setter 등)로 의존성 주입
클래스 생성 시 @Autowired 어노테이션으로 의존성 주입

  1. 스프링 XML 설정 파일 포맷

기본 포맷

👉 빈 등록, 빈 설정을 모두 XML에 작성할 경우에 이 포맷을 사용한다.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

</beans>
  1. 빈(Bean) 설정 예시

태그를 이용해 빈을 정의한다.

<bean id="memberDao" class="spring.MemberDao" />

태그의 필수 속성은 class 속성 하나 뿐이다.
id는 빈의 id를 통해 참조할 경우가 있는 경우에만 설정하면 된다.
자바 코드에서 getBean()으로 빈을 가져오던지, 주입 설정에서 ref 속성으로 빈을 참조하는 경우이다.
id, class 외에는 lazy-init, scope, primary, init-method, destroy-method 속성이 있다.

id : 빈 이름(id) 설정
class : 빈 타입 설정
scope : 빈의 scope 설정. singleton/prototype
primary : true를 지정하여 같은 타입의 빈이 여러개 일때 우선적으로 사용할 빈 설정
lazy-init : true를 지정하여 빈을 사용할 때 객체가 생성되도록 설정
init-method : 빈 객체가 생성될때 호출할 메소드 설정
destroy-method : 빈 객체가 소멸될때 호출할 메소드 설정

참고용어
Controller :

  •  사용자의 Request를 전달받아 요청의 처리를 담당하는 Service 를 호출

Service :

  •  Controller에 의해 호출되어 실제 비즈니스 로직과 트랜잭션을 처리
  •  dao를 호출하여 DB CRUD를 처리 후 Controller로 반환

dao :

  •  Service에 의해 호출되어 DB CRUD를 담당

mapper :

  •  dao에서 요청하는 실제 쿼리문이 위치하는 곳
profile
Back-End개발자 입문 과정 블로그🚀

0개의 댓글