Back-end/JAVA,Spring

스프링이란? Spring / IoC 역제어 / DI 의존성 주입

cheersHena 2018. 8. 24. 15:08
반응형

스프링 Spring Framework


자바 개발을 편하게 해주는 오픈소스 경량급 애플리케이션 프레임워크 (by 로드 존슨)

Framework: 뼈대/ 골조 : 어떠한 작업을 위한 뼈대/골조. 


애플리케이션 프레임워크 

일반적으로 라이브러리나 프레임워크는 특정 업무나 기술에 특화된 목표 가지고 만들어진다. 그래서 프레임워크란 애플리케이션 특정 부분에서 주로 동작하는 한가지 기술에 집중된다.

하지만 스프링은 이와다르게 '애플리케이션 프레임워크' 이다.

애플리케이션 프레임워크는 특정 분야에 국한되지 않고 애플리케이션의 전 영역을 포괄하는 범용적 프레임워크를 말함. 즉, 애플리케이션 개발의 전반적인 과정을 빠르고 편리, 효율적이도록 돕는 프레임 워크이다. 

흔히들 스프링하면 알고있는 개념인 MVC / JDBC / ORM 프레임워크 등은 스프링이 다루는 일부 영역이며 IoC / DI / AOP 프레임워크 또한 스프링이 제공하는 핵심 기술 중 하나일 뿐인 것이다.


스프링의 궁극적 목적은 핵심 기술에 담긴 프로그래밍 모델을 일관되기 적용해서 애플리케이션 전 계층과 전 영역에 기능을 제공하여 애플리케이션을 편리하게 개발하도록 돕는 애플리케이션 프레임워크로 사용되는 것임을 먼저 이해하자.   


경량급 lightweight

스프링이 가볍다는 말은 아니다. 오히려 스프링은 20여개의 모듈로 세분화되는 복잡하고 방대한 규모의 프레임워크이다. 

스프링은 불필요하게 무겁지 않다는 의미의 경량급이다. 단순한 개발툴과 기본적인 개발환경으로도 애플리케이션 개발에 충분하며 개발 과정도 단순해진다. 기존코드에 불필요하게 등장하던 프레임워크와 서버환경에 의존적인 부분을 제거해주기 때문이다. 


자바개발 편하게

객체 생성에 대한 책임을 더이상 개발자가 지지 않아도 되도록 스프링이 대신해준다. 

전통적인 자바  엔터프라이즈 개발 기법은 대부분 비즈니스 로직의 복잡한 구현코드와 엔터프라이즈 서비스를 이용하는 기술적인 코드가 혼재될 수 밖에 없었고 결국 개발자가 두시가지를 동시에 개발책임을 져야해 과도한 부담을 줬고 복잡함은 몇 배로 가중되었다. 

스프링은 자바 개발자들이 기술적인 복잡함에 신경쓰지 않고 비즈니스 로직을 효과적으로 개발하는데 더 집중할 수 있도록 해준다. 초기에 스프링의 기본설정과 적용기술만 잘 선택하고 준비해두면, 애플리케이션 개발 중에는 스프링 관련코드나 API에 대해 개발자가 더이상 책임을 지거나 신경쓰지 않아도 된다. 

스프링을 이용하면 기술적인 복잡함과 비즈니스 로직을 다루는 코드를 깔끔하게 분리할 수 있다. 그 과정에서 스프링 스스로가 애플리케이션 코드에 불필요하게 나타나지 않는다. 꼭 필요한것 같은 경우조차도 기술코드가 직접 노출되지 않도록 만들어 주었다. 


오픈소스

스프링은 오픈소스 프로젝트 방식으로 개발되어왔다 지금도 여전히 개발되는 중이며 앞으로도 개발되어 발전할 것이다. 

오픈소스란 말그대로 누구에게나 공개되고 라이센스를 취득할 필요 없이 얼마든지 자유롭게 이용할수 있다는 의미다. 소스를 자유롭게 열람하고 목적에 맞게 사용, 수정, 다시 배포까지 자유롭다.


스프링의 전략: 분업.

스프링의 기본적 저 전략은 비즈니스 로직 담은 애플리케이션 코드와 애플리케이션 기술을 처리하는 코드를 분리 시키는 것이다. 즉, 기존에 섞여있던 복잡한 코드를 각 목적에 맞도록 분업시킨다. 

 동시에 스프링이 제공하는 기술과, 프레임워크 API 및 확장 포인트는 그것을 이용하는 코드가 자연스럽게 객체지향적인 설계원리를 따라가도록 이끌어준다. 좋은 코드와 좋은 프레임워크의 특징은 그것을 사용해서 만들어지는 코드가 나쁜 코드가 되기 어렵다는 점이다. 

스프링은 매우 자연스럽게 개발자가 좋은 코드를 만들게 해준다. 이게 바로 스프링이 전 세계적으로 그토록 많은 개발자에게 인정받고 인기를 누리는 이유 되겠다.




스프링 프레임워크 2 - 컨테이너와 빈의 생명주기 

스프링: IoC / DI (역제어 / 의존적 주입)을 기반으로 하는 거대한 컨테이너. 


