본문 바로가기

SpringFramework

MVC,spring

spring DI(Dependency Injection)란?

■ 의존성(Dependency)

∎ 비즈니스 로직을 수행하기 위해서는 둘 이상의 클래스가 사용되는데, 각 객체는 협업할 객체의 참조를 취득해야할 책임이 있는데, 이것이 의존성이다.

∎ 객체간의 결합도가 높으면 테스트하기 어려운 코드가 만들어진다.

■ 의존성 주입 : 객체들은 객체의 생성 시점에 spring container로부터 의존성을 부여 받게 된다. 즉, 의존하는 객체를 주입받게 된다. 

■ 클래스와 클래스간의 의존성

∎ 클래스가 구현 클래스에 의존하는 경우

- 클래스와 클래스간의 결합도가 높다. 

 ∎ 클래스가 인터페이스에 의존하는 경우

- 클래스간의 결합도가 낮아진다. 

 

   

∎ factory pattern을 사용한 경우

- 구현클래스를 변경하더라도 소스 코드의 변화 없음

  ∎ spring DI 사용한 경우

- spring container가 객체 사이의 의존관계를 조립한다.

 

■ 제어역행(IoC : Inversion of Control)

각 객체는 협업할 객체의 참조를 취득해야하는 책임이 있는데, 제어역행은 의존하는 객체를 역행적으로 취득하는 것이다. IoC는 한 객체가 의존성을 가지는 다른 객체의 참조를 취득하는 방법에 대한 책임의 역행이라는 의미를 가지고 있다. IoC를 적용하면 객체들은 어떤 존재에 의해 객체를 생성할 때 의존성을 가지는 객체를 주입받게 된다.  


※ 의존성을 가지는 객체를 참조하는 법

 







 

 

 

 



 

■ spring framework에서의 DI


 

 MVC란



Model-View-Controller(MVC, 모델-뷰-컨트롤러)는 Model, View, Controller란 세 가지 요소로 만들어진 소프트웨어 구조를 일컫는 용어이다. 현재 소프트웨어 공학에서는 구조 패턴으로 간주된다. (다양한 구조 패턴의 하나이다.)

MVC패턴은 사용자 인터페이스(입력과 보여줌)에서 "도메인 로직(Domain logic or business logic)"1을 분리하여 각 경우의 테스트, 유지보수를 독립적으로 개발하는 것을 가능케한다. 즉 MVC패턴은 사용자 인터페이스와 데이터의 처리 관계를 분리한다. MVC패턴은 MVC를 이루는 Model, View, Controller의 역할과 행동을 살펴봄으로 구 구조를 익힐 수 있다.
 

Model(모델)은 응용프로그램 영역의 행동과 데이터를 관리하며 두 가지 역할을 한다.

1. 뷰의 요청에 따라 현재 상태에 대한 정보를 전달한다.
2. 컨트롤러의 요청에 따라 현재 상태를 변경한다.



View(뷰)는 모델을 상호작용에 적합한 양식(텍스트, 체크박스, 라디오 상자 등)으로 표현한다. 하나의 모델에 다양한 목적을 가진 여러개의 뷰가 존재할 수 있다. 뷰포트(Viewport, 일반적으로 화면에 보여지는 사각영역을 말한다)는 일반적으로 디스플레이 표면과 1대1 대응을 하며 그것을 어떻게 표현할지에 대해 알고 있다.

 
Controller(컨트롤러)는 입력을 받고 모델 객체들에서 만들어진 호출에 대한 응답을 초기화한다.

1. 컨트롤러는 사용자의 입력을 받아들인다.

2. 모델과 뷰포트에게 입력에 따른 행동을 수행하도록 지시한다. 




MVC패턴을 사용한 간단한 제어 흐름을 살펴보면 다음과 같다.


