레이블이 spring인 게시물을 표시합니다. 모든 게시물 표시
레이블이 spring인 게시물을 표시합니다. 모든 게시물 표시

2019년 3월 10일 일요일

[인프런] 스프링 프레임 워크 핵심 기술 수강 후기

스프링 프레임 워크 핵심 기술 수강 후기

사수님의 지식 공유로 백기선님에 대해 알게되었다. 처음에는 유튜브에 있는 영상만 보다가 인프런에서 직접 강의를 올리시는 것을 알게 되었고, 그 중 나에게 도움이 되면서 비교적 저렴한 강의를 찾다 '스프링 프레임워크 핵심 기술' 이라는 강의를 구매하였다.
이 강의에서는 스프링의 핵심기술을 이해하여, 스프링이 제공하는 다른 기능(JDBC, 테스트, MVC, 스프링부트 등)을 더 쉽고 정확하게 이해할 수 있게할 수 있는 베이스지식을 제공한다.
스프링하면 떠오르는 IoCAOP 에 대한 내용이 강의의 대부분을 차지하며, 이것이 무엇 이며 어떻게 제공되는지 설명하고 있다.
코드를 따라하면서 진행하는 강의는 아니었지만, 테스트 예제코드를 통해 설명을 해주셔서 이해하기 더 편했고, 재미있었다. 내 머리속에 애매하게 있던 지식들이 조금씩 정리가 되는 느낌이여서 매우 좋았다.
하지만, 엄청 깊게 설명하는 방향보다는 소개와 이해 중심의 강의여서 직접 써보면서 찾아봐야 확실하게 이해가 될 것 같은 느낌이었다. 모든 강의가 그렇겠지만 보는 것으로 끝나면 남는게 없다.
직접 해보고 내 머리속에 저장하자!
완강 후에는 바로 백기선님의 스프링 웹 MVC 강의도 구매하였다.
처음에는 '구글에 자료도 많고 잘 정리된 블로그도 많은데 왜 돈 주고 강의를 사야하지' 라는 생각이 있었는데, 생각을 조금만 해보면 고작 책 몇권 가격으로 내 소중한 시간을 아끼면서 좋은 지식을 습득할 수 있다면 구매할 가치가 충분하다. 매우
이것이 시간을 돈으로 살 수 있는 것이 아닐까?? 물론 내 것으로 만든다는 가정하에...




인프런 - 스프링 프레임워크 핵심기술
https://www.inflearn.com/course/spring-framework_core/

2019년 1월 13일 일요일

스프링에서 선언식 트랜잭션 간단하게 실습해보기

트랜잭션이란??

정보처리기사에 정말 많이 나오는 개념으로 all or nothing 이라고 생각하면 된다.
'모두 처리 아니면 모두 X'
예를 들면, 트랜잭션이 적용된 어떠한 행동이 3가지의 insert , update, insert의 쿼리를 수행하는 행동일 때,
insert 성공
update 성공
insert 실패
가 되었을 때 앞의 insert와 update 쿼리가 성공이 되었을 지라도 마지막 insert가 실패되었기 때문에 모두 롤백이 되어야하는 개념이다.
스프링에서 트랜잭션은 선언식 트랜잭션과 프로그램에 의한 트랜잭션을 통해 사용할 수 있는 것 같다.
선언식 트랜잭션 중 어노테이션방법을 게시판의 예제로 간단하게 살펴보자
사용자가 게시물을 클릭한다고 생각하면 다음의 순서로 진행된다. 
1. 조회수가 오른다. (update)
2. 게시물의 데이터를 가져온다. (select)
만약 이때 2. select 과정에서 오류가 발생한다고 가정한다면, 게시물의 데이터를 못가져왔으므로 조회가 되지않는다. 그렇다면 조회수도 오르지 말아야한다.
(예시가 좀 이상하다. 적절한 예시를 찾아서 수정해야할듯...)
이 행동에 대해서 트랜잭션을 적용해보겠다.

root-context.xml
...

    <!-- transactionManager -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

...
servlet-context.xml
...

<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>

...
serviceImpl
package com.wpp.service;
...
import org.springframework.transaction.annotation.Transactional;
...

@Service
public class BoardServiceImpl implements BoardService{
...


@Transactional
public Object read(int bnum) throws Exception {
    Object object = null;

    //조회수 올리기
    boardDao.uphit(bnum);

    //게시물 내용
    object = boardDao.read(bnum);

    //트랜잭션 테스트를 위한 Exception 발생
    if( object == null) {
        throw new RuntimeException();
    }

    return object;
}


...
}
아까 만든 가정대로 테스트를 하기위해
다음과 같이 object가 null이면 RuntimeException 을 발생시켜보았다.
breakpoint를 잡고 object = freeboardDao.read(bnum); 부분에 bum의 값을 DB에 없는 값을 줘서 object를 null이 나오도록 하였다.
@Transactional 어노테이션이 없을 때는 해당 Exception이 발생하더라도 그 전의 조회수가 올라가는 것을 볼 수 있지만, 어노테이션을 추가한 후에는 조회수 부분이 rollback 된 것을 볼 수 있다.

@Transactional 에는 다양한 속성을 지정해줄 수 있다.
ex_) @Transactional(isolation=Isolation.DEFAULT, timeout=10)
- 격리레벨 : 데이터에 대한 격리
  - ex_) 커밋된 데이터 읽기 허용, 커밋되지 않는 데이터 읽기 허용 등)
- 전파 : 트랜잭션 중 다른 트랜잭션 호출할 때의 경우
  - ex_) 기존에 실행되고 있는 트랜잭션이 있으면 참여 아니면 새로 생성, 무조건 트랜잭션 새로 생성
- readonly : 트랜잭션을 읽기전용으로 적용
  - ex_) 쓰기작업 발생 시 예외발생(기본설정은 false)
- rollbackFor : 특정 예외가 발생할 경우 롤백 처리 설정
  - ex_) : 스프링의 데이터엑세스 예외는 RuntimeException 이므로, 런타임예외만 롤백대상이므로 다른예외도 추가하는 방식...인가????
- timeout : timeout발생 시 롤백 처리(초단위같음)
  - ex_) : 지정된 시간안에 수행이 되지 않으면 롤백

어노테이션 외에도 aop를 이용해 service단의 모든 메소드에 트랜잭션을 적용시킬 수 있다.

게시판에 트랜잭션을 적용하려고 다시 소스를 보았는데.....
정말 개판이다..

물론 이 때는 게시판을 만들어보는 것에 목적으로 두고 생성하였지만,
참...ㅋㅋㅋ 이 구조는 왜 이런식이며...service단은 그냥 쿼리를 호출하는 거랑 뭐가 다르게 만들어졌으며..

너무 못짰다. 이게 뭐야ㅠㅠㅠㅠㅠㅠㅠㅠ
얘를 개선할 수 있을까?
todo
aop 예제도 해보자.

2017년 11월 29일 수요일

토비의 스프링 공부/정리 [3]

회사에서 토비의 스프링 스터디를 시작하였다.
새로운 기분으로 정독하고 있으며, 정리한 내용을 학습목적으로 git에 올리고 있다.
이해가 가지 않는 내용도 있지만, 일단 1회독을 마치는 것을 목표로 진행하자!









//////////////////////////////////////////////////////////////////////////////////////////////


3. 템플릿


템플릿이란 바뀌는 성질이 다른 코드 중에서 변경이 거의 일어나지 않으며 일정한 패턴으로 유지되는 특성을 가진 부분을 자유롭게 변경되는 성질을 가진 부분으로 독립시켜서 효과적으로 활용할 수 있도록하는 방법. (??)
3장에선 스프링에 적용된 템플릿 기법을 살펴보고, 이를 적용해 완성된 DAO코드를 만드는 방법을 소개한다.


3.1 다시 보는 초난감 DAO

책에서 소개한 UserDao 코드에는 예외상황에 대한 처리 부분에 문제점이 있다고 한다.
preparedstatement를 처리하는 중 예외가 발생하면 close를 실행못하고 마치게된다. 이것이 계속쌓이면 리소스가 부족하다는 오류가 발생할 수 있다. 그래서 try/catch 구문으로 예외처리를 하도록 권장한다.
글 조회부분 또한 ResultSet도 반환해야하는 리소스이기 때문에 예외상황에서도 ResultSet의 close()메소드가 반드시 호출되도록 만들어줘야 한다.

