[Spring] 핵심, Http 복습 下

bin1225·2022년 8월 15일
0

Spring

목록 보기
13/15
post-thumbnail

22.08.01


BeanFactory나 ApplicationContext를 스프링 컨테이너라 한다.
ApplicationContext는 BeanFactory 외에도 여러가지 편리한 기능을 상속받은 컨테이너이다. 그리고 이 컨테이너 설정 정보는 다양한 형식으로 설정할 수 있다. ex) 자바 코드, XML, Groovy 등

<bean id="orderService" class="hello.respringstart.order.OrderServiceImpl">
        <constructor-arg name="discountPolicy" ref="discountPolicy"></constructor-arg>
        <constructor-arg name="memberRepository" ref="memberRepository"></constructor-arg>
    </bean>

xml로 설정하면 이렇게 bean 이름과 return 하는 클래스를 지정해주고
constructor를 통해 생성자에 들어가는 객체를 지정해준다.

  • 싱글톤 패턴

인스턴스가 딱 1개만 생성되도록 디자인하는 패턴이다.
자바코드 private를 이용해 수작업으로 만들 수 있지만, 이렇게 했을 때는 private로 인한 변경, 상속 제한/ DIP, OCP 위반이 발생한다.

이 단점을 보완하고 장점을 가져가기 위해 spring container를 사용한다.
@Configuration 어노테이션이 붙은 클래스에 @Bean 을 이용해 등록한다.
주의할 점은 싱글톤은 말 그대로 하나의 인스턴스가 반복해서 사용되기 때문에 무상태를 유지해야한다. 상태를 유지하는 필드가 값이 변경된다면, 위험한 문제가 될 수 있다.

22.08.02

- 스프링 핵심 : 컴포넌트 스캔 ~ 의존관계 자동 주입

- 애노테이션을 이용한 컴포넌트 스캔 자동 빈 등록, 탐색위치 지정 및 필터 기능에 대해 배웠다.
탐색위치 디폴트값이 자신이 위치한 패키지부터이므로 보통 패키지 최상위에 설정파일을 위치시킨다.
필터를 이용해 등록하지 않을 클래스를 지정할 수도 있다.

@AutoWired

- 의존관계 주입도 @AutoWired 애노테이션을 이용한다.
생성자, 수정자, 일반매서드, 필드 주입 이렇게 4가지 방법이 있지만, 생성자 사용을 권장하고, 필요에 따라 수정자를 이용한다.

private final MemberService memberService;

@AutoWired
public MemberService(MemberRepository memberRepository){
	this.memberRepository = memberRepository
}

- 생성자를 이용하면, final 을 사용할 수 있고, 이를 통해 값이 딱 한번만 설정되고 변하지 않음을 보장할 수 있다. 이렇게 필요에 따른 제한은 프로그래밍을 할 때 굉장히 좋은 요소라고 한다.