1. 사용자는 뷰에서 사용자 인터페이스와 상호작용한다. (예를 들어 버튼을 눌렀다고 생각한다.)
2. 컨트롤러는 뷰로부터 이벤트를 받아 모델이 이해할 수 있는 형태로 변경한다. 이것은 보통 등록된 핸들러 혹은 콜벡으로 처리한다. (모델의 상태가 변경된다.)
3. 컨트롤러는 모델의 상태가 변경되었다고 뷰에게 알린다. (모델의 상태가 변경될 때 뷰어게 알리는 구조도 있다)
4. 뷰는 모델에게 질의하여 모델의 상태를 적합한 양식(텍스트, 리스트, 체크박스 등)으로 표현한다.
5. 추가적인 입력을 기다린다. 추가적인 입력 발생 시 위의 과정이 반복된다.

객체scope
page- 한 페이지 내에서만 유효
request-  요청된 페이지 범위에서만 유효
session-  세션이 시작되고 종료될때까지 거치는 페이지에서만 유효
application-  서버가 시작되고 종료될때까지 한 어플리케이션 내의 페이지 모든범위에서 유효


include액션 forward액션에 대해 차이를 설명하라.
forward메서드는 jsp페이지안에서 다른 jsp페이지를 호출할 때 사용하는 메서드이다. 하지만 forward는 호출된 jsp페이지가 끝나도 실행 흐름의 제어를 되돌려주지 않는다. 그러므로 어떤 jsp페이지가 할 일을 모두 마치고 난 다음에 다른 jsp페이지를 호출하고자 할 때 사용하는 것이 좋습니다.
반면 include액션은 forward처럼 다른jsp페이지를 호출하는 기능을 하지만, 호출된 jsp페이지가 끝나고 나면 실행흐름의 제어가 본래의 jsp로 돌아온다는 점이 다릅니다. 그렇기 때문에 이 메서드는 여러 jsp페이지가 공통으로 사용하는 코드를 호출하고자 할 떄 사용하는 것이 좋습니다.

서블릿의 생명주기
서블릿 클래스는 웹 브라우저에 의해 바로 호출되는 것이 아니라, 일단 서블릿 클래스로부터 서블릿 객체가 만들어지고, 그 객체가 웹 컨테이너에 의해 초기화된 다음에 호출됩니다. 이렇게 웹브라우저의 요청을 처리할 수 있는 상태의 서블릿 객체를 서블릿이라고 하는데, 웹 컨테이너는 더이상 필요치 않은 서블릿은 웹 컨테이너의 메모리로부터 제거하기도 합니다. 웹컨테이너는 jsp페이지로부터 변환된 서블릿 클래스를 로드하고, 그 클래스를 가지고 서블릿 객체를 만들고, 그 객체를 초기화해서 서블릿을 만들고, 그 서블릿이 더이상 필요치 않으면 메모리로 부터 제거합니다. 
<서블릿의 아리프 사이클>
서블릿클래스로드->웹컨테이너[서블릿클래스 ->(인스턴스화)서블릿객체->(초기화작업)서블릿->(더이상 사용되지 않는 서블릿)제거]                                                                                                       |
                                                                                                                            ㅜ
                                                                                                             웹브라우저로부터의 호출처리

그런데 위 그림의 과정중에 서블릿 객체를 생성하고 초기화하는 안스턴스화와 초기화작업단계는 컴퓨터의 자원을 많이 사용하므로 큰 부담이 됩니다. 그러므로 웹 컨테이너는 웹 브라우저의 요청이 올 때마다 이 라이프 사이클을 모두 거치는 것이 아니라, 일단 만들어진 서블릿을 메모리에 남겨두었다가 다음에 또 다른 요청이 오면 바로 호출합니다.그러면 웹 컨테이너는 서블릿을 언제제거할까요? 웹컨테이너는 자신이 종료되기전이나 웹 어플리케이션을 리로드하기 전에 그에 속하는 모든 서블릿을 제거합니다. 그리고 그럴때가 아니더라고 서블릿이 차지하고 있던 메모리를 다은 목적에 사용하기 위해 제거하는 경우도 있습니다. 

초기화(init-메서드) - >서비스(service-메서드)->제거(destroy-메서드)로 라이프사이클을 구현할 수 있다.



