헷갈리는 개념정리
- final
final을 클래스에 붙이는 이유 : 재정의를 방지하기 위해서
intellij 단축키
- alt+inset : getter and setter 자동 생성 단축키
- ctrl + shift + enter : 웬만한 단축키
- alt + enter : 오버라이딩
- ctrl + alt + v : 자동 객체 이름 생성
- ctrl + shift + t : 메서드 테스트 생성
- alt + entet : 스태틱함수로 코드 줄이기
- ctrl + e : 페이지 기록
- ctrl + n : 클래스 검색
- shift + f6 : 이름 변경
- ctrl + alt : implement 조회
- 출력화면 color 적용 (application.properties)
spring.output.ansi.enabled=always
- ctrl + alt + m : 자동 함수 생성
- ctrl + shift + f : 찾는 값 전체 검색
- ctrl + shift + r : 파일안에 있는 값 replace
- ctrl + p : 함수 매개변수 확인
SpringBoot 와 SpringFramework
스프링 프레임워크
- 순수 자바 객체(POJO)만을 사용하여 복잡성을 제거하고, 단순하고 가벼운 코드로 기업용 애플리케이션을 개발하기 위한 목적으로 개발된 프레임워크
- 스프링 di 컨테이너, 웹 기술(mvc), 테스트, 같은 기술들을 지원해주는 서비스
*POJO: 특정한 규약이나 프레임워크에 종속되지 않는 간단하고 순수한 자바 객체를 의미하며 유연하고 확장 가능한 코드를 작성할 수 있게 도와준다.
스프링 부트
- 간단한 설정과 구성을 통해 개발자들이 빠르게 애플리케이션을 개발할 수 있도록 지원하는 스프링 프레임워크
- 스프링을 편리하게 사용할 수 있도록 도와주는 도구 ex) 웹 서버 내장, 라이브러리 자동 구성 등..
Spring이란
핵심개념
- 자바 언어 기반의 프레임워크
- 스프링은 객체 지향 언어가 가진 강력한 특징을 살려내는 프레임워크
- 좋은 객체 지향 애플리케이션을 개발할 수 있게 도와주는 프레임워크
최대장점 : 다형성 ! (구조 변경이 용이)
- 역할과 구현으로 나누면 단순/유연/변경이 편해지며 클라이언트는 영향을 받지 않음, 내부 구조를 몰라도 됨
- 역할 = 인터페이스 , 구현 = 인터페이스를 구현한 클래스로 객체를 설계할 때는 역할과 구현을 명확히 분리해야 됨
* 스프링을 사용하면 레고 블럭을 조립하듯이 구현을 편리하게 변경할 수 있다.! ex) 제어의 역전 ioc, 의존관계 주입 di
의존성주입
의존성 주입 : 애플리케이션 실행 시점에 외부에서 실제 구현 객체를 생성하고 클라이언트에 전달해서 클라이언트와 서버의 실제 의존관계가 연결되는 것
*의존관계 주입을 사용하면 정적인 클래스 의존관계를 변경하지 않고(클라이언트 코드를 변경하지않고), 동적인 객체 인스
턴스 의존관계를 쉽게 변경할 수 있다.
AppConfig와 같이 객체를 생성하고 관리하면서 의존관계를 연결해주는 것을 ioc 컨테이너, di 컨테이너라고 함
- Spring Annotation
@Configuration | 설정 파일을 생성 |
@Bean | 스프링 컨테이너에 스프링 빈 등록 |
- ApplicationContext : 스프링 컨테이너
- AnnotationConfigApplicationContext : @Bean이 붙은 메서드를 모두 호출하여 저장소에 등록
ApplicationContext applicationContext= new AnnotationConfigApplicationContext(설정Config.class);
- getBean() : 스프링 컨테이너에서 스프링 빈 객체를 찾음
서비스객체 변수 = applicationContext.getBean("서비스이름",서비스객체.class);
스프링 컨테이너 생성 과정
- 스프링 컨테이너 생성
- new AnnotaionConfiApplictionContext(AppConfig.class)
- AppConfig.class에서 구성 정보 지정
- 넘어온 정보들을 통해 스프링 빈 등록
- 스프링 의존 관계 설정
Bean 조회 특징
- ac.getBean(타입) - 기본 조회
- ac.getBeanDefinitionNames() - 등록된 모든 빈 조회
- 타입으로 조회시 같은 타입의 빈이 존재할 시 오류 발생
- ac.getBean(빈이름, 타입) - 빈 이름을 지정하면 오류 해결
싱글톤 컨테이너
스프링이 없는 순수 DI 컨테이너는 요청할 때마다 객체를 새로 생성하여 메모리 낭비가 심하다
이를 해결하기위해 싱글톤 패턴을 사용한다.
싱글톤 패턴
클래스의 인스턴스 하나를 생성하여 이를 공유하도록 설계하는 디자인 패턴
- 주의점
- 객체 인스턴스를 2개 이상 생성하지 못하도록 막아야한다.
- private 생성자를 통해 외부에서 임의로 new 키워드를 사용하지 못하도록 해야 함
- 문제점
- 싱글톤 패턴 코드가 추가로 들어가야 함
- 클라이언트가 구체 클래스의 의존하여 DIP, OCP 원칙 위반
- 테스트가 어렵고 유연성이 떨어짐
스프링 컨테이너
싱글톤의 문제점을 해결하고 객체 인스턴스를 싱글톤으로 관리하는 방법, 스프링 빈이 바로 싱글톤으로 관리되는 빈이다.
- 특징
- 스프링 컨테이너는 싱글턴 패턴을 적용하지 않아도 객체 인스턴스를 싱글톤으로 관리한다.
- 주의점 : 싱글톤 객체는 상태를 유지하게 설계하면 안된다. 무상태로 설계해야만 한다.!!
- 특정 클라이언트에 의존적인 필드가 있으면 안된다.
- 특정 클라이언트가 값을 변경할 수 있는 필드가 있으면 안된다.
- 값을 공유할 수 없는 지역변수, 파라미터 등을 사용해야 한다.
@Configuration
- 특징
- 스프링 빈이 싱글톤이 되도록 보장해줘야 하기 때문에 반드시 AppConfig와 같이 파일을 설정할 클래스에 @Configuration을 붙여줘야한다.
- 여러번 메서드를 호출해도 같은 인스턴스를 공유하는 이유는 @Configuration을 통해 CGLIB라는 라이브러리를 사용했기 때문이다.
- 즉 @Bean이 붙은 메서드마다 이미 스프링 빈이 존재하면 존재하는 빈을 반환하고, 없으면 생성하여 스프링 빈으로 등록하는 코드가 동적으로 만들어진다. !
-> 스프링 설정은 항상 @Configuration을 사용하자
컴포넌트 스캔
여태까지 스프링 빈을 등록할 때 @bean을 통해 등록하였지만 스프링에서는 설정 정보없이 자동으로 스프링 빈을 등록해주는 컴포넌트 스캔이라는 기능을 제공해준다.
- Spring Annotation
@Configuration | 설정 파일을 생성 |
@ComponentScans | @Component가 붙은 클래스를 스캔하여 스프링 빈으로 등록 |
@Component | 작성한 클래스를 스프링 빈으로 등록 |
@Autowired | 의존 관계 자동 주입 |
- 특징
- 컴포넌트 스캔을 사용하려면 @ComponentScans를 설정 정보에 붙여야한다.
- 의존 관계를 주입하기 위해서는 생성자에 @Autowired를 붙이면 자동으로 스프링 빈을 찾아 주입한다.
- @Controller,@Service 등 또한 스캔 대상에 포함된다.
의존관계 자동 주입
의존관계 주입 방법
- 생성자 주입
- 불변, 필수 의존관계에 사용
- @Autowired를 이용하여 한번만 생성자가 호출되는 것을 보장
- 수정자 주입(setter 주입)
- 선택, 변경 가능성이 있는 의존관계에 사용
- @Autowired와 set 필드를 사용하여 의존관계를 주입
- 필드 주입
- 필드 위에 @Autowired를 붙여 의존관계 주입
- DI 프레임워크가 없으면 사용 불가, 스프링 설정을 목적으로 하는 @Configuraion 같은 특수 경우에만 사용을 권장
옵션 처리 (주입할 스프링 빈 없이도 동작할 때 처리 하는 방법)
- @Autowired(required=false) : 자동 주입 대상이 없으면 메서드 호출 X
- @Nullable : 주입 대상 앞에 선언하며 자동 주입 대상이 없으면 NULL 입력
- Optional<대상> : 자동 주입 대상이 없으면 Optional.empty 입력
생성자 주입의 권장 이유
- 불변 : 의존관계 주입은 종료 시점까지 의존관계를 변경할 일이 없으며, 혹시나 변경한다면 오류가 생길 가능성을 열어두는 것이다.
- 누락 : 주입 데이터를 누락했을 때 어떤 값을 필수로 넣어야 하는지를 오류를 통해 확인할 수 있다.
- final 키워드 : 생성자 주입을 사용하면 필드에 final 키워드를 사용할 수 있다. final을 통해 누락된 부분을 컴파일 시점에 확인할 수 있다.
롬북
롬북 라이브러리를 사용하면 간편하게 코드를 생략할 수 있다.
- Spring Annotation
@RequiredArgsConstructor | final이 붙은 필드를 모아 생성자 자동 생성 |
@Getter | getter 자동 생성 |
@Setter | setter 자동 생성 |
빈 중복 시 해결 방법
- @Autowired 필드 명 매칭 : 빈 중복 시 필드 명으로 빈 이름을 추가 매칭한다.
- @Qualifier 사용 : 추가 구분자를 붙여주는 방법으로 빈 등록시와 주입시 @Qualifier를 붙여 서로를 매칭시켜 빈 중복문제를 해결한다.
- @Primary : 우선권을 정하는 방법, @Autowired 시 여러 빈 매칭시 @Primary가 붙은 빈이 우선권을 갖게 된다.
모든 빈 조회
List와 Map을 통해 원하는 타입의 빈을 모두 가져온 이후 get() 메서드를 통해 원하는 빈을 꺼내면 된다.
public int discount(Member member, int price, String discountCode) {
DiscountPolicy discountPolicy = policyMap.get(discountCode); //원하는 타입 discountCode를 통해 호출
return discountPolicy.discount(member, price);}
최종 정리
편리한 자동 기능(@ComponentScan)을 기본으로 사용하되 명확하게 로직을 들어내야 될 때와 다형성을 사용해야할 때는 수동 등록(@Bean)을 하자!
빈 생명주기 콜백
스프링 빈은 객체를 생성하고, 의존관계 주입이 끝난 이후 데이터를 사용할 준비가 완료된다. 따라서 초기화 작업은 의존관계 주입이 끝난 이후 호출해야 된다.
스프링은 의존관계 주입이 완료되면 스프링 빈에게 콜백 메서드를 통해 초기화 시점을 알려주는 기능을 제공한다. (초기화 콜백) 또한 스프링 컨테이너 종료가 되기 직전에 소멸 콜백을 제공해준다.(소멸전 콜백 close())
스프링 빈의 이벤트 라이프사이클
스프링 컨테이너 생성 -> 스프링 빈 생성 -> 의존관계 주입 -> 초기화 콜백 -> 사용 -> 소멸전 콜백 -> 스프링 종료
* 생성자 안에서 초기화 작업을 함께 하는 것보다는 객체를 생성하는 부분과 초기화하는 부분을 명확하게 나누는 것이 유지보수 관점에서 좋다.
빈 생명주기 콜백 방법
- 설정 정보 @Bean에 초기화 메서드,종료 메서드 지정
- @Bean(initMethod = "초기화 메서드", DestroyMethod="종료 메서드") 지정
- 외부 라이브러리에도 적용할 수 있다.
- @PostConstruct, @PreDestroy 애노테이션 지원
- 생성자 메서드에 @PostConstruct을 , 종료 메서드에 @PreDestroy 애노테이션을 붙인다.
- 스프링에서 가장 권장하는 기법
빈 스코프
빈 스코프는 빈이 존재할 수 있는 범위를 뜻한다.
빈 스코프의 종류
- 싱글톤 : 기본 스코프로 스프링 컨테이너의 시작과 종료까지 유지되는 범위
- 빈 조회시 스프링 컨테이너는 항상 같은 인스턴스의 스프링 빈을 반환한다.
- 스프링 컨테이너 생성 시점에 초기화 메서드가 실행된다.
- 프로토타입 : 스프링 컨테니어는 프로토타입 빈의 생성과 의존관계 주입까지만 관여하고 더는 관리하지 않는 범위
- 빈 조회시 스프링 컨테이너는 항상 새로운 인스턴스를 생성하여 반환한다.
- 빈 조회시 스코프의 빈이 생성되고, 초기화 메서드가 실행된다.
- 웹 관련 스코프(requset) : 웹 요청이 들어오고 나올때 까지의 유지되는 범위
프로토타입 스코프
스프링 컨테이너는 프로토타입 빈을 생성하고 의존관계 주입, 초기화까지만 관여한다.
프로토타입 빈을 관리할 책임은 프로토타입 빈을 받은 클라이언트에게 주어진다. 그래서 @PreDestroy 같은 종료 메서드가 호출되지 않는다.
요청 시 각각 새로운 인스턴스를 생성하여 반환
- 싱글톤 빈과 함께 사용시 문제점
프로토타입 빈 생성 -> 싱글톤 빈에 반환 -> 호출 -> 항상 같은 싱글톤 빈 반환
와 같이 싱글톤 빈이 내부에 가지고 있는 프로토타입 빈은 이미 주입이 끝난 빈이다.
즉 스프링 컨테이너에 요청해서 프로토타입 빈을 새로 생성한 것이지, 사용할 때마다 새로 생성되는 것이 아니다.
- 싱글톤 빈과 함께 사용시 해결 방법
가장 간단한 방법은 싱글톤 빈이 프로토타입을 사용할 때마다 스프링 컨테이너에 새로 요청하는 것이다.
이처럼 의존관계를 외부에서 주입받는 것(DI)이 아니라 직접 필요한 의존관계를 찾는 것을 의존관계 조회 (DL)이라고 한다.
방법 1: ObjectProvider
ObjectProvider은 지정한 빈을 컨테이너에서 대신 찾아주는 DL 서비스를 제공해준다.
@Autowired
private ObjectProvider<PrototypeBean> prototypeBeanProvider;
public int logic() {
PrototypeBean prototypeBean = prototypeBeanProvider.getObject();
prototypeBean.addCount();
return prototypeBean.getCount();
}
getObject() 함수를 호출하면 내부에서는 스프링 컨테이너를 통해 해당 빈을 찾아서 반환한다.
방법 2: JSR-330 Provider
JSR-330 자바 표준을 사용하는 방법, javax.inject:javax.inject:1 gradle 추가
@Autowired
private Provider<PrototypeBean> provider;
public int logic() {
PrototypeBean prototypeBean = provider.get();
prototypeBean.addCount();
return prototypeBean.getCount();
}
get() 함수를 호출하면 내부에서는 스프링 컨테이너를 통해 해당 빈을 찾아서 반환한다.
이처럼 ObjectProvider, JSR-330 Provider를 사용하면 새로운 프로토타입 빈을 생성하여 프로토타입 범위를 지킬 수 있다.
웹 스코프
웹 환경에서만 동작되며 스프링이 해당 스코프의 종료시점까지 관리한다.
request 스코프 : HTTP 요청 하나가 들어오고 나갈 때까지 유지되는 스코프로 각각의 HTTP 요청마다 별도의 빈 인스턴스가 생성되고 관리된다.
동시에 여러 HTTP 요청이 오면 여러 요청이 남긴 로그인지 구분하기 어렵다. 이럴 때 requset 스코프를 사용하면 좋다.
@Scope(value="requset") 애노테이션을 붙여 사용한다.
출처 : 인프런 - 스프링 핵심 원리 feat.김영한 쌤
'웹 개발' 카테고리의 다른 글
스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 (2) | 2024.02.27 |
---|---|
스프링 DB 1편 - 데이터 접근 핵심 원리 (0) | 2024.02.24 |
스프링 MVC 2편 - 타임리프 (0) | 2024.02.23 |
스프링 MVC 1편 (0) | 2024.01.23 |
HTTP 웹 기본 지식 (1) | 2024.01.05 |