스프링 강의 요약-(2)

이진우·2023년 7월 1일
0

스프링 강의 요약

목록 보기
3/13

아래는 김영한 강사님의 스프링 핵심원리 강의를 듣고 중요한 내용 또는 어려운 내용을 정리한 것이다.

Section1

스프링의 핵심:스프링프레임워크
여러 스프링 기술 편리하게:스프링부트
스프링은 객체지향 언어(자바가 가진 강력한 특징을 살려내는 프레임워크 DI,IOC컨테이너)

스프링 프레임워크

  • 핵심기술:DI 컨테이너,Aop 이벤트,기타
  • 웹기술:스프링 MVC
  • 데이터 접근 기술:트랜잭션 JDBC ORM 지원
  • 기술통합: 캐시,이메일 ,원격접근 등
  • 테스트
  • 스프링부트


    스프링을 편리하게 사용할 수 있도록 지원,기본으로 생성

    스프링이란

  • 스프링 DI 컨테이너 기술
  • 스프링 프레임 워크
  • 스프링 부트,스프링 프레임 워크를 모두 포함한 생태계
  • 객체 지향 특징

    "객체들의 모임" 객체는 메세지를 주고 받으며 협력 , 유연하고 변경용이

    다형성이란?

    클라이언트를 변경하지 않고 서버의 구현 기능을 유연하게 변경 할 수 있는게 다형성의 본질이다
    스프링은 다형성을 편리하게 사용할 수 있도록 지원하는 기술이라 할 수 있음

    SOLID

  • SRP:단일 책임 원칙:한 클래스는 하나의 책임만 가져야 한다.
  • OCP:개방 폐쇄 원칙:확장에는 열려잇으나 변경에는 닫혀 있어야 함
  • LSP:리코프 지환 원칙:프로그램의 객체는 하위타입의 인스턴스로 바꿀수 있어야 함.
  • ISP:인터페이스 분리 원칙:특정 클라이언트를 위한 Interface 여러개가 범용 Interface 하나보다 낫다
  • DIP:의존 관계 역전 원칙:추상화에 의존해야지 구체화에 의존하면 안된다.
  • 결론

    스프링은 DI(의존관계,의존성 주입),DI컨테이너 제공 함으로 다형성 +OCP,DIP 가능하게 지원한다.

    Section2


    변경 가능성이 높은 것들은 역할과 구현을 분리하는 인터페이스를 적극 활용할 수 있다
    회원 클래스 다이어 그램과 회원 객체 다이어그램 중에 차이점 중 하나는 회원클래스 다이어그램은 인터페이스로 연결하여 실제로 무엇이 연결되는지 알수는 없으나 회원 객체 다이어그램은 클라리언트가 실제로 사용하는 것을 화살표로 표시한다

    테스트코드에다가 테스트 하는 이유

  • 실패했을 때 캐치가 쉽다
  • 회원 도메인 설계의 문제점(순수 자바코드)

    의존관계가 인터페이스 뿐만 아니라 구현까지 모두 의존하는 문제점
    ex)MeberService memberService=new MemberServiceImpl();

    참고

  • sout order하면 자동으로 toString 출력된다
  • enumType은 ==비교가 가능하다
  • NULL이 들어갈 수 있다면 Long으로 그게 아니면 primitive type으로 해도 상관 없다(long)
  • Section3

    문제점

  • 우리가 만든 것에 새로운 정책을 추가하고 사용할 때 문제점이 발생한다
  • OrderServiceImpl에는 DiscountPolicy인터페이스 뿐만 아니라 FixDiscountPolicy인 구체 클레스도 함께 의존하고 있기에 DIP위반이다
  • 정책을 변경하는 순간 OrderServiceImpl(클라이언트코드)도 함께 변경해야 하기 때문에 OCP위반이다
  • 뿐만 아니라 OrderServiceImpl에서 무언가 생성하는 역할을 하는 것이 탐탁지 않다 단일 책임 원칙에 살짝 안맞는다
  • -->DIP를 위반하지 않게 하려면 인터페이스에만 의존하게 해야하는데?

    해결방법

  • 누군가가 클라이언트인 OrderServiceImpl에 구현 객체를 생성하고 주입해 주어야한다.
  • 따라서 나의 애플리케이션 전체를 설정하고 구성하는 역할을 하는 AppConfig라는 것을 만들었다.
  • AppConfig에서 객체를 생성하고 주입해주므로(이 과정을 DI라고 함) 클라이언트 코드는 DIP를 완성하였다
  • 클라이언트 코드에서 생성할 것이 없어지므로 단일책임원칙 까지 잘 지킨다
  • 또한 클라이언트 코드를 변경하지 않아도 정책을 변경할 수 있으니 OCP를 잘 지킨다
  • --->AppConfig 같은게 필요하다

    참고

  • 테스트 작성할때 실패 테스트를 만들어야 한다.
  • AppConfig같은 설정 정보를 사용할 때는 역할과 구현이 잘 보이게 Refactoring 하는 것이 좋다
  • IoC(제어의 역전)이란 내가 무언가 호출하는 것이 아니라 framework같은 것이 내 코드를 대신 호출해 주는 것이라고 할 수 있다.
  • ex)Junit은 내가 짠 코드의 실행과 제어권을 가져서 Framework이다.
  • ApplicationContext는 Spring의 모든 것을 시작하면서 스프링 컨테이너의 역할을 한다. @Bean이라는 것을 다 관리한다라고 생각할것
  • 결국

    Spring이 DI컨테이너 역할을(DIP,단일책임원칙,OCP을 지킨다)를 하면서 추가적인 좋은 기능을 제공해주니 Spring을 쓴다.

    Section4

    컨테이너란?

    사용하는 객체들을 담고 있는것,ApplicationContext가 컨테이너 역할을 함

    참고

  • 자바 코드로 스프링 빈을 등록하면 생성자를 호출하면서 의존관계 주입도 한번에 처리됨.
  • 빈 이름은 항상 다른 이름을 부여 해야 함
  • 부모 타입으로 조회하면 자식 타입도 함꼐 조회하는 대원칙이 있다
  • 스프링 컨테이너는 다양한 형식의 설정 정보를 받아드릴 수 있게 유연하게 설계 되었다.
  • BeanDefinition이라는 추상화로 다양한 설정 형식을 지원
  • Section5

    스프링 컨테이너의 필요성

    객체 인스턴스가 JVM 안에 딱 하나만 있어야 하는 패턴을 싱글톤 패턴이라고 한다
    스프링 없이 순수한 자바 코드로 new 를 한다면 서로 다른 객체가 생성될 것이다
    우리는 요청할때마다 새로운 객체를 생성한다면 메모리 낭비가 심하므로 객체가 딱 1개만 생성되고 공유하도록 설계해야 한다
    static 을 사용해서 자바 코드로 순수하게 설계할 수 있지만 DIP,OCP 위반 가능성이 커지며 코드가 지저분해지는 단점이 있다
    싱글톤 컨테이너(스프링 컨테이너)를 사용한다면 싱글톤 패턴을 위한 지저분한 코드가 들어가지 않아도 된다

    주의점

  • 특정 클라이어느에 의존적인 필드가 있으면 안된다!
  • 특정 클라이언트가 값을 변경할 수 있는 필드가 있으면 안된다!
  • 가급적 읽기만 가능해야 한다(값을 수정하면 안된다)
  • @Configuration 과 싱글톤

    @Configuration이 붙는다면 싱글톤을 보장해준다.
    @Configuration 이 없다면 싱글톤이 보장이 안된다.
    이 경우 New 해서 생성되는 객체는 Spring 이 관리를 안해준다

    참고

  • 테스트에서 isSameAs는 ==과 같고 , isEqualTo는 자바의 equal과 같다
  • 객체 인스턴스를 생성하는데 비용이 1000이면 참조 가져오는 비용은 1정도로 엄청 작다
  • 요청할 때마다 새로 꺼내는 경우, http request life cycle 에 맞추어서 빈 라이프 사이클을 맞추거나,
    http session과 똑같은 life cycle 맞추어서 사용,고객이 들어올때 만들고 나갈때 죽이는 경우 만들거나
    할때 Singleton 안쓰는 경우가 있다.(99% singleton)
  • Section6

    요약

  • Autowired 는 마치 ac.getBean(MemberRepository.class)해주는 거랑 비슷하다
  • 스프링 빈의 기본 이름은 클래스 명을 사용하되 맨 앞글자만 소문자를 사용한다.
  • 기본 조회 전략: 타입이 같은 빈을 찾아서 주입
  • @Component 스캔이 붙은 설정 정보 클래스의 패키지가 시작 위치가 된다.
  • @SpringBootApplcation에 @ComponentScan 들어있다
  • Controller,@Service,@Repository,@Configuration 모두 @ComponentScan있다
  • 자동 빈 등록 될때 괜히 이름 변경하지 말것
  • 수동 빈 등록과 자동 빈 등록 시 스프링 부트는 에러 메세지를 띄운다.
  • 참고

  • @Configuration 이 컴포넌트 스캔의 대상이 된 이유는 @Configuration 에 @ComponentScan애노테이션이 붙어있기 때문
  • Section7

    의존관계 주입 방법

    생성자 주입

  • 생성자 호출시점에 딱 1번만 호출되는 것 보장
  • 불변 필수 의존관계에 사용된다.
  • 생성자 주입은 빈을 등록하면서 의존관계 주입도 함게 일어남
  • 수정자 주입

  • 선택,변경 가능성이 있는 의존관계에 사용됨
  • 선택:@Autowired(required=false)로 선택가능
  • 변경: 외부에서 강제로 호출가능
  • 필드 주입

  • 외부에서 변경이 불가능하고 순수한 자바코드 테스트를 못한다는 단점떄문에 사용하지 않는다.
  • 일반 메서드 주입

  • 일반 메서드를 통해서 주입할 수 있으나 잘 사용되지 않는다.
  • 스프링 빈이 없어도 동작해야 할 경우

  • @Autowired(required=false)->자동 주입할 대상이 없으면 메소드 호출 안된다
  • @Nullable: 자동 주입할 대상이 없으면 NULL 입력
  • Optional:자동 주입할 대상이 없으면 Optional.empty 입력
  • 생성자 주입이 좋은 이유

  • 불변:대부분 의존 관계 주입은 한번 일어나면 종료시점까지 의존관계가 변경될 일이 없는데 이를 보장하는게 생성자 주입
  • 누락: 수정자 주입같은 경우 데이터 누락시 컴파일 오류 없고 NULL pointer Exception 이 터지나 생성자 주입을 사용하면 주입 데이터를 누락하면 컴파일 오류선으로 해결이 가능하다.
  • final:생성자에서 혹시라도 값이 설정되지 않는 오류를 컴파일 시점에 막아주는 장점이 있다.
  • 정리

    기본으로 생성자 주입 선택, 필수 값이 아닌 경우 수정자 주입 방식을 옵션으로 설정(생성자 주입과 설정자 주입 동시 사용가능)

    롬복 사용 이유

  • @Getter,@Setter를 사용하면 자동으로 Getter,Setter를 만들어 준다
  • RequiredArgsConstructor로 final 이 붙은 것을 가지고 생성자를 자동으로 만들어 준다.
  • Autowired는 중복 타입 해결

  • @Autowired 는 타입으로 조회하기 때문에 두개 이상이 같은 타입일때 어떤 것을 끌고 올지 애매하다
  • 해결방법

  • 1)@Autowired 는 타입 매칭을 시도하고 여러 빈이 있다면 ,필드 이름 파라미터 이름으로 빈 이름을 추가로 매칭한다
  • 따라서 DiscountPolicy discountPolicy 를 DiscountPolicy rateDiscountPolicy로 고쳐서 매칭 가능
  • 2)@Qualifier: 클래스 위에 @Qualifier("이름")을 붙인 후 사용할 때도 @Qualifier("이름")으로 특정 빈 가져오기 가능하다
  • 단, @Qualifier("이름")은 문자이기 떄문에 실수할 가능성이 높으므로 애노테이션을 따로 지정하는 것도 생각을 해볼 수 있어야 한다.
  • 3)@Primary:@Primary가 붙은 클래스가 우선권을 가진다
  • 정리하면...

    자주 사용하는 것은 @Primary 로 사용 하고
    그렇지 않은 것들은 @Qualifier로 따로 지정한다.

    조회할 빈이 모두 필요할때:List,Map

    할인 서비스를 제공하는데 클라이언트가 fix,rate 를 선택할 수 있다고 가정하자,이럴 떄 사용될 수 있다.
  • List '<'DiscountPolicy> policies 에 DiscountPolicy 타입으로 조회한 모든 스프링 빈 타입을 담는다
  • Map'<'String,DiscountPolicy> 에는 map에 키에 스프링 빈의 이름을 넣어주고 그 값으로 DiscountPolicy 타입으로 조회한 모든 스프링 빈을 담아줌.
  • 자동vs수동

    자동 기능을 우선으로 사용하되 기술적인 문제나 공통 관심사(AOP)를 처리할 떄 주로 사용하는 기술(데이터베이스 연결,공통 로그 처리) ->기술 지원 객체는 수동 빈으로 등록. 단 다형성을 활용하는 비즈니스 로직은 자동과 수동 등록을 고민해야 한다. 수동으로 등록하면 한눈에 빈의 이름, 어떤 빈들이 주입될지 알 수 있기 때문

    참고

  • 자바빈 프로퍼티:get,set 메소드 활용
  • new AnnotationConfigApplicationContext(AutoAppConfig.class,DiscountService.class) 는 1) 컨테이너 생성 후 2)AutoAppConfig와 DiscountService 를 파라미터로 넘기면서 해당 클래스를 자동으로 스프링 빈 등록
  • Section8

    빈 생명 주기 콜백

  • 스프링 빈이 생성되거나 스프링 빈이 죽기 일보 직전에 스프링이 빈 안에 있는 메서드를 호출 할 수 있는 기능
  • 주로 데이터베이스 커넥션 풀이나 ,네트워크 소켓처럼 애플리케이션 시작 지점에 필요한 연결을 할때 사용
  • 객체 내부의 값을 세팅할때만 생성자를 활용하고 무거운 작업이나 외부 연결은 별도의 초기화 세팅으로 하는게 유지 보수 관점에서 좋다
  • 초기화 작업은 의존관계 주입이 완료되고 난 다음에 호출하고 싶을떄 다음 세가지 방법을 사용한다.
  • 인터페이스 InitiallizingBean,DisposableBean

  • 스프링 전용 인터페이스이고 외부 라이브러리에 적용할 수 없기에 안쓴다
  • 빈 등록 초기화 소멸 메서드 지정

  • @Bean(initMethod="init",destroyMethod="close")처럼 초기화 소멸 메서드 지정
  • 외부 라이브러리에도 초기화 종료 메서드 지정 가능 하고 스프링 코드에 의존적이지 않다
  • 종료 메서드는 close,shutdown 추론 가능
  • @PostConstructor,@PreDestroy

  • 자바 표준이기에 스프링 이 아닌 다른 컨테이너에서도 동작
  • 컴포넌트 스캔과도 어울린다.
  • 외부라이브러리에 적용 불가
  • 정리

    빈 생성 시 메서드 호출, 종료시 메서드 호출 필요시
    @PostConstructor,@PreDestroy 메서드 사용하되
    코드를 고칠 수 없는 외부라이브러리라면 @Bean의 initMethod,destroyMethod를 사용할 것

    Section9

    스프링은 다양한 스코프 지원

  • 싱글톤:스프링 컨테이너의 시작과 끝
  • 프로토타입: 스프링 컨테이너는 빈의 생성, 의존관계 주입, 초기화 메서드 부르고 클라이언트에 던져버리고 끝
  • Request: 웹 요청이 들어오고 나갈때까지만 유지
  • session: 웹 세션이 생성되고 종료될떄 까지만 유지
  • 프로토타입 스코프

  • 싱글톤과 다르게 프로토타입 스코프의 빈을 스프링 컨테이너에 요청하면
    ->그 시점에 프로토타입 빈을 생성하고, 필요한 의존관계 주입
    ->생성한 프로토 타입 빈을 클라이언트에 반환하고, 클라이언트에게 책임을 넘김
    ->같은 요청이 오면 항상 새로운 프로토타입 빈을 생성해서 반환
    ->종료 메서드 호출 X
  • 싱글톤과 문제점

    ->싱글톤 안에서 프로토타입 빈을 사용한다면 의도와는 다르게
    두 클라이언트가 프로토타입 클래스의 Count함수를 요청해도
    총 Count가 2가 되는 문제점이 발생한다.

    해결법

    ObjectProvider

  • 항상 새로운 프로토 타입 빈 생성가능
  • getObject를 호출하면 내부에서 스프링 컨테이너를 통해 해당 빈을 찾아서 반환(DL)
  • JSR-330 Provider

  • 라이브러리를 Gradle 에 추가해야함
  • 기능 단순
  • 프로토타입 빈 언제 사용?

    매번 사용할때마다 의존관계 주입이 완료가 된 새로운 객체가 필요하면 사용 ->거의 안씀

    웹 스코프

  • request:HTTP 요청 하나가 들어오고 나갈 때 까지 유지되는 스코프, 각각의 HTTP 요청마다 별도의 빈 인스턴스가 생성되고 관리된다
  • 동시에 여러 HTTP 요청이 오면 정확히 어떤 요청이 남긴 로그인지 구분하기 어렵기에 request 스코프를 사용한다.
  • request 요청이 있을 때만 생성이 가능한 클래스가 있고 그 클래스를 가진 클래스가 있다면 빈의 생성 시점(정확히 말하면 스프링 컨테이너에 요청을 지연)을 지연하여 문제를 해결할 수 있다
  • 해결법 1: ObjectProvider
  • 해결법 2: 프록시
  • ->가짜 프록시 객체를 만들어서 주입
    ->가짜 프록시 객체는 요청이 오면 그떄 내부에서 진짜 빈을 요청하는 로직이 있음
    결국 중요한 것은 지연해서 처리한다는 것!

    참고

  • AnnotationConfigServletWebServerApplicationContext로 웹과 관련된 애플리케이션 구동 가능
  • HttpServletRequest 는
    1)HTTP 요청을 파라미터,헤더,쿠키,세션 등 액세스 가능
    2)클라이언트의 IP주소,요청 메소드,요청 URL 등을 알 수 있다.
  • 완료!

    profile
    기록을 통해 실력을 쌓아가자

    0개의 댓글