리소스 반환과 close()

Connection이나 PreStatement에는 close()메소드가 있다. 종료라고 볼 수도 있지만 보통 리소스를 반환한다는 의미로 이해하는 것이 좋다. Connection과 PreparedStatement는 보통 풀(pool) 방식으로 운영된다. 미리 정해진 풀 안에 제한된 수의 리소스(Connection, Statement)를 만들어 두고 필요할 때 이를 할당하고, 반환하면 다시 풀에 넣는 방식으로 운영된다. 요청이 매우 많은 서버 환경에서는 매번 새로운 리소스를 생성하는 대신 풀에 미리 만들어둔 리소스를 돌려가며 사용하는 편이 훨씬 유리하다. 대신. 사용한 리소스는 빠르게반환해야 한다. 그렇지 안흥면 풀에 있는 리소스가 고갈되고 결국 문제가 발생한다. close()메소드는 사용한 리소스를 풀로 다시 돌려주는 역할을 한다.

3.2 변하는 것과 변하지 않는 것

finally 블록의 c.close() 라인 하나 빼먹은 것과 같은 실수를 했어도 테스트를 돌려보면 별 문제가 없어 보인다. 하지만 해당 메소드가 호출되고 나면 커넥션이 하나씩 반환되지 않고 쌓여가게 된다. 이를 그대로 사용하면 최대 DB커넥션 개수를 넘어설 것이고, 서버에서 리소스가 꽉 찼다는 에러가 나면서 서비스가 중단되는 상황이 발생한다.
>>이런 예외상황을 처리하는 코드는 테스트하기 매우 어렵고 번거롭다.
>> 효과적으로 다루기위해선..??

분리와 재사용을 위한 디자인 패턴 적용

책에서는 UserDao의 메소드를 개선하고 있다.
*****어려움 ㅠㅠ

3.3 JDBC 전략 패턴의 최적화


3.4 컨텍스트와 DI


3.5 템플릿과 콜백


3.6 스프링의 JdbcTemplate

2017년 11월 6일 월요일

토비의 스프링 공부/정리 2장

회사에서 토비의 스프링 스터디를 시작하였다.
새로운 기분으로 정독하고 있으며, 정리한 내용을 학습목적으로 git에 올리고 있다.
이해가 가지 않는 내용도 있지만, 일단 1회독을 마치는 것을 목표로 진행하자!



2. 테스트

저자는 스프링이 개발자에게 제공하는 것들 중 객체지향과 테스트가 가장 중요한 가치라고 하며 2장을 시작한다.
스프링으로 개발을 하면서 테스트를 만들지 않는다면 이는 스프링이 지닌 가치의 절반을 포기하는 셈이다.

테스트란? 
- 코드의 결함 제거(디버깅) --> 의도한대로 나올 수 있도록 수정해 나가는 작업 
- 내가 예상하고 의도했던 대로 코드가 정확히 동작하는지를 확인해서 만든 코드를 확신할 수 있게 해주는 작업 

책에서는 웹을 통한 DAO테스트 방법의 2가지 문제점에 대해 말하고 있다. 
1. 수동 확인 작업의 번거로움: 테스트 결과를 확인하는 작업을 사람의 눈으로 해야함. 
2. 실행 작업의 번거로움: 전체 기능을 테스트해보기 위해 main 메소드를 수백 번 실행하는 수고가 필요함.
  • ++DAO뿐만 아니라 서비스 클래스, 컨트롤러, 뷰 등 모든 레이어의 기능을 다 만들고 나서야 테스트가 가능 (이 경우 오류가 발생했을 때 어느부분에서 오류가 발생하였는지 파악이 어렵고, 빠르고 정확히 대응하기 어려움)
단위테스트란?(Unit Test)
- 작은 단위의 코드에 대해 테스트를 수행한 것
- 테스트의 관심이 다르다면 테스트할 대상을 분리하고 집중해서 접근해야한다.
- 단위 테스트를 하는 이유는 개발자가 설계하고 만든 코드가 원래 의도한 대로 동작하는지를 
개발자 스스로 빨리 확인 받기 위해서이다.
이 후 이 2가지 문제점에 대해 개선하는 작업을 보여주고 있다.
  1. 테스트 검증의 자동화
    • 테스트의 결과 값들을 사람의 눈으로 직접 확인하는 것이 아닌 테스트 수행과 기대하는 결과에 대한 확인까지 해주는 코드로 된 자동화된 테스트를 해야한다고 하고있다.
  2. 테스트의 효율적인 수행과 결과 관리
  • main() 메소드를 이용한 테스트 작성 방법만으로는 애플리케이션 규모가 커지고 테스트 개수가 많이지면 테스트를 수행하는 일이 점점 부담이 된다며, JUnit 을 소개하고있다.
JUnit 프레임워크
자바 테스팅 프레임워크로 JUnit을 통해 단위테스트가 가능하다.
책에서는 스프링을 학습하고 제대로 활용하려면 최소한의 JUnit 테스트 작성 방법과 실행방법은 알고있어야한다고 하고있다.
스프링의 핵심 기능 중 하나인 스프링 테스트 모듈도 JUnit을 이용하고 있다고 한다.
JUnit의 간단한 사용법과 테스트 방법을 설명한 후 테스트 결과의 일관성을 설명하고 있다. 
(책에서는 사용자를 추가하는 테스트를 수행하고있는데, 한번 수행 후 또 다시 테스트를 실행시키면 사용자가 중복되기 때문에 문제가 발생하기 때문에 테스트 전에 등록된 사용자 정보를 초기화 시켜주는 작업을 하여 동일한 테스트 결과를 나타날 수 있게 하는 과정을 설명하고있다.)
  - 반복적으로 테스트를 수행하였을 때, 항상 동일한 결과가 나와야한다.
  - 단위테스트는 코드가 바뀌지 않는다면 매번 실행할 때마다 동일한 테스트 결과를 얻을 수 있어야 한다.
"항상 네거티브 테스트를 먼저 만들라" 
부정적인 케이스를 먼저 만드는 습관을 들이는게 좋다.
테스트 주도 개발(Test Driven Development-TDD)이란?
만들고자 하는 기능의 내용을 담고 있으면서 만들어진 코드를 검증도 해줄 수 있도록
테스트 코드를 먼저 만들고, 테스트를 성공하게 해주는 코드를 작성하는 방식의 개발 방법
("실패한 테스트를 성공시키기 위한 목적이 아닌 코드는 만들지 않는다")
TDD의 장점
 코드를 만들어 테스트를 실행하는 그 사이의 간격이 매우 짧다.
(오류를 빨리 발견할 수 있다.)

스프링은 JUnit을 이용하는 테스트 컨텍스트 프레임워크를 제공한다. 라고하며, 의존성 주입을 이용한 테스트를 소개하고 있다. (이 부분은 직접 실습을 해보면서 하는 게 좋을 듯 하다.)
@Autowired가 잠깐 나오는데, 2권에서 자세하게 설명한다고 되어 있다.
- Autowired 가 붙은 인스턴스 변수가 있으면, 테스트 컨텍스트 프레임워크는 변수 타입과 일치하는 컨텍스트 내의 빈을 찾는다. 
타입이 일치하는 빈이 있으면 인스턴스 변수에 주입해준다.

학습테스트(learning test)란?
자신이 만들지 않은 프레임워크나 다른 개발팀에서 만들어서 제공한 라이브러리 등에 대해서는 테스트를 작성해야한다.

-목적: 자신이 사용할 API나 프레임워크의 기능을 테스트로 보면서 사용 방법을 익히려는 것
-장점
1. 다양한 조건에 따른 기능을 손십게 확인 가능
2. 학습 테스트 코드를 개발 중에 참고할 수 있음.
3. 프레임워크나 제품을 업그레이드할 때 호환성 검증을 도와줌.
4. 테스트 작성에 대한 좋은 훈련이 됨.
5. 새로운 기술을 공부하는 과정이 즐거워짐.

