본문 바로가기
IT Study/Spring

Spring - 제어의 역행(IoC), 생성자 인젝션(생성자 주입방식)

by hhyyyjun 2023. 1. 2.

프레임 워크

개발을 어떻게 해야하는지 아웃라인을 제공

spring 프레임워크를 사용하는 이유?

1) 프레임워크를 사용하기 때문에 개발시간이 단축된다.

2) 관리가 용이 = 유지보수 용이

3) 개발자들의 실력이 상향 평준화

4) 스프링 프레임워크가 뭔지 한마디로 표현하자면?

"IoC와 AOP를 지원하는 경량의 프레임워크"

IoC(Inversion of Controll) - 제어의 역행 > 낮은결합도 제공

AOP(Aspect Oriented Programming) - 관점지향 프로그래밍 > 높은 응집도 제공

경량 -> .java 파일을 사용 == POJO(서블릿이 아닌 일반 .java 파일)

제어의 역행(Inversion of Control)

지금까지는 사용자의 요청에 따라 FrontController을 통해 새로운 컨트롤러 액션을 사용하였음.

하지만 FC에서 액션을 new 하므로 높은 결합도를 보인다.(개발자가 새로운 메모리를 할당하므로)

이러한 문제를 컨테이너에게 맡기는 것(컨테이너에게 객체화를 담당시키는 것)

소스코드에 new가 없기 때문에 결합도가 낮아진다 -> 유지보수가 용이해진다.

소스코드에 new가 있는 것 == 의존관계를 명시했다.

1) servlet 태그 - 서블릿 생성

name - test로 지정

class - a.Test로 지정

2) servlet-mapping 태그 - 연결

name - servlet 태그의 name과 동일해야 함

url-pattern - 해당 서블릿의 경로를 간단히 나타내줌

web.xml 을 통한 객체화

1) web.xml 은 서블릿 컨테이너에게 설정을 알려주는 파일

2) 어떤 설정? 만들어야 할 서블릿에 관련된 설정(무엇을 만들지, 언제 호출할지)

3) new를 작성하지 않았지만 객체화가 진행 => 서블릿 컨테이너

4) 서블릿에 기본생성자가 필수로 있어야 한다.

5) .xml에서 @(어노테이션)으로 해결

6) 스프링 프레임워크가 @(어노테이션)을 적극적으로 활용한다.

동작순서

1) web.xml 이 로딩 -> /test.do 요청이 들어옴

2) a.test 클래스를 객체화

3) doGet() 메서드 호출(서블릿 컨테이너 담당)

4) 브라우저(사용자, client)에 실행 결과 출력


생성자 주입(constructor-arg)

결합도가 높은 코드의 결합도를 낮추는 법

1) 인터페이스

객체지향 - 다형성을 이용

2) 디자인 패턴 - 팩토리(Factory) 패턴

Client에서 직접적으로 new 소스코드 x

생성자 주입의 특징

생성자 호출 시점에 1번만 호출되는 것이 보장

=> 이후 호출되는 일이 없음

=> 불변하게 설계할 수 있음 == final 키워드 사용 가능

BeanFactory(각 클래스를 통해 생성된 객체를 반환하는 클래스)

예시 코드에 사용될 Galaxy 클래스(의존 객체를 생성자를 통해 전달 받을 예정)

IoC와 관련된 설정을 applicationContext.xml로 작성

=> 스프링 설정파일

applicationContext.xml(스프링 설정파일)

객체화 및 속성 설명(실행파일에 사용될 코드는 3번줄 이후~ 부분)

1) <bean id="phone" class="test.Galaxy"/>

=> test패키지에 있는 Galaxy 클래스로부터 객체를 만들어달라는 의미

2) init-method 속성 - 객체 초기설정 메서드를 실행

3) destroy-method 속성 - 객체 메모리를 제거할 때 호출하는 메서드

4) lazy-init(지연 생성 방식) 속성 "true" - 해당 id가 호출되어야만 객체 생성

=> 사진에서 galaxyWatch 클래스로부터 객체를 만들어서 id를 통하여 호출했으므로 Galaxy 클래스에 대해 객체가 생성됨

5) scope 속성 - 기본적으로 'singleton' 설정이다.

=> 여러 객체를 사용할 때는 'prototype' 으로 설정한다.

6) <constructor-arg ref = "객체"> - 의존성 있는 객체를 외부에서 주입하는 것(생성자 인젝션(=생성자 주입방식))

=> 사진에서 gphone의 bean 객체에 gw 객체를 주입한 것

=> 즉 Galaxy 클래스는 GalaxyWatch 클래스에 의존성을 갖게 되는 것

Client.java(실행파일)

동작순서

1) 클라이언트가 컨테이너를 로딩

2) 이 때, 스프링 설정파일을 참고하여 로드

3) 스프링 설정파일의 <bean> 객체화

=> <bean>을 통해 객체화 된 것들은 즉시 로딩(pre-loading)

4) "gphone" 객체 요청 = Lookup이라 표현

5) 요청한 객체 반환


p 네임스페이스

xml 파일 하단 Source 옆 Namespaces를 클릭하면 사진과 같은 화면이 나온다.

위와 같은 코드를 아래와 같이 간단하게 작성할 수 있다.

참고용

1) xxx.xml

환경설정과 관련된 파일

2) web.xml

FC와 같은 서블릿을 관리하는 서블릿 컨테이너(톰캣, 웹 서버)에게 설정을 알려주는 파일

3) 컨테이너

java 객체화를 담당

4) pom.xml

스프링 컨테이너에게 설정을 알려주는 파일

현재의 프로젝트가 가지고있는 패키지(클래스 파일) 참조 사항을 설정함

100%까지 대기

Maven Dependencies 라이브러리로, 패키지 참조가 완료된 것을 확인가능

댓글