ServletConfig - 하나의 Servlet에 관련된 초기화 파라메터들.
ServletContext - 하나의 context 내에서 다른 servlet 간 공유 가능한 data 혹은 자원.

이라고 딱 잘라 정의 할 수 있습니다.
쉽게 생각하면 두 가지는 어떤 데이터를 공유를 해서 사용하는 데 그 범위가 엄청나게 차이가 납니다.
ServletConfig는 해당하는 하나의 Servlet에서만 쓸 수 있는 자원입니다.
즉, 하나의 servlet에서 밖에 쓸 수 없기 때문에 주로 그 Servlet의 초기화 파라메타 값들을 설정, 저장 할 수 있습니다.
ServletContext는 해당 context내에서 모든 JSP/Servlet들이 다 공유해서 쓸 수 있는 공유 자원입니다. context 라 하면 우리가 만든 test 혹은 만들어져 있는 examples, ROOT 등입니다.
이 Context는 application의 최상위 개념, 가장 큰 개념이라 생각하시면 됩니다.
(나중에 나오겠지만 JSP에서 application 이란 내장객체로 명명하는 것도 바로 이것입니다)

이런 큰 차이점이 있다는 것을 숙지하시고 하나씩 알아보도록 하겠습니다.



1) ServletConfig
ServletConfig는 하나의 servlet에서 사용할 수 있는 초기화 파라메터 값이라고 했습니다.
그럼, 이 값을 어디서 설정을 하고, 또 servlet에서 어떻게 사용하는 지를 알아봅시다.
여기에 설정되는 값은 위에서 말씀드린 Read Only 한 값입니다.
① 값 설정
ServletConfig에 값을 설정하기 위한 곳은 바로 DD 입니다. (그래서 앞에서 DD를 설명드린 거죠....)
하나의 Servlet에서 계속적으로 읽어 와서 사용코자하는 용도 보다는 처음에 Servlet이 로딩시 즉, init() 메서드가 수행 시에 한 번 읽어 와서 계속 사용하고자 하는 의미가 더 큽니다.
DD에서 설정하실 때는 분명 하나의 Servlet에서 사용 한다고 했으니 그 계층구조를 유심히 보셔야 합니다.


예로서 지난 번에 봤던 HelloServlet에 어떤 디폴트 이름을 하나 영원히 가지게 하고 싶어서 DD에 추가를 한다하면, (뭔말이지 지금은 잘 몰라두 나중에 어떻게 사용하는 가를 보시면 이해가 되실 듯)

<servlet>
        <servlet-name>Hello</servlet-name>
        <servlet-class>codeland.web.HelloServlet</servlet-class>
        <init-param>
                <param-name>hello</param-name>
                <param-value>Good Morning !</param-value>
        </init-param>
</servlet>

위처럼 할 수가 있습니다. 주의 할 것은 태그의 위치와 구조입니다.
한 Servlet 안에서 쓴다고 했으니 <servlet>과 </serlvet> 안에 있습니다.
그리고 servlet definition 밑에 옴니다.
그러면, hello 라는 이름으로 Good Morning! 이란 글자를 나중에 꺼낼 수가 있습니다.

② 사용
ServletConfig의 값을 사용하고자 한다면, init() 메서드에서 사용하시는 것이 가장 좋습니다.
이유는 지난 시간의 Life Cycle과 관련이 되겠죠?
ServletConfig API도 꼭 한 번 확인해 보시기 바랍니다.

위의 예로 HelloServlet에서 Good Moring ! 이란 인사말을 계속 사용하고 싶다면,

public class HelloServlet extends HttpServlet{
        private String helloWord;

        public void init(){
                helloWord = getInitParameter("hello");
        }
        