컨테이너

인스턴스(객체) 생명주기 관리. 생성된 객체들에게 추가적 기능 제공하도록 하는 것.

즉, 컨테이너란 개발자가 작성한 코드의 처리과정을 위임받은 독립적인 존재이다. 컨테이너는 적절한 설명만 되어있다면 누구의 도움없이 스스로 프로그래머가 작성한 코드를 스스로 참조한 뒤 알아서 객체 생성 및 소멸을 컨트롤 해준다. Wooooow


스프링 컨테이너는 스프링 프레이워크의 핵심이며, 종속 객체 주입을 이용하여 애플리케이션 구성하는 컴포넌트들을 관리한다.

프로그래머가 작성한 코드는 컨테이너를 사용함으로써 프로그래머의 손을 떠나 컨테이너의 영역으로 떠난다. 즉, 코드를 주되, 객체 생성은 컨테이너가 대신해주고, 이용자의 호출에 의해 컨테이너가 동작하면서 해당 객체를 대신 생성해주는 것.  



스프링 컨테이너의 종류


1.  빈팩토리 BeanFactory  (org.springframework.beans.factory.BeanFactory) 

* 빈 = 스프링에서 생성하는 자바 객체. 즉,  빈 = 객체 

BeanFactory factory = new XmlBeanFactory(new FileInputStream("bean.xml"));
MyBean myBean = (Mybean) factory.getBean("myBean");


getBean()이 호출되면 팩토리는 의존성 주입 (DI) 이용해 빈을 인스턴스화 한다.



2. 어플리케이션 컨텍스트 ApplicationContext 

(org.springframework.context.factory.BeanFactory) 


 빈팩토리와 유사기능 하지만 더 많은 기능 제공하는 어플리케이션 컨텍스트.


가장 많이 사용되는 어플리케이션 컨텍스트 구현체

  • - ClassPathXmlApplicationContext
      •  : 클래스패스에 위치한 xml 파일에서 컨텍스트 정의 내용을 읽어들인다.
  • - FileSystemxmlApplicationContext
      •  : 파일 경로로 지정된 xml 파일에서 컨텍스트 정의 내용을 읽어들인다.
  •  -XmlWebApplicationContext
      •  : 웹 어플리케이션에 포함된 xml 파일에서 컨텍스트 정의 내용을 읽어들인다.



ApplicationContext context = new ClassPathXmlApplicationContext("Spring-Module.xml");
    BoardDAO boardSimpleDAO = (BoardDAO) context.getBean("boardSimpleDAO");


호출시 빈을 생성하는 빈팩토리와는 달리 컨텍스트를 초기화 할때 미리 빈을 생성해놓고 빈이 필요할때 즉시 사용할수 있도록 보장한다. 

BoardDAO boardSimpleDAO = (BoardDAO) context.getBean("boardSimpleDAO");

: 스프링이 생성한 BoardDAO 를 쓴다.

getBean("[bean id]"): 객체를 호출. (기존의 하던 생성대신 호출하는것!) 



xml파일 : 설정파일 

 필요정보를 외부 설정파일로부터 얻는다. **모든 프레임워크는 설정파일(xml)  존재.

ex)

Spring-Module.xml 파일로 가보면

    <import resource="database/Spring-Datasource.xml"/>
    <import resource="board/Spring-Board.xml"/>

import 하고 있는 설정 파일이 또있고. 또 따라가보면, 


    <bean id="boardDAO" class="com.mkyong.board.dao.impl.JdbcBoardDAO">
        <property name="dataSource" ref="dataSource" />
    </bean>

bean의 id 호출하면 프레임워크가 해당 아이디에 연결된 클래스를 준다. 

(책임: 개발자 -> 프레임워크) 

해당 아이디의 클래스를 따라가보면 실재로 해당 클래스가 존재한다. 

여기서는 boardDao 를 호출하면 JdbcBoardDAO 클래스가 호출되는 것.


* property: bean 구성에서  Class 생성 시 필요한 정보들 ..
* name:  set 메서드명. 이 네임은 set뒤 네임과 같다.
    property는 set메서드를 찾아간다.
* ref : bean의 id를 통해 참조형 객체를 넘겨주는것. . set메서드의 매개변수.

 <property name="dataSource" ref="dataSource" />

 set메서드                                       해당 매개변수

 (매개변수 늘어나면 property가 늘어나는것) 



IoC 

Inversion of Control 역제어 

: 객체의 생성에서부터 소멸 까지의 모든 객체에 대한 생명주기 관리 및 책임을 기존의 개발자에서 컨테이너가 하는 것. 즉 IoC는 바로 스프링 컨테이너이다.  스프링 컨테이너는 개발자가 작성한 코드의 컨트롤 (객체의 생성~소멸) 을 대신해주고 개발자는 언제든 필요할때 생성이 아닌 '호출'만 해서 사용하는 것. 

** IoC : 대신해줌  **DI : 갖다씀


DI 

Dependency Injection 의존적 주입 