버그테스트(bug test)란?
코드에 오류가 있을 때 그 오류를 가장 잘 드러내줄 수 있는 테스트
(일단 실패하도록 만들어야함. 그 후 성공할 수 있도록 애플리케이션 코드를 수정함.)
필요성과 장점
1. 테스트의 완성도를 높여줌
2. 버그의 내용을 명확하게 분석하게 해줌
3. 기술적인 문제를 해결하는 데 도움이 됨


동등분할: 같은 결과를 내는 값의 범위를 구분해서 각 대표값으로 테스트 하는 방법

경계값 분석: 에러는 동등분할 범위의 경계에서 주로 많이 발생한다는 특징을 이용해서 경계의 근처에 있는 값을 이용해 테스트하는 방법.







//////////////////////////////////////////////////////////////////////////////////////////////


2. 테스트

스프링이 개발자에게 제공하는 가장 중요한 가치는? >> 객체지향과 테스트
스프링은 IoC/Di를 이용해 객체지향 프로그래밍 언어의 근본과 가치를 개발자가 손쉽게 적용하고 사용할 수 있게 도와주는 기술, 동시에 복잡한 엔터프라이즈 애플리케이션을 효과적으로 개발하기 위한 기술. 
테스트는 스프링이 강조하고 가치를 두고 있다. 테스트를 통해 만들어진 코드를 확신할 수 있게 해주고, 변화에 유연하게 대처할 수 있는 자신감을 준다. 
2장에서는 테스트란 무엇이며, 그 가치와 장점, 활용 전략, 스프링과의 관계를 살펴본다.

2.1 UserDaoTest 다시보기

테스트란 내가 예상하고 의도했던 대로 코드가 정확히 동작하는지를 확인해서, 만든 코드를 확신할 수 있게 해주는 작업. 테스트의 결과가 원하는대로 나오지 않을 경우 코드나 설계에 결함이 있음을 알 수 있음. 이를 통해 코드의 결함을 제거해가는 작업, 일명 디버깅을 거치게 되고, 결국 최종적으로 테스트가 성공하면 모든 결함이 제거됐다는 확신을 얻을 수 있음.

웹을 통한 DAO테스트 방법의 문제점

DAO뿐만 아니라 서비스 클래스, 컨트롤러, JSP 뷰 등 모든 레이어의 기능을 다 만들고나서 테스트가 가능하다. 이 때문에 테스트도중 에러가 발생하면 에러를 간단히 찾을 수 없게 된다. >> 다른 계층의 코드와 컴포넌트, 심지어 서버의 설정 상태까지 모두 테스트에 영향을 줄 수 있기 때문에 이런 방식으로 테스트하는 것은 번거롭고, 오류가 있을 때 빠르게 대응이 어렵다.

작은 단위의 테스트

테스트는 가능하면 작은 단위로 쪼개어 집중해서 할 수 있어야 한다. 관심사의 분리라는 원리는 여기에도 적용됨. 
작은 단위의 코드에 대해 테스트를 수행한 것을 단위 테스트라 한다. 
>> 단위 테스트 없이 긴 테스트를 수행하는 경우, 수많은 에러가 발생하거나 에러가 안나지만 기능이 제대로 동작하지 않을 수 있음. 이때 문제의 원인을 찾기 힘들다.  하지만 단위 별로 테스트를 진행한 후 긴 테스트를 한다면, 에러나 실패가 발생할 수 도 있겠지만, 이미 각 단위별로 검증을 마친 상태이므로 훨씬 더 나을 것임이다.

자동수행 테스트 코드

테스트는 자동으로 수행되도록 코드로 만들어지는 것이 중요함.
번거로운 작업 없이 테스트를 빠르게 실행 할 수 있기 때문에 언제든 코드를 수정하고나서 테스트를 해볼 수 있음. 

지속적인 개선과 점직적인 개발을 위한 테스트

테스트를 통해 기능을 추가해가면서 점직적인 개발이 가능하고 기존에 만들었던 기능에 영향을 주지 않고 확인할 수 있음.


책에서 소개한 UserDaoTest의 문제점을 서술하고 있다.

수동확인 작업의 번거로움: 테스트의 수행은 자동으로 진행되지만 결과확인은 사람의 책임이므로 완전히 자동으로 테스트되는 방법이라고 할 수 없음.

실행 작업의 번거로움: 매번 main() 메소드를 실행하는 것은 분거로움으로 좀 더 편리하고 체계적으로 테스트를 실행하고 그 결과를 확인하는 방법이 필요.

2.2 UserDaoTest 개선

테스트 검증의 자동화

책에선 가져오는 오브젝트의 값을 비교해서 확인하는 것을 추가하여 첫번째 문제점인 결과확인 작업까지 테스트 코드에 추가하였다. 

테스트의 효율적인 수행과 결과 관리

좀 더 편리하게 테스트를 수행하고 편리하게 결과를 확인하려면 단순한 main 메소드로는 한계가 있음. 일정한 패턴을 가진 테스트를 만들 수 있고, 많은 테스트를 간단히 실행시킬 수 있으며, 테스트 결과를 종합해서 볼 수 있고, 테스트가 실패한 곳에서 빠르게 찾을 수 있는 기능을 갖춘 테스트 지원 도구와 그에 맞는 테스트 작성 방법이 필요.
자바에서는 실용적인 테스트를 위한 도구가 여러가지 존재함. >> JUnit를 통해 자바로 단위 테스트를 만들 때 유용하게 쓸 수 있다.

JUnit 테스트로 전환

JUnit은 프레임워크이다. 1챕터에서 프레임워크의 기본 동작원리가 바로 제어의 역전(IoC)라고 했다. 프레임워크는 개발자가 만든 클래스에 대한 제어 권환을 넘겨받아서 주도적으로 애플리케이션의 흐름을 제어한다. 개발자가 만든 클래스의 오브젝트를 생성하고 실해아는 일은 프레임워크에 의해 진행된다. 따라서 프레임워크에서 동작하는 코드는 main()메소드가 필요 없고 오브젝트를 만들어서 실행시키는 코드를 만들 필요도 없다.


테스트 메소드 전환

기존의 책에서 소개한 main()메소드 테스트는 이런 면에서 프레임워크에 적용하기에 적합하지 않다. >> 테스트가 main()메소드로 만들어졌다는 것은 제어권을 직접 갖는다는 의미이기 때문
책에서 새로 만들 테스트 메소드는 JUnit 프레임워크가 요구하는 조건 두 가지를 따라야한다고 한다. 1. 메소드가 public으로 선언 2. 메소드에 @Test라는 어노테이션 붙이기


검증 코드 전환

책에서 앞서 소개한 결과를 확인할 때 사용한 if/else문을 asserThat이라는 스태틱 메소드를 이용해 변경하고 있다. 

2.3 개발자를 위한 테스팅 프레임워크 JUnit

스프링을 학습하고 제대로 활용하려면 최소한의 JUnit 테스트 작성 방법과 실행 방법은 알고 있어야 한다.
JUnitCore(JUnit API 인듯?)를 이용해 테스트를 실행하고 콘솔에 출력된 메시지를 보고 결과를 확인하는 ㅂ아법은 가장 간단하긴 하짐나 테스트의 수가 많아지면 관리하기 힘들어지므로 자바 IDE에 내장된 JUnit 테스트 지원도구를 사용하는 것이 좋다.

IDE
이클립스에서 @Test가 들어있는 테스트클래스를 선택한 뒤 run as 항목 중 junit test를 선택하면 테스트를 실행시킬 수 있다. >> 테스트의 총 수행시간, 실행한 테스트의 수, 테스트 에러의 수, 테스트 실패의 수를 확인할 수 있음.
빌드 툴
프로젝트의 빌드를 위해 ANT나 메이븐 같은 빌드 툴과 스크립트를 사용하고 있다면, 빌드 툴에서 제공하는 JUnit 플러그인이나 태스크를 이용해 JUnit테스트를 실행할 수 있다.
>>여러 개발자가 만든 코드를 통합해서 테스트를 수행해야할 때는 서버에서 모든 코드를 가져와 통합하고 빌드한 뒤에 테스트를 수행하는 것이 좋다고 함...