        public void doGet(HttpServletRequest request, HttpServletResponse response)
                        throws ServletException, IOException{
                .......중간 생략.....
                out.println(“미국인은 ”+ helloWord+"라고 인사합니다“);
                ......
        }
}


자, 살펴 보면, init() 메서드에서 getInitParameter() 하고 있습니다. 앞에 어떤 레퍼런스두 없이 메서드를 호출하고 있습니다. 그럼 이 메서드는 어디에서 온 것일까요?
상속 관계로 거슬러 올라가 보면 되겠습니다.
찾아보면 ServletConfig에도 있고, GenericServlet에도 있습니다. 둘중 어떤 거라해도 상관없습니다. 둘 다 가능하니까요. 결국 GenericServlet도 ServletConfig를 implements하고 있으니....
결론은 getInitParameter() 하면 DD에서 <servlet>안에 있는 <param-name>에 해당하는 <param-value> 값을 리턴시켜 준다는 것입니다.
그래서 hello 이것은 <param-name>에 해당이 되겠죠?

자 다시 정리를 해 보자면, ServletConfig에 어떤 값을 설정하고 싶으면 DD의 적절한 위치에 정의를 하고,
그것을 사용코자 한다면 특정 Servlet에서 getInitParameter() 메서드를 써서 사용할 수 있다는 것입니다.

앗! 근데 Servlet내에서 쓸 거 같으면 그냥 그 안에서 변수로 선언하면 되지 왜 이렇게 어렵게 하느냐? 물어 볼 수두 있는데, 그건 혹시나 다음에 그 값이 바뀔 때 입니다.
값이 바뀌었을 때 소스 자체를 변경하는 그런 예전의 방법은 지양해야겠죠.
그래서 Property 파일이나 Configuration 파일을 쓰는 이유이겠죠.

2) ServletContext
ServletContext는 자원 공유의 의미가 더 큽니다.
하나의 Context에서 여러 파일 간 자원을 공유해서 쓰고자 함입니다.
여기에는 두 가지 방법이 있습니다.
아까 말씀드린 대로 Read Only 하는 방법과 Read Write 하는 방법이 있습니다.

① Read Only 방법
이 방법은 ServletConfig 와 비슷합니다.
단 DD에서 위치를 주의 하셔야 합니다.

ServletConfig 는 <servlet></servlet>내에 있었지만 개념적으로 context 가 더 상위 개념이겠죠? 그래서 위치도 제일 먼저 <servlet> 태그 이전에 같은 레벨에 옵니다.


    <context-param>
       <param-name>catalogFileName</param-name>
       <param-value>/WEB-INF/catalog.txt</param-value>
    </context-param>

    <servlet>
        <servlet-name>Hello</servlet-name>
        <servlet-class>codeland.web.HelloServlet</servlet-class>
    </servlet>

아까 보았던 ServletConfig와 유사하나 태그 위치와 <context-param> 이란 것이 다릅니다.
이것은 “catalogFileName” 이란 이름으로 “/WEB-INF/catalog.txt” 이란 텍스트를 쓰겠다는 것입니다. (예제 때문에 까딱 혼동이 되겠는데, txt 파일 자체가 아니라 “/WEB-INF/catalog.txt” 글자입니다.)

이것을 불러와서 쓸 때는
ServletContext 에 있는 getInitParameter() 메서드를 사용합니다.
ServletConfig 의 getInitParameter() 와 이름이 같기 때문에 잘 구분하셔야 합니다.

ServletContext context = getServletContext()     // GenericServlet의 메서드
String fileName = context.getInitParameter("catalogFileName");

라고 하시면 되겠습니다.
이렇게 하시면 위의 값은 어느 특정 Servlet 뿐만 아니라 Context내에선 다 공유 해서 쓸 수 있다는 것입니다.
getInitParameter() 메서드는 그래서 두 두군데 있으니 구분을 잘 하셔야겠죠?

② Read Write 방법
이 방법은 ServletContext API를 보면 몇 가지 메서드가 있습니다.
setAttrubute(), getAttribute() 메서드가 그것입니다.
setAttribiute() 로 어떤 Object를 저장하고, getAttribute() 로 그 값을 꺼내와 쓸 수 있습니다.

'SpringFramework' 카테고리의 다른 글

Spring websocket  (0) 2023.12.10
spring batch  (0) 2023.02.06
SpringFramework  (0) 2018.02.03
Spring Day4  (0) 2012.06.01
Spring01정리  (0) 2012.06.01