스프링 컨테이너가 생성한 객체를 개발자는 가져다 주입하여 사용하는 것이다. 이때 이미 생성한 객체를 다른 클래스에 주입하는 것이 의존성 주입이다.  (단어에 쫄지말자... 왜케 어려운말 쓰냐 ㅠ )

의존적 주입을 할때 사용되는 것: ref = '클래스명' **value는 의존이 아니므로 DI개념이 아니다.

ex)

<bean id="boardDAO" class="com.mkyong.board.dao.impl.JdbcBoardDAO">

: Ioc - 스프링 빈이 개발자 대신 객체 생성.

<property name="dataSource" ref="dataSource" />

: DI - ref 를 통해 이미 생성한 객체(dataSource)를 다른 클래스에 주입하여 객체 자체를 매개변수로 사용하는 것. (like DTO)

** Ioc - 주체: 스프링  /  DI - 주체: 개발자  


* 기존 의 객체 생성 및 실행 순서

1. 객체생성 new 2. 의존성 객체생성(클래스내부의) 3.의존성 객체 매서드 호출

스프링의 객체 생성 및 실행순서. (IoC)

1.객체 생성 2. 의존성 객체 주입 DI (스스로 만드는게 아니라 제어권을 스프링이 가지고 스프링이 만들어 놓은 객체를 주입 ref ) 3. 의존성 객체 매서드 호출.


스프링이 모든 의존성 객체를 실행될때 다 만들어주고, 필요한 곳에 주입 시켜줌으로써 Bean들은 싱글톤 패턴의 특징을 가지고, 제어의 흐름 내어주는 것이다. 


 DI의 필수조건

Spring DI위해서는 HAS-A관계에 있는 두 객체(클래스)가 모두 Spring Bean으로 선언 돼 있어야함.


명시적 DI

Spring Bean선언 시 속성(Property)으로 의존 관계에 있는 Bean을 전달할 수도 있다.

ex) [Spring-beans.xml]

<bean id="mService" class="com.service.impl.MemberServiceImpl">
<property name="memberDao" ref="mDao"/>
</bean>
<bean id="mDao" class="com.dao.impl.MemberDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>

위 코드는 두개의 Bean을 선언했고 두 Bean은 서로 의존관계에 있다. 코드 흐름에 따라 Service구현체는 DAO구현체를 필요로 하기 때문에 Service Bean선언에 Dao Bean을 전달하고 있다. 

<property name="memberDao" ref="mDao"/>-->이 작업을 DI라고 함.

ref: 다른 빈을 참조할 것이고 그 Bean을 특정하는 id를 적어준다. 

property: 프로퍼티 속성을 사용하게 되면 빈 클래스에 setter메서드가 반드시 존재한다.

public class MemberServiceImpl implements MemberService {

private MemberDao mDao; //Dao 인스턴스 저장할 멤버 변수

public void setMemberDao(MemberDao mDao){
//<property name="memberDao" ref="mDao" />에 대응되는 setter 메서드.
this.mDao = mDao;
}
}

setter메서드의 매개변수는 DI되는 클래스의 타입이다.


묵시적 DI

DI역시 시스템 규모가 커짐에 비례하여 설정 파일에 적어야할 코드가 점점 늘어나 관리가 불편해진다. 이 불편을 해소하고자 IoC와 마찬가지로 Annotation을 활용하여 의존관계를 설정할 수 있게끔 할 수 있다.

ex) [Spring-beans.xml]

<bean id="mService" class="com.service.impl.MemberServiceImpl">
</bean>
<bean id="mDao" class="com.dao.impl.MemberDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>

위코드로는 DI코드가 명시되어 있지 않으므로 코드만으로는 두 빈(mService와 mDao)의 의존관계를 알 수 없다.

public class MemberServiceImpl implements MemberService{
@AutoWired private MemerDao mDao;

@AutoWired : MemeberDao와 일치하는 타입을 찾아 DI.

명시적 DI에서는 참조(ref)할 Bean을 지정했는데, 이 @Autowired Annotation은 Bean을 객체의 1)타입으로 먼저 찾고 일치하면 그 인스턴스를 대입하게 된다.타입으로 일치하는 객체가 없다면 2)ID로 찾게 된다. 

**만약 객체의 타입이 아니라 내가 설정한 빈의 id로 찾고자 한다면 이때는 어노테이션 @Resource 을 사용하면 된다. 이 @은 객체 ID로 먼저 찾고, 일치하는 아이디 없을 경우 타입으로 찾는다.

@Resource(name="mDao")
private MemberDao mDao;

객체의 타입을 찾되 ID까지 일치하도록 강제사항을 두고자 한다면 @Qualifier추가하면 된다.

@AutoWired //객체의 타입으로 검색
@Qualifier("mDao") //id가 mDao인 Bean검색.
private MemberDao mDao;



* 묵시적 DI를 지원하는 @어노테이션 종류.

  어노테이션 

 제공처 

  설명

  @Autowired

 Spring Framework 

 1.타입 검색 2.ID검색 

  @Resource

 Standard Java

 1.ID검색 2. 타입검색 

  @Qualifier

 Spring framework

 ID,타입 모두 일치하는 경우로 검색. (AND 조건으로 강제)






반응형