테스트 결과의 일관성

데이터베이스를 사용하는 테스트 후 데이터가 남아있다면 다음 테스트 때 오류가 발생할 수 도 있기때문에 테스트 후 이전상태의 데이터로 만들어줘야 한다. 
책에선 deleteAll()라는 메소드를 추가하여 데이터를 지우고 테스트를 시작한다.


>>개발자는 빨리 테스트를 만들어 성공하는 것을 보고 다음 기능으로 나아가고 싶어하기 때문에, 긍정적인 경우를 골라서 성공할만한 테스트를 먼저 작성하게 되기 쉽다. 그래서 테스트를 작성할 때 부정적인 케이스를 먼저 만드는 습관을 들이는 것이 좋다고 함. (ex id를 정확하게 가져오는 것도 중요하지만, 존재하지 않는 id가 주어졌을때 어떻게 반응할지를 먼저 결정하고 이를 확인할 수 있는 테스트를 만들려고 한다면 예외적인 상황을 빠뜨리지 않는 꼼꼼한 개발이 가능하다고 한다.


테스트 주도 개발(Test Driven Development, TDD)

만들고자 하는 긴으의 내용을 담고 있으면서 만ㄷ느렁진 코드를 검증도 해줄 수 있도록 테스트 코드를 먼저 만들고, 테스트를 성공하게 해주는 코드를 작성하는 방식의 개발 방법.
>>아예 테스트를 먼저 만들고 그 테스트가 성공하도록 하는 코드만 만드는 식으로 진행

JUnit이 하나의 테스트 클래스를 가져와 테스트를 수행하는 방식

1. 테스트 클래스에서 @Test가 붙은 public이고 void형이며 파라미터가 없는 테스트 메소드를 모두 찾는다.
2. 테스트 클래스의 오브젝트를 하나 만든다.
3. @before가 붙은 메소드가 있으면 실행한다.
4. @Test가 붙은 메소드를 하나 호출하고 테스트 결과를 저장해둔다.
5. @After가 붙은 메소드가 있으면 실행한다.
6. 나머지 테스트 메소드에 대해 2~5번을 반복
7. 모든 테스트의 결과를 종합해서 돌려준다. 

픽스처

테스트를 수행하는데 필요한 정보나 오브젝트
>>책에선 테스트를 하기위한 유저정보(픽스처인듯?)를 @Before 를 통해 선언

2.4 스프링 테스트 적용

테스트를 위한 애플리케이샨 컨텍스트 관리

책에서 DI를 통해 오브젝트를 주입받아 테스트를 하는 방법을 소개하고 있다.
(생략 or 더 추가??)

@Autowired

스프링의 DI에 사용되는 특별한 어노테이션, @Autowired가 붙은 인스턴스 변수가 있으면, 테스트 컨텍스트 프레임워크는 변수 타입과 일치하는 컨텍스트 내의 빈을 찾는다. 타입이 일치하는 빈이 있으면 인스턴스 변수에 주입해준다.  


침투적 기술과 비침투적 기술

침투적(invasive) 기술은 기술을 적용했을 때 애플리케이션 코드에 기술 관련 API가 등장하거나, 특정 인터페이스나 크랠스를 사용하도록 강제하는 기술, 침투적 기술을 사용하면 애플리케이션 코드가 해당 기술에 종속되는 결과를 가져옴
비침투적(noninvasive) 기술은 애플레키에션 로직을 담은 코드에 아무런 영향을 주지 않고 적용가능. 따라서 기술에 종속적이지 않은 순수한 코드를 유지 
스프링은 비침투적 기술의 대표적 예
>>책에서 @autowird를 이용하지 않고 직접 오브젝트를 생성하여 테스트하는 방법을 소개하고 있다. 

(책에선 DI를 테스트에 이용하는 세가지 방법을 소개한 후 장점들을 소개하였음.)


2.5 학습 테스트로 배우는 스프링

학습테스트: 자신이 만들지 않은 프레임워크나 다른 개발팀에서 만들어서 제공한 라이브러리 등에 대해서도 테스트를 작성하는 것
>> 이를 통해 자신이 사용할 API나 프레임워크의 기능을 테스트로 보면서 사용방법을 익히려는 것


학습테스트의 장점

1. 다양한 조건에 따른 기능을 손쉽게 확인해 볼 수 있음.
2. 학습 테스트 코드를 개발 중에 참고할 수 있음.
3. 프레임워크나 제품을 업그레이드할 때 호환성 검증을 도와줌.
4. 테스트 작성에 대한 좋은 훈련이 됨.
5. 새로운 기술을 공부하는 과정이 즐거워짐. 


버그테스트

코드에 오류가 있을 때 그 오류를 가장 잘 드러내줄 수 있는 테스트.
버그테스트는 버그가 원인 되서 테스트가 실패하는 코드를 만들도록 해야함. 이 후 버그 테스트가 성공할 수 있도록 애플리케이션의 코드를 수정한다. 

버그테스트의 장점
1. 테스트의 완성도를 높여줌.
2. 버그의 내용을 명확하게 분석하게 해줌.(버그로 인해 발생할 수 있는 다른 오류들을 발견할 수 있고 이를 테스트의 중요한 기법 중의 하나인 동등분할이나 경계값 분석을 적용해 볼 수 있음)
3. 기술적인 문제를 해결하는데 도움.

동등분할(equivalence partitioning)
같은 결과를 내는 값의 범위를 구분해서 각 대표 값으로 테스트하는 방법. 어떤 작업의 결과의 종류가 true, false 또는 예외발생 세가지라면 각 결과를 내는 입력 값이나 상황의 조합을 만들어 모든 경우에 대한 테스트를 해보는 것이 좋다.
경계값 분석(boundary value analysis) 
에러는 동등 분할 범위의 경게에서 주로 많이 발생한다는 특징을 이용해서 경계의 근처에 있는 값을 이용해 테스트하는 방법. 보통 숫자의 입력 값인 경우 0 이나 그 주변 값 또는 정수의 최대값, 최소값 등으로 테스트해보면 도움이 될 때가 많음. 

2017년 10월 29일 일요일

토비의 스프링 공부/정리 1장


회사에서 토비의 스프링 스터디를 시작하였다.
새로운 기분으로 정독하고 있으며, 정리한 내용을 학습목적으로 git에 올리고 있다.
이해가 가지 않는 내용도 있지만, 일단 1회독을 마치는 것을 목표로 진행하자!

https://github.com/cotgyu/toby_springstudy


1. 오브젝트와 의존관계

스프링 프레임워크에서 가장 중요한 것은 오브젝트(생성, 다른 오브젝트와의 관계, 사용, 소멸)이라 설명하면서, 스프링은 오브젝트를 어떻게 효과적으로 설계하고 구현, 사용 , 어떻게 개선해야하는 가의 기준을 마련해준다고 한다.
객체지향 기술, 설계, 구현, 검증된 프렉티스를 프레임워크로 제공

어떠한 변경이 일어날 때, 필요한 작업을 최소화하고 다른 곳에 영향이 가지 않게 하는 것이 중요한데, 이를 분리와 확장을 고려한 설계라 한다. 이 분리의 개념 중 하나인 관심사의 분리를 책에서 단계별 예제를 통해 소개하고 있다.
관심사의 분리 - 관심이 같은 것은 하나의 객체 안으로, 관심이 다른 것은 가능한 떨어뜨려 서로 영향이 가지 않게 분리

책에서는 간단한 사용자를 등록하는 UserDao를 제시하였는데, 여기에는 3가지 관심사가 있다.
  1. DB연결을 위한 커넥션
  2. SQL을 실행하는 statement
  3. statement, 커넥션 닫기
1장에서는 1번을 분리와 확장을 고려하여 개선하는 작업을 수행하였다.
첫번째로 이 커넥션 부분을 getConnention 이라는 함수로 빼내었고, 이를 통해 분리하였다. (메소드 추출 기법)
두번째로는 커넥션 확장을 위해 상속을 사용하였다. UserDao를 상속하고 서브클래스에서 추상메소드인 getConnention을 구현하여 DB커넥션 연결이라는 관심을 서브클래스로 분리하여 각자 원하는 구성의 getConnention을 사용하는 소개하고있다.
템플릿 메소드 패턴 - 슈퍼클래스의 기본적인 로직흐름을 만들고, 그 기능의 일부를 추상메소드나 오버라이딩이 가능한 메소드 등 
으로 만든 뒤 서브클래스에서 필요에 맞게 구현, 사용하는 방법

팩토리 메소드 패턴 - 상속을 통해 기능을 확장하는 패턴으로 서브클래스에서 구체적인 오브젝트 생성방법을 결정한다.
하지만 이 상속을 이용한 방법도 슈퍼클래스 내부의 변경이 있을 때 모든 서브클래스를 함게 수정하거나 다시 개발할 수 있는 단점이 있음.(생각보다 밀접한 관계)
그래서 책에서는 세번째로 상속이 아닌 인터페이스를 통해 클래스를 분리하는 것을 소개한다. 이를 통해 UserDao는 인터페이스의 메소드를 통해 알 수 있는 기능에만 관심을 가지면 되지, 그 기능을 어떻게 구현했는지에는 관심을 둘 필요가 없어진다. (최종족으로 UserDao는 ConnentionMaker라는 인터페이스 외에는 어떤 클래스와 관계를 갖지 않게 개선하였다.)

책에서는 이 UserDao를 개선해온 결과를 객체지향 기술의 여러가지 이론을 통해 설명하였다.
개방 폐쇄 원칙(OCP) - 클래스나 모듈은 확장에는 열려 있어야하고 변경에는 닫혀있어야한다. (객체지향설계원칙)

높은 응집도 - 하나의 모듈이나 클래스가 하나의 책임 또는 관심사에 집중되어 있다.
낮은 응집도 - 하나의 오브젝트가 변경이 발생할 때, 관계를 맺고있는 다른 오브젝트에 변경을 최소화한다.

전략패턴 - 필요에 따라 변경이 필요한 알고리즘을 인터페이스를 통해 통째로 외부로 분리시키고, 이를 구현한 구체적인 알고리즘 
클래스를 팔요에 따라 바꿔서 사용할 수 있게 하는 디자인 패턴  
ex) DB연결방식(ConnentionMaker) - 알고리즘
스프링은 이러한 객체지향적 설계원칙과 디자인 패턴에 나타난 장점을 자연스럽게 개발자들이 활용할 수 있게 해주는 프레임워크라고 소개하고 있다.