@Primary
public class DiscountPolicy rateDiscountPolicy{...}
@Qualifier("fixDiscountPolicy)
public class DiscountPolicy fixDiscountPolicy{...}

- 조회할 빈의 타입에 해당하는 것이 여러개일 때 우선순위나 구분을 위해 @Primary, @Qualifier 애노테이션을 이용하고 @Qualifier의 경우에는 애노테이션을 직접 커스텀해서 사용하기도 한다. 하지만 무분별한 애노테이션 생성은 유지보수를 어렵게 하니 주의해야 한다. 보통은 여러개인 경우 메인 객체를 Primary로 지정하고 다른 객체를 사용해야할 경우에 Qualifier를 이용한다.

@RequiredArgsConstructor
	static class DiscountService{
		private final Map<String, DiscountPolicy> policyMap;
		private final List<DiscountPolicy> policies;
	}

- Map이나 List에 해당 타입을 주입받아 다형성을 활용할 수 있다.

- 자동과 수동 등록을 이용하는 기준
기본적으로 자동을 활용, 직접 등록하는 기술 지원 객체, 다형성을 적극 활용하는 비즈니스 로직은 수동 등록을 고민

22.08.03

- 스프링 빈의 이벤트 라이프사이클
스프링 컨테이너 생성 -> 스프링 빈 생성 의존관계 주입 -> 초기화 콜백 -> 사용 -> 소멸전 콜백 -> 스프링 종료

의존관계 주입이 끝난 시점, 스프링 종료 직전에 수행해야하는 작업이 있을 때 해당 시점에 작동하도록 함수를 설정할 수 있다.

방법은 인터페이스 상속, @Bean 옵션추가, 자바표준 지원 애노테이션 사용이 있는데, 애노테이션을 사용하는 것이 권장된다.

어떻게 쓰는지는 알겠지만, 실제로 어떤 상황에서 사용되는지는 잘 상상이 안 된다. 하지만 객체의 생성과 초기화를 분리하는 것이 유지보수측면에서 더 좋다고 한다. 여기서 초기화는 외부커넥션을 연결하는 것과 같은 무거운 작업이다. 객체 생성자는 객체 자체를 생성하는 것에만 집중하는 편이 좋다.

- 빈 스코프
스프링 컨테이너에서 빈을 관리하는 범위를 빈 스코프라고 한다.

  • 프로토타입 스코프
    기본값이 싱글톤(생성 ~ 종료) 이고, 프로토타입이라는 옵션이 있다. 프로토타입은 생성 후 의존관계주입 후 초기화까지만 마치고 빈 관리를 종료한다.
    싱글톤 빈 안에 프로토타입 빈이 관련돼있을 때 문제가 발생한다. 프로토타입도 싱글톤과 함께 하나로 유지되기 때문이다. 이렇게 됐을 때 프로토타입 빈이 의도한대로 작동하지 않는다. 이를 해결하기 위해서 provider를 사용한다.
private ObjectProvider<PrototypeBean> prototypeBeanProvider; //provider 선언

public int logic() {
 PrototypeBean prototypeBean = prototypeBeanProvider.getObject(); 
 prototypeBean.addCount();
 int count = prototypeBean.getCount();
 return count;
}

ApplicationContext를 선언해서 getBean을 할 수도 있지만, 그렇게 되면 스프링에 너무 종속적인 코드가 된다.

사실 프로토타입은 거의 사용 x, 초기가 아닌 필요할 때 생성된다는 특징이 있다.

  • request scope
    request scope는 Http 요청이 들어오는 시점부터 나가는 시점까지 유지되는 스코프이다.
    request마다 각각 생성되고, 각 요청이 구분된다는 특징이 있다.
    프로토타입과 마찬가지로 request가 없는 시점에 의존관계 주입이 불가능하여 provider 를 사용해야 한다.
    provider대신 프록시를 이용해 문제를 해결할 수 있다.
@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MyLogger {
}

프록시는 가짜 객체를 만들고 실제 필요한 시점에 진짜 객체와 연결해주는 스프링의 기능중 하나이다.
사실 Provider를 사용하든, 프록시를 사용하든 핵심 아이디어는 진짜 객체 조회를 꼭 필요한 시점까지
지연처리 한다는 점이다.
단지 애노테이션 설정 변경만으로 원본 객체를 프록시 객체로 대체할 수 있다. 이것이 바로 다형성과 DI
컨테이너가 가진 큰 강점이다.
꼭 웹 스코프가 아니어도 프록시는 사용할 수 있다.

22.08.05

HTTP 기본지식 강의를 듣기 시작했다.

  • 인터넷 통신
    기본적으로 IP주소를 이용해 컴퓨터간 통신을 한다. 이 IP를 전화번호부처럼 이름을 붙인게 도메인, DNS(Domain Name System)이라고 부른다. 같은 IP 내에서 여러개의 요청을 할 때 구분하기 위해 사용되는 것이 port, 그리고 TCP, UDP는 요청이을 보내는 과정에서 데이터가 잘 갔는지 검증하거나, 순서를 보장하는 등 보조하는 역할이다.

이런식으로 전송 데이터를 TCP로 감싸고, IP로 다시 감싸서 전송한다.
UDP는 TCP보다 좀 더 간결한? 형식이라고 이해했는데, 최근에는 UDP를 사용하는 추세라고 한다.

  • URI
    URL, URN을 총칭하는데, 일반적으로 URL을 의미한다.

전체 문법
• scheme://[userinfo@]host[:port][/path][?query][#fragment]
https://www.google.com:443/search?q=hello&hl=ko

• 프로토콜(https)
• 호스트명(www.google.com)
• 포트 번호(443)
• 패스(/search)
• 쿼리 파라미터(q=hello&hl=ko)

  • HTTP
    거의 모든 데이터를 주고받는 형식이 HTTP이다.
    되도록 무상태, 비연결성으로 구성하는 게 좋다. 무상태로 했을 때 장점은, 서버 확장에 유리하고 더 효율적으로 요청을 처리할 수 있다. 하지만 주고받는 데이터의 양이 늘어나고, 연결을 끊었다 맺는데 비용이 발생한다.

  • HTTP 메서드
    HTTP 요청을 보낼 때 path를 설정하는데, 이 path 를 리소스로 구성하는 게 좋다고 한다.
    예를 들면 멤버를 찾는 거면 /member-find 가 아닌 그냥 /member 처럼 리소스로만 구성한다. 이때 동작을 구분하기 위해 HTTP 메서드를 이용한다.

- GET : 조회
- POST : 데이터를 처리 ( 대부분의 경우 사용 가능 )
- PUT : 데이터 자체를 교체, 바꿀 데이터의 위치가 정해져있고 클라이언트가 알고있다는 점에서 POST와 차이가 있고 데이터 자체를 바꿔버린다는 특징이 있다.
- PATCH : 데이터 수정, 일부분만 수정하는 점에서 PUT과 차이가 있다.
- DELTE : 삭제
이외에도 몇가지가 있지만 주로 사용되는 것의 위의 다섯가지이다.
메서드별로 안전, 멱등(Idempotent), 캐시와 같은 속성이 있다.
안전 : 리소스가 변하지 않는 것 ex) GET
멱등 : 여러번 호출해도 결과에 변화가 없는 것 ex) GET,PUT, DELETE
캐시는 뒤에서 자세히 다룰 예정

