[Spring] 스프링 핵심 원리 - 기본편
1. 객체지향
다형성 (역할과 기능 분리)
- 인터페이스
- 클라이언트를 변경하지 않고, 서버의 구현 기능을 유연하게 변경할 수 있다.
- 한계 : 역할(인터페이스) 자체가 변하면, 서버 모두에 큰 변경 발생 -> 인터페이스를 안정적으로 설계할 것
스프링과 객체지향
- 다형성
- 스프링에서 이야기하는 제어의 역전(IoC), 의존관계 주입(DI)은 다형성을 활용해서 역할과 구현을 편리하게 다룰 수 있도록 지원한다.
- 스프링의 핵심 = 객체 지향
- 객체지향의 핵심 = 다형성 = 구현과 기능 분리
좋은 객체 지향 설계의 5가지 원칙(SOLID)
- SRP(단일 책임 원칙) : 한 클래스는 하나의 책임만. 변경이 있을 때 파급 효과가 적어야 함
- OCP(개방-폐쇄 원칙)* : 확장에는 열려있으나 변경에는 닫혀있어야 한다 -> 스프링 컨테이너가 OCP를 지켜줌
- LSP(리스코프 치환 원칙) : 프로그램의 정확성을 깨뜨리지 않아야 한다
- ISP(인터페이스 분리 원칙) : 여러 개의 인터페이스로 분리
- DIP(의존관계 역전 원칙)* : 추상화에 의존해야지, 구체화에 의존하면 안된다. 추상 클래스에 의존해야지, 구체 클래스에 의존해서는 안된다.
=> DI와 DI컨테이너를 통해 SOLID를 지킬 수 있음
회원 도메인 설계의 문제점
- DIP 준수 X
- memberService와 MemberSericeImpl를 모두 의존하고 있음
관심사의 분리 - AppConfig
- MemberSericeImpl에서 MemoryMemberRepository를 가지도록 지정 받지 않고, AppConfig에서 MemberRepository를 가지도록 지정해줌
- *구체적인 것은 AppConfig에서 결정. "공연기획자"
제어의 역전 - IoC
- 프로그램의 제어 흐름을 직접 제어하는 것이 아니라 외부에서(AppConfig)에서 관리하는 것
- IoC 컨테이너, DI 컨테이너 = AppConfig
2. 스프링 컨테이너
ApplicationContext applicationContext
= new AnnotationConfigApplicationContext(AppConfig.class);
스프링 컨테이너 생성 방법
- XML 기반
- 애노테이션 기반의 자바 설정 클래스
빈 등록 방법
- 직접 등록
- FactoryBean을 통해 등록 (일반적으로 사용됨)
빈 출력 방법
- 빈 이름으로 출력하기
ac.getBean("memberService", MemberService.class)
- 빈 타입으로 출력하기
ac.getBean(MemberService.class);
상속관계
- 스프링 컨테이너 > 스프링 빈 저장소 > 스프링 빈
BeanFactory
<-ApplicationContext
<-AnnotationConfigApplicatonContext
3. 싱글톤 컨테이너
싱글톤 패턴
- 클래스의 인스턴스가 딱 1개만 생성되는 것을 보장하는 디자인 패턴
- 해당 객체가 하나만 생성되고, 객체 인스턴스를 공유해서 사용
스프링 & 싱글톤
- 스프링 컨테이너는 싱글톤 패턴을 적용하지 않아도, 객체 인스턴스를 싱글톤으로 관리한다
- 싱글톤 방식의 주의점 : 무상태(stateless)로 설계해야 한다!!!
- 객체 인스턴스를 공유하기 때문에 값이 변경될 수 있음
@Configuration과 싱글톤
AppConfig@CGLIB
을 통해 싱글톤 보장@Bean
이 붙은 메서드마다 이미 스프링 빈이 존재하면 존재하는 빈을 반환하고, 스프링 빈이 없으면 생성해서 스프링 빈으로 등록하고 반환하는 코드가 동적으로 만들어진다.
@Configuration
:AppConfig
->AppConfig@CGLIB
@Configuration
을 안 하고@Bean
만 하면 스프링 컨테이너의 싱글톤이 깨짐
4. @Component 와 DI
컴포넌트 스캔과 의존관계 자동 주입
- 기존 :
AppConfig.class
& 설정정보에 직접 등록 - 컴포넌트 스캔 : @Component 애노테이션이 붙은 클래스를 스캔하여 스프링 빈으로 등록
- 의존관계 자동 주입 : 클래스의 생성자에
@Autowired
를 붙여줌 -> 의존관계를 auto wire 함- 생성자가 1개 있으면
@Autowired
를 생략할 수 있음
- 생성자가 1개 있으면
스프링 빈 & 의존관계
@Configuration
,@Bean
: AppConfig 에 함@Component
,@Autowired
: 객체에 함
애노테이션
@Configuration
: 스프링 설정 정보로 인식. AppConfig에서 사용@Component
: 컴포넌트 스캔에서 사용@Controller
: 스프링 MVC 컨트롤러@Service
: 스프링 비즈니스 로직@Repository
: 스프링 데이터 접근 계층
필터
includeFilters
: 컴포넌트 스캔에 추가할 대상 지정excludeFilters
: 컴포넌트 스캔에 제외할 대상 지정
자동의존관계 주입 방법
스프링 빈에 등록되어야 의존관계 주입(DI)를 할 수 있다
-
생성자 주입 (권장)
- 불변, 필수
- 생성자 호출 시점에 딱 1번 호출
- 장점 : 대부분 다 불변임. final 키워드를 사용할 수 있음. 순수한 자바 언어의 특징을 잘 살리는 방법임.
- 롬복 : 코드 깔끔 - 예) getter setter 자동으로 만들어줌
-
수정자 주입(setter 주입)
- getter/setter -> 선택, 변경
-
필드주입
- 코드 간결 but 외부 변경 불가능
- 테스트 코드에서만 사용하자
-
일반 메서드 주입
- 잘 사용하지 않는다
조회된 빈이 2개 이상일 때
- @Autowired 필드 명 매칭
@Autowired private DiscountPolicy rateDiscountPolicy
- @Qualifier 끼리 매칭
@Component
@Qualifier("mainDiscountPolicy")
public class RateDiscountPolicy implements DiscountPolicy {
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, @Qualifier("mainDiscountPolicy") DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
- @Primary : 우선순위 부여
@Component
@Primary
public class RateDiscountPolicy implements DiscountPolicy { ... }
@Component
public class FixDiscountPolicy implements DiscountPolicy { ... }
동적으로 빈을 사용할 때
private final Map<String, DiscountPolicy> policyMap;
private final List<DiscountPolicy> policies;
- fixDiscountPolicy, rateDiscountPolicy 에 상관없이 Map 에 등록된 Bean 을 읽어와서 해당 할인 가격을 반환함
- 다형성을 활용하는 경우
자동, 수동의 올바른 실무 운영 기준
- 편리한 자동 기능을 기본으로 사용하자!
- 애플리케이션에 광범위하게 영향을 미치는 기술 지원 객체는 수동 빈으로 등록해서 딱! 설정 정보에 바로 나타나게 하는 것이 유지보수 하기 좋다.
- 다형성을 적극 활용하는 비즈니스 로직은 수동 등록을 고민해보자
5. 빈 생명주기
스프링 빈의 이벤트 라이프사이클
- 스프링 컨테이너 생성 -> 스프링 빈 생성 -> 의존관계 주입 -> 초기화 콜백 -> 사용 -> 소멸전 콜백 -> 스프링 종료
- 참고 : 생성자 주입은 스프링 빈이 생성될 때 의존관계 주입을 함께 함. but 객체 생성과 초기화는 분리하는 것이 좋음 (단일 책임의 원칙)
- 애노테이션
@PostConstruct
@PreDestroy
6. 빈 스코프
빈 스코프
- 빈이 존재할 수 있는 범위
- 싱글톤, 프로토타입, 웹관련스코프(request)
- 스프링 빈 => 싱글톤 스코프
프로토타입 스코프
@Scope("prototype")
- 프로토타입 스코프의 특징
- 스프링 컨테이너에 요청할 때 마다 새로 생성된다.
- 종료 메서드가 호출되지 않는다
- 싱글톤 빈과 함께 사용시 문제점
- 싱글톤 빈 위에 프로토타입 스코프가 만들어 지는데, 싱글톤 빈은 한번만 호출되고, 프로토타입 스코프도 싱글톤 빈 위에서 주입 시점에 한번만 호출됨
ObjectProvider
: 찾아주는 기능만 해서 여러개의 프로토타입 생성 가능
웹 스코프 - request
@Scope(value = "request")
- 웹 클라이언트의 요청(request) 가 올 때 생성됨
프록시
- 프록시(가짜) 객체를 만들어 진짜 myLogger을 찾는 방법을 저장
- 프록시 객체는 request 스코프의 진짜 myLogger.logic()을 호출함
- 프록시 객체 덕분에 클라이언트는 마치 싱글톤 빈을 사용하듯이 편리하게 request scope를 사용할 수 있다.
Author And Source
이 문제에 관하여([Spring] 스프링 핵심 원리 - 기본편), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@sians0209/Spring-스프링-핵심-원리-기본편저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)