책에서는 어떤 ConnectioNmaker를 사용할지 결정하는 기능을 UserDaoTest가 맡고 있는데, 이를 분리하면서 팩토리의 개념을 설명하고 있다.
(DaoFactory를 통해 UserDao타입의 오브젝트를 어떻게 만들고, 어떻게 준비하는지를 결정하도록 개선하였다.)
팩토리 - 객체의 생성방법을 결정하고 만들어진 오브젝트를 돌려줌.

이를 통해 책에서는 기존의 Dao는 모든 종류의 작업을 사용하는 쪽에서 제어하는 반면, 개선된 Dao는 ConnectionMaker의 구현 클래스 결정과 오브젝트의 생성의 제어권이 DaoFactory에 있음을 비교하며 IoC를 설명하고 있다.
 IoC(제어의 역전) - 객체에 대한 제어권이 개발자로 부터 컨테이너에 넘어가면서 객체의 생성부터 생명주기 관리까지의 
 모든 것을 컨테이너가 맡아서 함
스프링은 IoC를 극적으로 적용하고 있는 프레임워크

스프링의 IoC
빈(bean): 스프링이 제어권을 가지고 직접 만들고 관계를 부여하는 오브젝트
(스프링 빈 - 스프링 컨테이너가 생성과 관계설정, 사용 등을 제어해주는 제어의 역전이 적용된 오브젝트)

빈 팩토리: 빈의 생성과 관계설정 같은 제어를 담당하는 IoC오브젝트
(어플리케이션 컨텍스트 - 별도의 정보를 참고해 빈의 생성, 관계 설정 등 제어작업 총괄)

어노테이션
@Configuration - 스프링이 오브젝트 설정을 담당하는 클래스로 인식
(어플리케이션 컨텍스트가 사용할 설정 정보)
@bean: 오브젝트 생성 담당

Application Context: 어플리케이션에서 IoC를 적용해서 관리할 모든 오브젝트에 대한 생성과 관계설정을 담당
- 오브젝트 팩토리가 아무리 많아도 이를 알아야하거나 직접 사용X
- 종합 IoC서비스를 제공한다.
- 빈을 검색하는 다양한 방법을 제공한다. (이름, 타입, 어노테이션)

책에서는 DaoFactory와 어플리케이션컨텍스트를 사용해서 UserDao를 호출 시 차이점을 보여주면서 싱글톤을 설명하고 있다.
DaoFactory를 직접 사용해서 UserDao를 여러번 호출 시 다른 오브젝트가 생성되지만, 애플리케이션 컨텍스트를 이용하면 
동일한 오브젝트가 생성되는 것을 볼 수 있는데(싱글톤 레지스트리),
이는 스프링이 주로 적용되는 대상이 자바 엔터프라이즈 기술을 사용하는 서버환경이기 때문이라고 설명하고 있다.
(서버 환경에서는 싱글토의 사용이 권장됨)

또한 자바의 기본 싱글톤 패턴 구현은 여러 단점이 있기 때문에 스프링은 직접 싱글톤 형태의 오브젝트를 관리하는 기능을 제공한다.

스프링 빈 스코프: 빈이 생성되고 존재하고, 적용되는 범위
 - 기본은 싱글톤(컨테이너 내 한개, 컨테이너가 존재하는 한 유지)
 - 그 외 프로토 타입, 요청, 세션 등 있음(10장에서 자세한 설명)

IoC의 대표적인 동작원리 - DI
DI(의존관계 주입)
- 자신이 사용할 오브젝트에 대한 선택과 생성 제어권을 외부로 넘겨 자신은 수동적으로 주입받은 오브젝트를 사용
- 어떤 오브젝트가 이용할 오브젝트를 프로퍼티에 설정
- 객체의 실체를 외부환경설정(xml, 어노테이션 등)에서 컨트롤 할 수 있도록 하는 것
DI(의존관계 주입)를 통해 모듈간 결합도를 낮춰서 유연한 변경이 가능해진다.

스프링은 DaoFactory와 같은 자바클래스 외에도 다양한 방법들을 통해 DI의존관계 설정 정보를 만들 수 있는데, 책에서는 대표적으로 XML을 이용한 설정을 소개하고 있다.
장점
- XML은 텍스트파일이기 때문에 다루기 쉽다.
- 쉽게 이해 할 수 있다.
- 컴파일과 같은 별도의 빌드 작업이 필요 없다.
- 스키마나 DTD를 이용해 정해진 포멧에 따라 작성되었는지 확인 가능하다.

@Configuration -> <beans>
@bean -> <bean>
스프링이란 '어떻게 오브젝트가 설계되고, 만들어지고, 어떻게 관계를 맺고 사용되는지에 관심을 갖는 프레임워크' 라는 사실을 기억하자.
스프링의 관심은 오브젝트와 그 관계다.






//////////////////////////////////////////////////////////////////////////////////////////////






도서관에서 책을 빌렸다.
차근차근 정리해보자!!


1. 오브젝트와 의존관계

1장에서는 스프링이 어떤 것이고, 무엇이을 제공하는지보다는 오브젝트의 설계과 구현, 동작원리에 더 집중해보도록 하자.
스프링을 이해하려면 오브젝트에 깊은 관심을 가져야한다.  이러한 오브젝트에 대한 관심은 오브젝트의 기술적인 특징과 사용 방법을 넘어서 오브젝트의 설계로 발전한다. 

**책에서는 간단하고 문제가 많은 DAO코드를 예시를 주고 이를 계속 개선, 수정하면서 그에 해당하는 개념을 설명하는 방식으로 설명하는 듯 싶음

1.1 초난감 DAO

DAO(Data Access Object)란?