22.08.06

  • HTTP 메서드 활용
    클라이언트가 서버에 데이터를 전송하는 상황은 크게 4가지이다.
    정적 데이터 조회, 동적 데이터 (ex 검색 결과), HTML Form 이용, HTTP API 이용
    동적 데이터를 조회하는 경우에는 쿼리 파라미터를 이용한다.
    HTML Form 은 웹 브라우저에서 형식에 따라 요청을 생성해주는데, GET과 POST만 가능하다는 제약이 있다.
    HTTP API는 주로 서버와 서버간의 통신이나 앱 클라이언트에서 사용한다.
    여기에는 POST 기반 등록인 컬렉션(Collection) 과 PUT기반 등록인 스토어(Store) 가 있다.
    클라이언트가 자료의 이름을 알고 있는 경우가 Store 에 해당한다.
    이상적인 것은 URI를 리소스와 메소드로만 구성하는 것이지만 HTML Form 을 사용하는 경우는 메소드가 제한되기도 하고, 그렇지 않은 경우에도 이상적으로 구성하기엔 한계가 있다.
    그래서 동사를 추가로 구성하기도 하는데 이것을 컨트롤 URI라고 한다

2개의 댓글

comment-user-thumbnail
2022년 8월 15일

이야 빈씨 오랜만에 포스팅 !!

1개의 답글