어플리에키션 간 상호작용을 가능하게 해주는 인터페이스이다.
다른 어플리케이션에서 제공하는 기능을 사용,데이터 교환을 할 수 있으며
해당 기능을 사용할 때 내부 구현을 몰라도 사용할 수 있도록 도와준다.
재사용이 가능한 코드 모음이다.
라이브러리에서 제공하는 함수를 활용하면 개발자가 복잡한 알고리즘을 처음부터
구현할 필요가 없다.
프레임워크는 특정 목적을 위해 만들어진 틀 ,규칙이다.
어플리케이션 개발을 위한 템플릿의 역할을 하며 , 전체적인 구조와 패턴을 정의한다.
같은 구조와 패턴을 사용하여 모든 개발자들이 표준화된 방식으로 개발을 할 수 있게 도와주고
개발 시간을 단축시켜준다.
라이브러리는 개발자에게 주도권이 있고 프레임워크는 개발자에게 주도권이 없다
-자바 기반 웹 어플리케이션 개발에 사용하는 프레임워크
-개발의 복잡성을 줄이고 , 비교적 쉽게 테스트가 가능하여 생산성을 높인다.
-유지 관리에 용이하며 , 다른 프레임 워크와 연동이 매우 뛰어나다.(접착성)
2.DI(Dependency Injection) : 의존성 주입
스프링의 핵심 기능이며 , 클래스들 간 의존성을 낮춰주고 코드 재사용성을 높인다.
3.AOP (Aspect-Oriented Programming) : 관점 지향 프로그래밍
공통되고 반복되는 관심사 ( 기능 등 ) 을 분리하여 모듈화한다.
관심사를 분리하면 개발자는 핵심 로직에만 집중하여 코드를 작성할 수 있으며
유지보수에 유리하다.
분리한 기능을 관점 (Aspect)라고 한다.
3.AOP (Aspect-Oriented Programming) : 관점 지향 프로그래밍
공통되고 반복되는 관심사 ( 기능 등 ) 을 분리하여 모듈화한다.
관심사를 분리하면 개발자는 핵심 로직에만 집중하여 코드를 작성할 수 있으며
유지보수에 유리하다.
분리한 기능을 관점 (Aspect)라고 한다.
6.WAS에 종속적이지 않음
스프링 프레임워크를 사용한 프로젝트는 특정 WAS만 사용 가능한 것이 아니라 다양한 서버에서
동작할 수 있다
또한 WAS 없이도 독립적인 테스트가 가능하여 테스트가 쉽고 빠르다.
객체의 입장에서 사용할 다른 객체를 직접 생성하여 제어한다. 이러한 개발이 일반적인
제어 흐름이다.
제어권의 역전이란 이러한 흐름을 반대로 뒤집은 것으로 객체가 사용하는 다른 객체를 직접 생성하지도 않으며
자기 자신도 어디서 사용되는지 알 수 없다
특별한 권한을 가진 다른 객체에 의해 결정되고 만들어진다.
스프링에서 객체 생성, 관리 ,의존성 주입을 담당하는 주요 컴포넌트
IoC 컨테이너는 논리적인 구조이다.
즉, 실체가 아니며 IoC컨테이너라는 논리적 구조를 바탕으로 스프링에서 사용하는 실제 구현
객체는 BeanFactory 와 ApplicationContext 객체이다.
BeanFactory 는 가장 기본적인 IoC컨테이너 기능을 제공하며 ,
ApplicaitonContext는 좀 더 업그레이드 되어 추가기능을 제공한다.
프로젝트 경로
1.src/main/java : 서버에서 사용하는 java파일
2.src/test/java : 단위 테스트 java파일
3.src/main/resource : 설정파일 , 뷰
4.resource/static : css , js파일
5.resource/templates : html 파일
6.pom.xml 또는 build.gradle : 라이브러리 의존성 관리
7.application.properies : 서버 ,DB, 라이브러리 설정파일
profile
주입의 종류
1.필드 주입
권장하지 않는다. 단, 테스트에서는 사용한다.
-장점
편하다.
-단점
1. 생성자나 setter를 사용해서 주입을 받는것이 아니기 때문에 스프링의 도움없이는 주입이
불가능하여 테스트에서 사용하기 불편하다.
2.final 키워드 사용이 불가능하여 불변성을 보장받지 못한다.
3.순환 참조시 예외가 발생하지 않는다.
2.생성자 주입
가장 권장하는 방법
-생성자에 @Autowired 를 사용하면 된다.
-Spring 4.x.x 이상은 생성자가 한 개만 있으면 자동으로 @Autowired가 붙는다.
-SpringBoot 2.7.11 Spring 5.xx버전을 기반으로 만들어졌으므로 생략이 가능하다.
만약 private 필드를 초기화 할 때 setter가없고 반드시 생상자를 통해서 필드를
초기화 할 수 밖에 없다면 객체의 불변성이 보장된다.
3.수정자 주입 (setter 주입)
-setter를 사용하여 주입하는 방법 setter에 @Autowired를 사용하면 된다
-setter를 이용하여 언제든 수정이 가능하게 되므로 불변성이 보장되지 않는다
-특정 필드의 setter를 사용하지 않아도 해당 클래스의 객체를 만들 수 있어서
NPE(Null Point Exception)이 발생할 수 있다.
-장점
주입을 상황에 따라 유연하게 하기 위해 사용할 수는 있으나 일반적으로 그런 상황은
거의 없다. 그러므로 권장하지 않는다.
순환참조
순환참조란 A,B클래스가 서로 참조를 할 경우 발생하는 문제이다.
(서로 주입을 하는 경우)
서로가 주입하면써 무한 반복으로 주입을 시도하게된다.
스프링 MVC
-스프링 MVC 에서는 Didspatcher servlet이 Front Controller의 역할을 한다.
-Controller 의 메소드를 Handler라고도 부른다.
1.Dispatcher Servelt이 요청을 받으면 Handler Mapping을 통해서 URL에 매핑된 컨트롤러를 찾는다.
2.디스패쳐 서블릿이 핸들러 어댑터를 실행시킨다 .
3.핸들러 어댑터가 올바른 핸들러를 실행시키고 핸들러는 결과를 반환한다 .
-Model : 컨트롤러에서 처리한 데이터를 저장(DB에서 가져온 정보 등)
-View : 클라이언트에게 보여줄 페이지의 이름을 저장
5.디스패쳐 서블릿이 받은 결과 중 어떤 view가 필요한지를 View resolver에 전달한다.
6.View resolver은 올바른 View를 찾아 디스패쳐 서블릿에게 경로를 알려준다.
7. View 는 디스패쳐 서블릿에게 받은 모델 데이터로 html을 완성시켜 클라이언트에게 응답을 보낸다.
특징
-HttpServletRequest,HttpServletResponse 를 거의 사용할 필요 없이 구현 가능하다.
-다양한 타입의 파라미터 , 다양한 타입의 리턴 사용이 가능하다.
-Get ,Post 등의 전송방식에 대한 처리를 어노테이션으로 처리가 가능하다 .
스프링과 JSP의 데이터 흐름 (DB기준)
-JSP
DB->mapper.xml - > DAO ->Controller
-Spring
DB-mapper.xml->Mapper 인터페이스 ->Service ->Controller
3-tier 구조 (3-layer)
Console 쿼리짜고 - >memberDto ->MemberMapper.xml - > MemberMapper. 인터페이스 ->
스프링 프로젝트는 3-layer 방식으로 구성한다.
어플리케이션을 3개의 계층으로 분리한 디자인 패턴이며 각 계층간 책임을 명확히 구분한다.
1.Presentation layer : 화면 계층
클라이언트 화면에 보여주기 위한 기술을 사용하는 영역 , 클라이언트가 직접 상호작용하는 부분을 모두 포함한다.
HTML엔진 , HTML , CSS ,JS등이 사용되며 주요 역할은 클라이언트의 입력을 받아 비즈니스 층에 전달하며,
처리 결과를 클라이언트에게 전달한다.
-디스패쳐 서블릿 , 뷰 등이 포함
-컨트롤러
2.Business layer : 비즈니스 계층
어플리케이션의 핵심 기능 , 비즈니스 로직이 구현되는 계층이다.
클라이언트의 요청을 처리하고 데이터 처리 , 검증 등의 작업을 수행한다.
필요한 데이터는 영속 계층에 요청하며 일반적으로 이 계층은 서버 사이드 언어로 구현된다.
화면 계층과 영속 계층 사이에서 중간다리 역할을 한다.
-서비스 클래스
3.Persistence layer :영속계층
영속 계층은 데이터 엑세스 계층이라고도 불린다.
DB에 연결 , 쿼리 실행 , 저장된 데이터의 CRUD 작업 처리 등을 수행한다 .
-mapper
동적쿼리
MyBatis 프레임워크에서 지원하는 강력한 기능이다.
쿼리를 상황에 따라 동적으로 생성해주어 하나의 쿼리를 여러 상황에서 사용할 수 있게 해준다.
<choose> ~ <when> ~ <otherwise>
<choose>
<when test="조건"></when>
<when test="조건"></when>
........
<otherwise></otherwise>
</choose>
<where>
태그 내부에 조건절을 생성해주는 태그이다.
주로 where 태그 내부에 if 태그 처럼 동적으로 쿼리를 삽입하는 태그를 사용한다
<where>
<if test="조건"><if>
<if test="조건"><if>
<if test="조건"><if>
</where>
내부의 if문에서 하나라도 true가 나오면 where절을 추가해주고
if문에서 모두 false가 나오면 where절을 생략한다.
<trim>
동적쿼리를 생성할 때 접두어 (prefix) , 접미어(suffix) 를 붙여주고 지워주는 기능을 가진 태그이다.
<if>의 부족한점을 보완해주는 역할을 한다.
<trim 속성 1 속성 2 ....>
<if test="조건"><if>
<if test="조건"><if>
...
</trim>
-속성의 종류
1.prefix : trim 태그 내부의 쿼리 앞에 붙는 명령어를 지정한다
2.suffix : trim 태그 내부의 쿼리 마지막에 붙는 명령어를 지정한다.
3.prefixOverrides : trim 태그 내부의 쿼리 앞에 명령어 중 지우고 싶은 것을 지정한다.
4.suffixOverrides : trim 태그 내부의 쿼리 마지막에 명령어 중 지우고 싶은 것을 지정한다.
옵셔널 클래스는 NPE를 방어하기 위해 사용한다.
개발을 할 때 가장 많이 발생하는 예외 중 하나가 NPE이다. 참조변수에 들어있는 값이 null인경우 접근 연산자(.)를 이용하여 메소드나 필드에 접근하면 NPE가 발생하므로 프로그램이 강종될 수 있다.
그러므로 if문을 이용하여 해당 값이 null인지 검사를 해야하는데 null이 나올 수 있는 경우의 수가 너무 많다보니 if문을 너무 많이 사용하여 개발을 피곤하게 만든다.
Optional타입은 null 체크를 보다 간결하고 안전하게 코드를 작성하도록 도와준다.
empty()
Optional opt = Optional.empty();
비어있는 옵셔널 객체를 생성한다.
of()
Optional opt = Optional.of(값);
값을 저장하고 있는 옵셔널 객체를 생성한다. 값이 확실하게 null이 아닌경우에만 사용한다.
만약 null을 저장하면 NPE가 발생한다.
ofNullable()
Optional opt = Optional.ofNullable(값);
값을 저장하고 있는 옵셔널 객체를 생성한다. 값이 null일 수도 있는 경우 사용한다.
옵셔널 객체는 값을 저장할 수 있으며 저장한 값이 null인지 체크하거나, null이면 다른 값으로 대체해서 반환하는 등의 메소드를 지원한다.
get()
opt.get()
opt객체에 저장된 값을 반환한다. null인 경우 예외가 발생된다. (NoSuchElementException)
Optional opt = Optional.of("test");
String result = opt.get();
orElse()
opt.orElse(대체 값)
opt객체에 저장된 값을 반환한다. 만약 null인 경우 [대체 값]이 반환된다.
Optional opt = Optional.of("test");
String resultj = opt.orElse("a");
System.out.println(isABC(null));
public boolean isABC(String str){
// return str.equals("ABC"); //str이 null인 경우 오류 발생함
return Optional.ofNullable(str).orElse("null이네").equals("ABC");
}
orElseGet()
opt.orElseGet(람다식) → opt.orElseGet(MyClass::new)
opt객체에 저장된 값을 반환한다. 만약 null인 경우 [람다식의 결과]가 반환된다.
class Student{
String name;
//getter
}
Student std = null;
String name = Optional.ofNullable(std).orElseGet(Student::new).getName();
orElseThrow()
opt.orElseThrow(특정 예외) → opt.orElseThrow(NullPointerException::new)
opt객체에 저장된 값을 반환한다. 만약 null인 경우 [특정 예외]가 발생된다.
Optional.ofNullable(null).orElseThrow(NullPointerException::new);
isPresent()
opt.isPresent()
opt객체에 저장된 값이 null이면 false, null이 아니면 true를 반환한다.(조건식으로 사용)
opt.ifPresent(람다식)
opt객체에 저장된 값이 null이 아닌 경우에만 람다식을 실행한다.
이 외에도 Stream<T>에서 사용하는 map() , filter() 등을 사용할 수 있다.
Unit Test(단위 테스트)
소스 코드 중 특정 모듈이 개발자가 의도한대로 작동하는지 검증하는 절차이다.
함수나 메소드의 테스트 케이스를 만드는 절차이며, 코드 변경으로 인한 문제가 발생한 경우 빠른 시간 내에 이를 파악하고 수정할 수 있다.
가장 이상적인 테스트 방법은 각 테스트 별로 서로 간섭하면 안되고, 항상 같은 결과를 기대할 수 있어야 한다.
JUnit과 assert(검증)
JUnit
자바 어플리케이션의 단위 테스트를 쉽게 해주는 프레임워크이다.
assert메소드와 @Test, @Before, @After 등의 어노테이션을 지원한다.
Assert 메소드
검증을 하기위한 메소드이다.
그러나 사용 방법이나 가독성이 떨어져서 잘 사용하지 않는다.
AssertJ 라이브러리 (오픈 소스)
AssertJ는 assertThat()으로 시작한다.
assertThat(타겟).검증메소드().검증메소드()......
검증 메소드는 이름만 봐도 기능을 알 정도로 직관적이기 때문에 사용 방법이 매우 간편하다.
assertThatThrownBy(예외가 발생할것 같은 코드를 람다식으로 작성)
예외를 검증하는 메소드
isInstanceOf(예외객체의 클래스.class)
hasMessageContaining("메세지")
========================================
Mockito란?
mock을 만들고 mock의 행동을 정의하는 stubbing과 작동하는지에 대한 검증을 할 수 있는 verify등 다양한 기능을 제공해주는 프레임워크
JUnit에서 Mockito 사용하기
JUnit과 Mockito는 둘 다 프레임워크이기 때문에 서로 결합하여 사용하기 위해서는 추가 설정이 필요하다.
JUnit5에서는 @ExtendWith(MockitoExtension.class)를 사용해야 기능이 확장된다.
Mock객체란?
어떤 객체를 모방하는 가짜 객체이다. 껍데기만 있으며 내부 구현부는 존재하지 않는다.
Mock객체를 만드는 것을 Mocking이라고 한다.
Mockito에서 지원하는 어노테이션
@Mock : Mock객체를 만들어준다.(Mocking)
@InjectMocks : Mock객체를 주입해준다.
예시)
관계 : UserService는 UserMapper를 주입받는다.
사용 : UserService를 테스트하기 위해서는 UserMapper가 주입되어야
하는데 UserMapper는 개발자가 테스트하고 싶은 대상이 아니다.
그러므로 UserMapper를 Mock객체로 만들어 UserService에 주입하여 테스트를 진행한다.
스터빙(stubbing)이란?
Mock객체의 메소드를 실행했을 때 행위를 미리 정의하는 것
스텁(stub)이란?
스터빙으로 새롭게 정의된 메소드
when(userMapper.select()).thenReturn(userDto);
//위의 코드는 stubbing을 하는것
// userMapper.select()는 stub이다.
Mockito의 스터빙 방법
모키토의 스터빙 방법은 2가지가 있다.
when(mock객체.스터빙할 메소드()).OngoingStubbing()
특이사항 : when()의 매개변수로 반환타입이 void인 메소드를 사용할 수 없다.
OngoingStubbing 메소드
thenReturn() : 스텁이 반환할 객체를 정의
thenThrown() : 스텁이 throw할 예외를 정의
thenCallRealMethod() : 스텁이 아닌 원본 객체의 메소드를 호출
stubber().when(mock객체).스터빙할 메소드()
특이사항 : 반환타입이 void인 메소드를 스터빙하려면 doNothing()을 사용한다.
stubber메소드 종류
1. doReturn() : 스텁이 반환할 객체를 정의
2. doThrow() : 스텁이 throw할 예외를 정의
3. doNothing() : 스텁이 아무런 행위도 안하도록 정의(void 메소드도 사용 가능)
Verify(검증)
스텁 메소드를 검증하는 메소드이며 다음과 같이 사용한다.
verify(T mock객체, VerificationMode mode)
VerificationMode는 검증할 값을 정의하는 메소드이다.
주로 times(n)가 많이 사용된다.
VerificationMode의 종류
1. times(n) : n번 호출됐는지 검증 ***
2. never : 한 번도 호출하지 않았는지 검증
3. atLeastOne : 최소 한 번 호출됐는지 검증
4. atLeast(n) : 최소 n번 호출됏는지 검증