DB를 사용해 데이터를 조회하거나 조작하는 기능을 전담하도록 만든 오브젝트

자바빈(JavaBean)이란?

자바빈은 원래 비주얼 툴에서 조작 가능한 컴포넌트를 말한다. 자바의 주력 개발 플랫폼이 웹 기반의 엔터프라이즈 방식으로 바뀌면서 비주얼 컴포넌트로서 자바빈은 인기를 잃어갔지만 자바빈의 몇 가지 코딩 관례는 JSP 빈, EJB와 같은 표준 기술과 자바빈 스타일의 오브젝트를 사용하는 오픈소스 기술을 통해 게속 이어져 왔다. 이제는 자바빈이라고 말하면 비주얼 컴포넌트라기 보다는 다음 두 가지 관례를 따라 만들어진 오브젝트를 가리킨다. 간단히 빈이라고 부르기도 한다.
-디폴트 생성자: 자바빈은 파라미터가 없는 디폴트 생성자를 갖고 있어야 한다. 툴이나 프레임워크에서 리플렉션을 이용해 오브젝트를 생성하기 때문에 필요하다.
-프로퍼티: 자바빈이 노출하는 이름을 가진 속성을 프로퍼티라고 한다. 프로퍼티는 set으로 시작하는 수정자 메소드(setter)와 get으로 시작하는 접근자 메소드(getter)를 이용해 수정 또는 조회할 수있다. 

1.2 DAO의 분리

프로그래밍의 기초 개념 중에 관심사의 분리(Separation of Concerns)이라는 게 있다. 이를 객체지향에 적용해보면, 관심이 같은 것끼리는 하나의 객체 안으로 또는 친한 객체로 모이게하고, 관심이 다른 것은 가능한 한 따로 떨어져서 서로 영향을 주지 않도록 분리하여는 것이라 생각할 수 있다. 

리펙토링이란?

기존의 코드를 외부의 동작방식에는 변화 없이 내부 구조를 변경해서 재구성하는 작업 또는 기술을 말한다. 리펙토링을 하면 코드 내부의 설계가 개선되어 코드를 이해하기가 더 편해지고, 변화에 효율적으로 대응할 수 있다. 결국 생산성은 오라가고, 코드의 품질은 높아지며, 유지보수하기 용이해지고, 견고하면서도 유연한 제품을 개발할 수 있다. 대표적으로 중복된 코드 제거가 있다.

템플릿 메소드 패턴이란?

상속을 통해 슈퍼클래스의 기능을 확장할 때 사용하는 가장 대표적인 방법이다. 변하지 않는 기능을 슈퍼클래스에 만들어두고 자주 변경되며 확장할 기능은 서브클래스에서 만들도록 한다. 슈퍼클래스에서는 미리 추상 메소드 또는 오버라이드 가능한 메소드를 정의해두고 이를 활용해 코드의 기본 알고리즘을 담고 있는 템플릿 메소드를 만든다. 슈퍼클래스에서 디폴드 키능을 정의해두거나 비워뒀다가 서브클래스에서 선택적으로 오버라이드할 수 있도록 만들어둔 메소드를 훅 메소드라고 한다. 서브클래스에서는 추상 메소드를 구현하고나, 훅 메소드를 우버라이드하는 방법을 이용해 기능의 일부를 확장한다. 


펙토리 메소드 패턴이란?

펙토리 메소드 패턴도 템플릿메소드 패턴과 마찬가지로 상속을 통해 기능을 확장하게 하는 패턴이다. 그래서 구조도 비슷하다. 슈퍼클래스 코드에서도 서브클래스에서 구현할 메소드를 호출해서 필요한 타입의 오브젝트를 가져와 사용한다. 이 메소드는 주로 인터페이스 타입으로 오브젝트를 리턴하므로 서브클래스에서 정호가히 어떤 클래스의 오브젝트를 만들어 리턴할지는 슈퍼크래스에서는 알지 못한다. 사실 관심도 없다. 서브 클래스는 다양한 방법으로 오브젝트를 생성할 수 있도록 미리 정의해둔 메소드를 펙토리 메소드라고 하고, 이 방식을 통해 오브젝트 생성 방법을 나머지 로직, 즉 슈퍼클래스의 기본 코드에서 독립시키는 방법을 펙토리 메소드 패턴이라고한다, 자바에서는 종종 오브젝트를 생성하는 기능을 가진 메소드를 일반적으로 펙토리 메소드라고 부르기도 한다, 이때 말하는 펙토리 메소드와 펙토리 메소드 패턴의 펙토리 메소드는 의미가 다르므로 혼동하지 않도록 주의해야 한다. 
//이 부분 다시 정리 할 것 

>>이 템플릿 메소드 패턴이나 팩토리 메소드 패턴으로 관심사사힝 다른 코드를 분리하고 서로 독립적으로 변경, 확장할 수 있도록 만드는 것은 효과적이지만 상속을 사용했다는 단점이 있다.
>>상속 자체는 간단해 보이고 사용하기도 편리하게 느껴지지만 사실 많은 한계점이 있다.

>>자바는 다중상속을 지원하지 않기 때문에 상속 후 다른 목적으로 상속을 적용하기 힘들기 때문??


1.3 DAO의 확장

독립적인 클래스를 만들어 클래스를 분리하여 확장할 수 있다. 하지만 이런식으로 사용하면 다른 환경에 맞게 구현해서 쓸 수 있는 자유로운 확장이 불가능 하다. 
그렇기 때문에 두 개의 클래스가 서로 긴밀하게 연결되어 있지 않도록 중간에 추상적인 연결고리를 만들어주는 방법으로 해결할 수 있다. >> 인터페이스  

개방 폐쇄의 원칙이란?

깔끔한 설게를 위한 적용 가능한 객체지향 설계 원칙 중 하나로, '클래스나 모듈은 확장에는 열려 있어야 하고 변경에는 닫혀 있어야 한다.' 라는 의미이다. 잘 설계된 객체 지향 클래스의 구조를 살펴보면 이 원칙을 잘 지키고 있다.(인터페이스를 사용해 확장 기능을 정의한 대부분의 API)
>> 개방 폐쇄 원칙은 높은 응집도와 낮은 결합도라는 원리로도 설명 가능함.
높은 응집도란, 변경이 일어날 때 모듈의 많은 부분이 함께 바뀐다는 것이다. 만약 모듈의 일부분에만 변경이 일어나도 된다면, 모듈 전체에서 어떤 부분이 바뀌어야 하는지 파악해야 하고, 또 그변경으로 인해 바뀌지 않은 부분에는 다른 영향을 미치지 않는지 확인해야 하는 이중의 부담이 생긴다. 

낮은 결합도란, 관계를 유지하는 데 꼭 필요한 최소한의 방법만 간접적인 형태로 제공하고, 나머지는 서로 독립적이고 알 필요도 없게 만들어주는 것이다. 결합도가 낮아지면 변화에 대응하는 속도가 높아지고, 구성이 깔끔해진다. 또한 확장하기 편해짐
>>결국 하나의 변경이 발생할 때 모듈과 객체로 변경에 대한 요구가 전파되지 않은 상태

객체지향 설계 원칙(SOLID)이란?

오랜 시간 동안 객체지향 설계에 관한 여러가지 원리와 원칙을 체계적으로 잘 정리한 것으로, 로버트 마틴이 정리하였다. SOLID는 
SRP(The Single Responsibility Principle): 단일 책임 원칙
OCP(The Open Closed Principle): 개방 폐쇄 원칙
LSP(The Liskov Substitution Principle): 리스코프 치환 원칙
ISP(The Interface Segregation Principle): 인터페이스 분리 원칙
DIP(The Dependency Inversion Principle): 의존관계 역전 원칙

전락패턴이란?

자신의 기능 맥락에서, 필요에 따라 변경이 필요한 알고리즘을 인터페이스를 통해 통째로 외부로 분리시키고, 이를 구현한 구체적인 알고리즘을 클래스를 필요에 따라 바꿔서 사용할 수 있게하는 디자인 패턴
>> 스프링은 지금까지 언급한 객체지향적 설계 원칙과 디자인 패턴에 나타난 장점을 자연스럽게 개발자들이 활용할 수 있게 해주는 프레임워크이다. 

1.4 제어와 역전(IoC, Inversion of Control)

IoC는 프로그램의 제어 흐름 구조가 뒤바뀌는 것이라고 설명할 수 있다.

//추가정리 필요


1.5 스프링의 IoC

빈(bean): 스프링이 제어권을 가지고 직접 만들고 관계를 부여하는 오브젝트

빈펙토리(bean factory): 빈의 생성과 관계 설정과 같은 제어를 담당하는 IoC 오브젝트 보통 빈 팩토리보다는 이를 좀 더 확장한 애플리케이션 컨텍스트를 주로 사용함
(빈 팩토리라고 할때는 빈을 생성하고 관게를 설정하는 IoC의 기본 기능에 초점을 맞춘 것이고, 에플레케이션 컨텍스트라고 말할 때는 애플리케이션 전반에 걸쳐 모든 구성요소의 제어 작업을 담당하는 IoC 엔진이라는 의미가 좀 더 부각된다 보면 된다.)

애플리케이션 컨텍스트: 빈의 생성, 관계설정 등의 제어 작업을 총괄(IoC컨테이너라고도 하고, 스프링컨테이너, 빈 팩토리라고도 부름?)>>스프링의 가장 대표적인 오브젝트


애플리케이션 컨텍스트를 사용했을 때 얻을 수 있는 장점

클라이언트는 구체적인 팩토리 클래스를 알 필요가 없다
>>오브젝트 텍토리가 아무리 많아져도 이를 알아야하거나 직접 사용할 필요 없고, 일관된 방식으로 원하는 오브젝트를 가져올 수 있다.

애플리케이션 컨텍스트는 종합 IoC 서비스를 제공해준다.
>>오브젝트가 만들어지는 방식, 시점과 전략을 다르게 가져갈 수도 있고, 부가적으로 자동생성, 오브젝트에 대한 후처리, 정보의 조합, 설장방식의 다변화 ,인터셉팅 등 오브젝트를 효과적으로 활용할 수 있는 다양한 기능을 제공한다. 또한 빈이 사용할 수 있는 기반기술 서비스나 외부 시스템과의 연동 등을 컨테이너 차원에서 제공해주기도 한다.

애플리케이션 컨텍스트는 빈을 검색하는 다양한 방법을 제공해준다.
>>getBean()메소드는 빈의 이름을 이용해 빈을 찾아준다. 타입믄으로 빈을 검색하거나 특별한 어노테이션 설정이 되어 있는 빈을 찾을 수도 있다.


스프링 IoC의 용어 정리

빈: 스프링이 IoC방식으로 관리하는 오브젝트. 주의할 점은 스프링을 사용하는 애플리케이션에서 만들어지는 모든 오브젝트가 다 빈은 아니라는 사실이다. 그중에서 스프링이 직접 생성과 제어를 담당하는 오브젝트만을 빈이라 부른다.

빈 팩토리: 스프링의 IoC를 담당하는 핵심 컨테이너. 빈을 등록하고, 생성하고, 조회하고 돌려주고, 그 외 부가적인 빈을 관리하는 기능을 담당. 보통 바로 사용하지 않고 이를 확장한 애플리케이션 컨텍스트를 이용함. BeanFactory라고 붙여쓰면 빈 팩토리가 구현하고 있는 가장 기본적인 인터페이스의 이름이 됨. getBean()과 같은 메소드가 정의되어 있다.

애플리케이션 컨텍스트: 빈 팩토리를 확장한 IoC컨테이너. 빈을 등록하고 관리하는 기본적인 기능은 빈 팩토리와 동일. 여기에 스프링이 제공하는 각종 부가서비스를 추가로 제공함

설정정보/설정 메타정보(configuration metadata): 애플리케이션 컨텍스트 또는 빈 팩토리가 IoC를 적용하기 위해 사용하는 메타 정보를 말함. 실제로 스프링의 설정 정보는 컨테이너에 어떤 기능을 세팅하거나 조정하는 경우에도 사용하지만, 그보다는 IoC컨테이너에 의해 관리되는 애플리케이션 오브젝트를 생성하고 구성할 때 사용됨. 애플리케이션 형상 정보라고 부르기도 함.

컨테이너 또는 IoC컨테이너: IoC방식으로 빈을 관리한다는 의미에서 애플리케이션 컨텍스트나 빈 팩토리를 컨테이너 또는 IoC컨테이너 라고도 함.

스프링 프레임워크: IoC컨테이너, 애플리케이션 컨텍스트를 포함해서 스프링이 제공하는 모든 기능을 통틀어 말할 떄 주로 사용함.


1.6 싱글톤 레지스트리와 오브젝트 스코프 

오브젝트의 동일성과 동등성

동일성 ==, 하나의 오브젝트만 존재하는 것이고 두 개의 오브젝트 레퍼런스 변수를 가짐

동등성 equals(), 두개의 각기 다른 오브젝트가 메모리상에 존재, 오브젝트 동등성 기준에 따라 두 오브젝트의 정보가 동등하다고 판단되는 것


싱글톤 패턴(Singleton Pattern)이란?

GoF가 소개한 디자인 패턴중 하나로 가장 자주 활용되는 패턴이기도 하지만 가장 많은 비판을 받는 패턴이기도 함.
어떤클래스를 애플리케이션 내에서 제한된 인스턴스 개수, 이름처럼 주로 하나만 존재하도록 강제하는 패턴. 이렇게 하나만 만들어지는 클래스의 오브젝트는 애플리케이션 내에이서 전역적으로 접근이 가능함. 단일 오브젝트만 존재해야하고, 이를 애플리케이션의 여러 곳에서 공유하는 경우에 주로 사용함.


자바에서 싱글톤을 구현하는 방법

-클래스 밖에서는 오브젝트를 생성하지 못하도록 생성자를 private으로 만든다.
-생성된 싱글톤 오브젝트를 저장할 수 있는 자신과 같은 타입의 스태틱필드를 정의한다.
-스태틱 펙토리 메소드인 getInstence()를 만들고 이 메소드가 최초로 호출되는 시점에서 한 번만 오브젝트가 만들어지게 한다
-한번 오브젝트(싱글톤)가 만들어지고 난 후에는 getInstence() 메소드를 통해 이미 만들어져 스태틱 필드에 저장해둔 오브젝트를 넘겨준다.


싱글톤 패턴 구현방식의 문제점

-private 생성자를 갖고 있기 떄문에 상속할 수 없음.
-싱글톤은 테스트하기가 힘들다
-서버환경에서는 싱글톤이 하나만 만들어지는 것을 보장하지 못한다.
(자바 언어를 이용한 싱글톤 패턴 기법은 서버환경에서는 싱글톤이 꼭 보장된다고 볼 수 없음)
-싱글톤의 사용은 전역 상태를 만들 수 있기 때문에 바람직하지 못하다.


싱글톤 레지스트리

자바의 기본적인 싱글톤 패턴의 구현 방시기은 여러가지 단점이 있기 때문에, 스프링은 직접 싱글톤 형태의 오브젝트를 만들어 관리하는 기능을 제공

-장점은 스태틱 메소드와 private 생성자를 사용해야하는 비정상적인 클래스가 아니라 평범한 자바 클래스를 싱글톤으로 활용하게 해준다는 점.

-싱글톤은 멀티스레드 환경이라면 여러 스레드가 동시에 접근해서 사용할 수 있기 때문에 조심해야 함. 상태정보를 내부에 갖고 있지 않는 무정부(stateless)방식으로 만들어져야 함.

-다중 사용자의 요청을 한꺼번에 처리하는 스레드들이 동시에 싱글톤 오브젝트의 인스턴스 변수를 수정하는 것은 매우 위험함.>> 저장할 공간이 하나뿐이니 서로 값을 덮어쓰고 자신이 저자앟지 않은 값을 읽어올 수 있기 때문
따라서 싱글톤은 기본적으로 인스턴스 필드의 값을 변경하고 유지하는 상태유지(stateful) 방식으로 만들지 않는다.


스프링 빈의 스코프

스코프: 스프링이 관리하고 오브젝트, 즉 빈이 생성된고, 존재하고 적용되는 범위
스코프의 종류
-싱글톤 스코프: 컨테이너 내에 한 개의 오브젝트만 만들어져서, 강제로 제거하지 않는 한 스프링 컨테이너가 존재하는 동안 계속 유지됨. 스프링에서 만들어지는 대부분의 빈은 싱글톤스코프임.

-프로토타입 스코프: 싱글톤과 달리 컨테이너에 빈을 요청할 때마다 매번 새로운 오브젝트를 만들어줌.

-요청(request) 스코프: 웹을 통해 새로운 HTTP 요청이 생길때마다 생성

-세션(session) 스코프: 웹의 세션과 유사


1.7 의존관계 주입(DI)

의존관계 주입, 의존성 주입, 의존 오브젝트 주입?

Dependency Injection는 오브젝트 레퍼런스를 외부로부터 제공(주입)받고 이를 통해 여타 오브젝트와 다이내믹하게 의존관계가 만들어지는 것이 핵심이다. 그렇기에 책에선 의존관계 주입이라 사용한다.
>>의존관계를 런타임시에 연결해주는 작업

의존 관계주입이란 다음 세가지 조건을 충족하는 작업

-클래스 모델이나 코드에는 런타임 시점의 의존관계가 드러나지 않는다. 그러기 위해서는 인터페이스에만 의존하고 있어야 한다.

-런타임 시점의 의존관계는 컨테이너나 팩토리 같은 제3의 존재가 결정한다.

-의존관계는 사용할 오브젝트에 대한 레퍼런스를 외부에서 제공(주입)해줌으로써 만들어진다.

의존관계 검색(dependency lookup)

의존관계를 맺는 방법이 외부로부터의 주입이 아니라 스스로 검색을 이용
getBean()메소드를 통해 객체를 검색하여 받아옴



1.8 XML을 이용한 설정

스프링은 자바클래스를 이용하는 것 외에도, 다양한 방법을 통해 DI의존관계 설정정보를 만들 수 있는데 대표적인 것이 XML이다. XML은 텍스트파일이기 때문에 다루기 쉽고, 컴파일과 같은 별도의 빌드작업이 없다는 것이 장점이다.


XML설정

스프링 애플리케이션 컨텍스트는 XML에 담긴 DI정보를 활용할 수 있다. DI정보가 담긴 XML파일은 <beans>를 루트 엘리먼트로 사용한다.
빈의 DI정보
-빈의 이름
-빈의 클래스: 빈 오브젝트를 어떤 클래스를 이용해서 만들지를 정의
-빈의 의존 오브젝트: 빈의 생성자나 수정자 메소드를 통해 의존 오브젝트를 넣어줌.

클래스 설정과 XML 설정의 대응항목
                         자바                        XML 설정 정보
빈 설정파일    @Configuration                 <beans>
빈의 이름       @Bean methodNames         <bean id="methodName"
빈의 클래스     return new BeanClass()       class-"a.b.c...BeanClass">

XML에서는 <property>태그를 사용해 의존 오브젝트와의 관계 정의한다.


DTD와 스키마

XML 문서는 미리 정해진 구조를 따라서 작성됐는지 검사할 수 있다. 구조를 정의하는 방법에는 DTD와 스키마(schema)가 있는데, 스프링 XML 설정파일은 두 가지 방식 모두 지원한다.
-DTD를 사용할 경우
<beans>엘리먼트 앞에 다음와 같은 선언을 넣어준다.
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">

-스키마는 DI를 위한 기본태그 <beans>, <bean> 외에도 특별한 목적을 위해 별도의 태그를 사용할 수 있는 방법을 제공한다. 특별한 이유가 없으면 스키마를 사용하는 것이 바람직함.
ex)내가 쓴 applicationcontext.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
    http://www.springframework.org/schema/jdbc  
    http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    <context:property-placeholder location="classpath*:application-properties.xml"/>
    
    <context:annotation-config />
    
    <!-- 데이터 부분 -->
     <bean id="dataSource"
        class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
            <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
            <property name="url" value="jdbc:mysql://localhost:3306/cot_pr1"></property>
            <property name="username" value="root"></property>
            <property name="password" value="123321"></property>
    </bean>    
    
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation" value="classpath:mybatis-config.xml" />
    </bean>
    
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="sqlSessionFactory"></constructor-arg>
    </bean>
   
    <bean id="UserDao" class="net.cot_pr1.dao.UserDao"
        p:sqlSession-ref="sqlSession"
        p:dataSource-ref="dataSource" />
            
    <bean id="webBoardDao" class="net.cot_pr1.dao.WebBoardDao"
        p:sqlSession-ref="sqlSession"
        p:dataSource-ref="dataSource" />
     
    <bean id="webReplyDao" class="net.cot_pr1.dao.WebReplyDao"
        p:sqlSession-ref="sqlSession"
        p:dataSource-ref="dataSource" />
        
    <bean id="galleryDao" class="net.cot_pr1.dao.GalleryDao"
        p:sqlSession-ref="sqlSession"
        p:dataSource-ref="dataSource" />
    <bean id="freeboardDao" class="net.cot_pr1.dao.FreeBoardDao"
        p:sqlSession-ref="sqlSession"
        p:dataSource-ref="dataSource" />
        
    <bean id="freereplyDao" class="net.cot_pr1.dao.FreeReplyDao"
        p:sqlSession-ref="sqlSession"
        p:dataSource-ref="dataSource" />
        
    <bean id="noticeDao" class="net.cot_pr1.dao.NoticeDao"
        p:sqlSession-ref="sqlSession"
        p:dataSource-ref="dataSource" />
        
    <bean id="noticereplyDao" class="net.cot_pr1.dao.NoticeReplyDao"
        p:sqlSession-ref="sqlSession"
        p:dataSource-ref="dataSource" />
    
    <bean id="qnaDao" class="net.cot_pr1.dao.QnADao"
        p:sqlSession-ref="sqlSession"
        p:dataSource-ref="dataSource" />
        
    <bean id="qnareplyDao" class="net.cot_pr1.dao.QnAReplyDao"
        p:sqlSession-ref="sqlSession"
        p:dataSource-ref="dataSource" />
    <bean id="adminDao" class="net.cot_pr1.dao.AdminDao"
        p:sqlSession-ref="sqlSession"
        p:dataSource-ref="dataSource" />
        
        
    <!-- 파일업로드를 위한 디렉토리 설정 -->
    <!-- String uploadPath = new String("업로드 경로") -->
    <bean id="uploadPath" class="java.lang.String">
        <!-- 파일업로드 디렉토리 -->
        <constructor-arg value="C:\Users\SK\git\Cot_pr1\Cot_Pr1\src\main\webapp\resources\uploads" />
    </bean>
    <bean id="uploadPath2" class="java.lang.String">
        <!-- 파일업로드 디렉토리 -->
        <constructor-arg value="C:\Users\SK\git\Cot_pr1\Cot_Pr1\src\main\webapp\resources\profile" />
    </bean>
    
     <!-- 메일보내기 -->
   <bean id="mailSender" class = "org.springframework.mail.javamail.JavaMailSenderImpl">
      <property name="host" value="smtp.gmail.com" />
      <property name="port" value="587" />
      <property name="username" value="--@gmail.com" />
      <property name="password" value="--" />
      <property name="javaMailProperties">
         <props>
               <prop key="mail.transport.protocol">smtp</prop>
               <prop key="mail.smtp.auth">true</prop>
               <prop key="mail.smtp.starttls.enable">true</prop>
               <prop key="mail.debug">true</prop>
         </props>
      </property>
   </bean>
</beans>
cs

1장을 끝내기 전에, 스프링이란 '어떻게 오브젝트가 설계되고, 만들어지고, 어떻게 관계를 맺고 사용되는지에 관심을 갖는 프레임워크' 라는 사실을 기억하자. 스프링의 관심은 오브젝트와 그 관계다. 



//////////////////////////////////
ㅜㅜㅜ어렵다 책 1회독으로 안될듯 장기간적으로 봐야하나..ㅠㅠ