[코드스테이츠] 05_01_TIL : Spring Framework 핵심 개념 _ DI
Today I Lean
Spring Framework 핵심 개념 _ DI
학습목표 및 개념정리
# DI (Dependency Injection)
- 버거퀸 프로그램을 스프링으로 전환해 보면서 스프링의 핵심 개념에 대해 이해할 수 있다.
- 기본적인 테스트 케이스의 개념과 구조를 이해하고, 간단한 테스트 케이스를 작성할 수 있다.
- 스프링 컨테이너가 싱글톤 컨테이너 임을 이해하고, 그 내용을 설명할 수 있다.
- @Configuration과 @Bean 애너테이션을 사용하는 수동 주입과 @ComponentScan과 @Component를 사용하는 자동 주입의 차이에 대해 이해하고, 이를 활용할 수 있다.
- @Autowired 애너테이션의 특성과 작동 방식에 대해 이해하고, 적절하게 활용할 수 있다.
배운 것
# DI (Dependency Injection)
1. 버거퀸 - 스프링 전환
→ 기존 버거퀸 코드 보러가기
- 스프링 전환
▪ 기존 버거퀸 실습과제의 문제점
- 새로운 할인 정책을 도입하는데 있어 부수적으로 변경해야 하는 코드들이 많았음 (객체지향적 설계원칙에 위반; OCP)
- 문제 발생의 핵심 지점 : 특정 객체가 어떤 객체를 사용할 것인지 직접 결정한다는 것
- 즉, 역할이 아닌 구현에 의존하고 있었음(의존성 역전원칙 위반; DIP)
→ new 연산자를 통해 구현객체를 직접 선택했음
public class CozDiscountCondition {
private FixedRateDiscountPolicy fixedRateDiscountPolicy = new FixedRateDiscountPolicy(10);
}
▪ 객체들의 관계를 관리 해 줄 클래스 설정 (의존성을 주입해 주는 역할)
- @Configuration : 스프링 컨테이너가 만들어 질 때 AppConfigurer 클래스를 컨테이너의 구성 정보로 사용한다는 의미
- @Bean : 스프링이 실행되었을 때 @Bean으로 등록된 메서드를 모두 호출하여 반환된 객체를 스프링 컨테이너에 등록하고 관리하겠다는 의미
- Cart 클래스를 싱글톤 패턴에서 스프링객체로 변경할 수 있었던 이유 : 스프링 컨테이너가 기본적으로 싱글톤으로 빈 객체들을 관리해주기 때문
// AppConfigurer 클래스는 각 역할과 책임에 따라 필요한 객체를 생성한 후에 생성한 객체의 참조값을 생성자를 통해 주입(연결)
// DI을 통해 각 객체들 간 의존 관계를 연결
@Configuration
public class AppConfigurer {
// private Cart cart = new Cart(productRepository(), menu()); 순수 자바 코드로 DI 구현
// Cart 클래스 객체를 한번 생성하여 구현한것 : 싱글톤 패턴(Singleton Pattern)
@Bean
public Menu menu() {
return new Menu(productRepository());
}
@Bean
public ProductRepository productRepository() {
return new ProductRepository();
}
@Bean
public Cart cart() {
return new Cart(productRepository(), menu());
}
@Bean
public Order order() {
return new Order(cart(), discount());
}
// 여기 코드를 변경하여 할인 정책을 추가하거나, 의존관계 변경이 가능
@Bean
public Discount discount() {
return new Discount(new DiscountCondition[] {
new CozDiscountCondition(new FixedRateDiscountPolicy()),
new KidDiscountCondition(new FixedAmountDiscountPolicy())
});
}
}
▪ 객체를 주입받을 클래스
: 구현객체가 객체의 참조값을 받으려면
→ 관련 필드 선언
→ 생성자의 참조값으로 주입받을 필드 설정
→ 각각의 필드 값이 외부의 영향으로 의도치 않게 변경되는 것을 방지하기 위해 접근 제어자를 private으로 선언
public class OrderApp {
// 주입 받을 필드 선언
private ProductRepository productRepository;
private Menu menu;
private Cart cart;
private Order order;
// 생성자를 통한 주입
public OrderApp(ProductRepository productRepository, Menu menu, Cart cart, Order order) {
this.productRepository = productRepository;
this.menu = menu;
this.cart = cart;
this.order = order;
}
}
▪ Main 클래스
- ApplicationContext : 스프링 컨테이너 (인터페이스로 구현되어 있음)
- AnnotationConfigApplicationContext : ApplicationContext의 구현객체 (AppConfigurer.class 를 구성정보로 넘김)
- 전달받은 클래스 구성정보를 바탕으로 스프링 컨테이너는 빈 객체 생성, 객체들 간의 의존 관계 연결
- getBean() 메서드로 필요한 객체(스프링 빈)를 불러서 사용 가능
public class Main {
public static void main(String[] args) {
// AppConfigurer 객체 생성
// AppConfigurer appConfigurer = new AppConfigurer();
// AppConfigurer 클래스에서 정의한 메서드 호출하여 DI 해줌
// OrderApp orderApp = new OrderApp(
// appConfigurer.productRepository(),
// appConfigurer.menu(),
// appConfigurer.cart(),
// appConfigurer.order()
// );
// 스프링 컨테이너 생성
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfigurer.class);
// 스프링 빈 조회
ProductRepository productRepository = applicationContext.getBean("productRepository", ProductRepository.class);
Menu menu = applicationContext.getBean("menu", Menu.class);
Cart cart = applicationContext.getBean("cart", Cart.class);
Order order = applicationContext.getBean("order", Order.class);
// 불러온 빈의 사용
OrderApp orderApp = new OrderApp(
productRepository,
menu,
cart,
order
);
orderApp.start();
}
}
2. 버거퀸 - DI
- 의존성 주입의 특징
: 빈번하게 사용되는 스프링의 핵심
▪ 주입 받는 객체
- 외부로부터 특정 객체를 주입받아 this 키워드를 사용하여 내부 필드에 할당 후 값 사용
- 모두 생성자를 통해 객체를 주입받고 있음
- 필드의 접근 제어자가 private 키워드를 통해 선언됨 (캡슐화)
- 생성자 주입에서도 private 키워드와 함께 final 키워드를 같이 사용하기도 함
→ 이 외에 setter 메서드를 사용하는 주입 (setter 주입)과 필드에 직접 주입 (필드 주입)하는 방식이 있지만 권장되지 않음
→ final 키워드 : 해당 값이 들어오지 않는 경우 컴파일러가 에러를 알려줌 (개발자의 실수에 의한 오류가 줄어듬)
▪ 주입 하는 클래스
- 객체를 생성하고 의존 관계를 연결시키는 역할 (버거퀸의 AppConfigurer)
- 순수 자바 코드 vs 스프링 프레임워크
: 차이점 → 스프링 컨테이너의 존재 여부
(1) 순수 자바 코드로 만들어진 AppConfigurer
AppConfigurer appConfigurer = new AppConfigurer();
OrderApp orderApp = new OrderApp(
appConfigurer.productRepository(),
appConfigurer.menu(),
appConfigurer.cart(),
appConfigurer.order()
);
(2) 스프링 컨테이너의 관리 하에 있는 AppConfigurer
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfigurer.class);
ProductRepository productRepository = applicationContext.getBean("productRepository", ProductRepository.class);
Menu menu = applicationContext.getBean("menu", Menu.class);
Cart cart = applicationContext.getBean("cart", Cart.class);
Order order = applicationContext.getBean("order", Order.class);
OrderApp orderApp = new OrderApp(
productRepository,
menu,
cart,
order
);
3. 스프링 컨테이너 (Spring Container), 스프링 빈 (Spring Bean)
- 스프링 컨테이너 (Spring Container)
▪ ApplicationContext
- ApplicationContext 인터페이스를 일반적으로 스프링 컨테이너 라고 부름
- 빈을 관리하고 조회함
- 웹 애플리케이션을 개발하는데 필요한 다양한 부가기능 제공
▪ AnnotationConfigApplicationContext
- ApplicationContext의 구현 객체
- 매개변수로 구성정보를 넘겨줌
→ 빈을 생성하고 호출할 때, 스프링 컨테이너는 호출되는 메서드의 이름을 기준으로 빈의 이름을 등록함
→ 각각의 빈은 해당 빈에 대한 메타정보를 가짐, 스프링컨테이너는 이 메타정보를 기반으로 스프링빈을 생성함
- 스프링 빈 (Spring Bean)
: 클래스의 등록정보, getter/setter메서드를 가짐
→ 구성정보(설정메타정보)를 통해 생성됨
▪ 빈 조회
: getBean()
// (1) getBean(빈 이름, 타입)
Cart cart = applicationContext.getBean("cart", Cart.class);
------------------------------------------------------------------------------------------
// (2) getBean(타입)
applicationContext.getBean(Menu.class);
------------------------------------------------------------------------------------------
// (3) 변경에 유연하지 않아 추천하지 않음
getBean(FixedAmountDiscountPolicy.class)
------------------------------------------------------------------------------------------
// (4) 스프링 빈에 있는 모든 빈 조회
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
Object bean = applicationContext.getBean(beanDefinitionName);
------------------------------------------------------------------------------------------
// (5) 빈 메타정보 조회
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
BeanDefinition beanDefinition = applicationContext.getBeanDefinition(beanDefinitionName);
if(beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION) {
* BeanFactory : 스프링 컨테이너의 최상위 인터페이스
▪ 빈 이름 설정
: 기본적으로 조회시 호출하는 이름으로 설정됨
@Bean (name = "cart2")
public Cart cart() {
return new Cart(productRepository(), menu());
}
→ 만약 위 코드와 같이 빈의 이름을 등록할 경우, 같은 이름의 빈이 등록 되지 않도록 주의 필요
4. 테스트 케이스 (Test Case)
- 단위 테스트 (Unit Test)
: 작은 단위의 어떤 특정 기능을 테스트하고, 검증하기 위한 도구 (테스트케이스를 작성한다고 표현)
→ 주로 입력 데이터, 실행 조건, 기대결과 에 대한 값을 테스트 함
- JUnit
: 스프링에서 제공하는 오픈소스 테스트 프레임워크
→ 각각의 단위 테스트는 메서드 단위로 작성
▪ 구조
- 기본적으로 test 디렉토리 안에서 작성하는것이 원칙
- main 패키지와 동일한 디렉토리 구조로 작성
- 테스트케이스 작성을 위한 테스트클래스는 테스트의 대상이 되는 클래스의 이름에 Test를 붙여서 클래스 생성
public class JunitDefaultStructure {
@Test
public void test1() {
// 테스트하고자 하는 대상에 대한 테스트 로직 작성
}
@Test
public void test2() {
// 테스트하고자 하는 대상에 대한 테스트 로직 작성
}
@Test
public void test3() {
// 테스트하고자 하는 대상에 대한 테스트 로직 작성
}
}
- 로직 작성
▪ 빈 조회 단위 테스트 작성
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MainTest {
// 스프링 컨테이너 생성
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfigurer.class);
// 빈 조회 테스트케이스
@Test
void findBean() {
// (1) given → 초기화 || 테스트에 필요한 입력 데이터
// AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfigurer.class);
// (2) when → 테스트 할 동작
Cart cart = applicationContext.getBean("cart", Cart.class);
// (3) then → 검증
Assertions.assertThat(cart).isInstanceOf(Cart.class);
}
}
▪ BDD (Behavior Driven Development)
: 테스트 로직 작성 템플릿
* 위 예제의 경우를 예시로 들어 설명 *
(1) given (입력 데이터)
- 테스트에 필요한 초기화 값 or 입력 데이터 의미
- 빈 조회 테스트에 필요한 초기화 세팅 : AppConfigurer 클래스를 구성 정보로 하는 스프링 컨테이너를 생성
(2) when (실행 동작)
- 테스트 할 실행 동작 지정
- 일반적으로 단위 테스트 에서는 메서드 호출을 통해 테스트를 진행 (보통 한 두줄 작성으로 끝남)
- 빈 조회 테스트에서 실행할 동작 : getBean() 메서드를 사용하여 빈을 불러오는 것
(3) then (결과 검증)
- 테스트의 결과를 최종적으로 검증
- 일반적으로 예상되는 기대값(expected)과 실제 실행 결과값을 비교
- 주로 JUnit / AssertJ 라이브러리에서 제공하는 Assertions 클래스의 기능 사용
- 위 코드는 AssertJ 라이브러리의 Assertions 클래스의 assertThat() 메서드 사용
- AssertJ는 메서드 체이닝(method cjaining)을 지원함 (스트림과 유사, 여러 메서드를 연속하여 호출이 가능)
- AssertJ에서 모든 테스트코드는 assertThat()을 사용 (테스트를 실행할 대상을 파라미터로 전달하여 호출)
- 호출결과는 ObjectAssert 타입의 인스턴스 반환 (isInstanceOf(), isCameAs(), isNotNull(), isNotEmpty() 사용 가능)
→ 테스트가 성공했을 경우 (왼쪽에 초록체크가 보임)
→ 테스트가 실패했을 경우 (왼쪽에 노란 엑스가 보임)
오류 메시지 해석
java.lang.AssertionError:
Expecting actual: // "조회된 Menu@55b62629 인스턴스가"
com.codestates.burgerqueenspring.Menu@55b62629
to be an instance of: // "Cart 클래스의 인스턴스 객체인 것으로 기대되었으나"
com.codestates.burgerqueenspring.Cart
but was instance of: // "실제로는 Munu 클래스의 인스턴스 객체인 것으로 보여짐"
com.codestates.burgerqueenspring.Menu
→ 잘못된 이름의 빈 조회 (메서드 레벨에 @DisplayName 애너테이션을 사용하면 테스트 케이스에 이름을 붙일 수 있음)
class MainTest {
@Test
@DisplayName("빈의 이름이 잘못된 경우")
void findBeanX() {
//given => 초기화 또는 테스트에 필요한 입력 데이터
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfigurer.class);
//when => 테스트 할 동작
Menu menu = applicationContext.getBean("car", Menu.class);
//then => 검증
Assertions.assertThat(menu).isInstanceOf(Cart.class);
}
→ 존재하지 않는 빈 검증 (Assertions가 AssertJ의 API가 아닌 JUnit 메서드 API를 사용)
import org.junit.jupiter.api.Assertions;
@Test
@DisplayName("빈이 존재하지 않는 경우2")
void findBeanX2() {
//given => 초기화 또는 테스트에 필요한 입력 데이터
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfigurer.class);
//when => 불필요
//then => 검증
Assertions.assertThrows(NoSuchBeanDefinitionException.class, () -> applicationContext.getBean("xxx", Menu.class ));
}
5. 스프링 컨테이너 = 싱글톤 컨테이너
- 싱글톤 패턴 (Singleton Pattern)
: 인스턴스가 단 한 번만 생성되게 만들어 객체의 참조값을 공유할 수 있도록 하는 것(싱글톤 패턴)
→ 동시다발적인 고객 요청을 처리할 때 사용
- 스프링컨테이너와 싱글톤 패턴
: 스프링 컨테이너는 직접 싱글톤패턴 코드(결합도가 높은 코드)를 작성하지 않아도 객체 인스턴스를 싱글톤으로 관리 함
→ 싱글톤으로 객체를 생성 및 관리하는 기능을 싱글톤 레지스트리(Singleton Registry)라 부름
→ 스프링 컨테이너가 싱글톤 레지스트리 기능을 가지고 있는 싱글톤 컨테이너이기 때문에 그 안에서 생성되고 관리되는 객체들이 싱글톤으로 관리 됨
▪ CGLIB 내부 동작 코드
: 스프링은 CGLIB라는 바이트코드 조작 라이브러리를 사용하여 싱글톤 레지스트리를 가능하게 함
@Bean
public Cart cart() {
if(cart가 이미 스프링 컨테이너에 있는 경우) {
return 이미 있는 객체를 찾아서 반환
} else {
새로운 객체를 생성하고 스프링 컨테이너에 등록
return 생성한 객체 반환
}
}
6. 빈 생명주기와 범위
: 스프링 컨테이너는 '초기화' 와 '종료'라는 생명주기(Life-cycle)를 가지고 있음
- 스프링 컨테이너 생명주기
public class Main {
public static void main(String[] args) {
// (1) 컨테이너 초기화
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(TestConfigurer.class);
// (2) 컨테이너 사용
ProductRepository productRepository = applicationContext.getBean("productRepository", ProductRepository.class);
Menu menu = applicationContext.getBean("menu", Menu.class);
Cart cart = applicationContext.getBean("cart", Cart.class);
Order order = applicationContext.getBean("order", Order.class);
// (3) 컨테이너 종료
applicationContext.close();
}
}
(1) 컨테이너 초기화
- AnnotationConfigApplicationContext를 통해 객체 생성, 스프링 컨테이너 초기화
- 스프링 컨테이너는 구성 정보를 기반으로 빈 객체 생성, 각 의존 관계를 연결하는 작업을 수행
(2) 컨테이너 사용
- 스프링 컨테이너의 관리하에 있는 빈 객체들을 조회하여 사용 가능
- 주로 getBean() 메서드를 사용하여 빈을 조회
(3) 컨테이너 종료
- 컨테이너를 close() 메서드를 통해 종료시킬 수 있음
- 빈 객체 생명주기
: 위 스프링 컨테이너의 생명주기와 비슷함
(1) 빈 객체 생성
- 스프링 컨테이너가 초기화 될 때 빈 객체 생성
(2) 의존관계 주입
- 스프링 컨테이너가 초기화 될 때 생성된 객체들 간의 의존관계 설정
(3) 초기화
- 메서드를 호출하여 빈 객체의 초기화
(4) 소멸
- 스프링 컨테이너가 종료되면, 메서드를 호출하여 빈 객체들을 소멸시킴
→ 데이터베이스의 커넥션 풀, 채팅 클라이언트의 기능을 구현 등에 사용
→ 스프링은 의존 관계 설정이 완료된 시점과 스프링 컨테이너의 종료 직전 시점에 지정된 메서드를 호출하여 개발자가 각각의 시점에 필요한 작업을 수행할 수 있도록 지원
▪ 공통 main 코드
public class ClientMain {
public static void main (String[] argss) {
// 컨테이너 생성
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext((ClientConfig.class));
// 컨테이너 사용
TestClient testClient = applicationContext.getBean("testClient", TestClient.class);
testClient.connect();
// 컨테이너 종료
applicationContext.close();
}
}
▪ InitializingBean & DisposableBean 인터페이스
public class TestClient implements InitializingBean, DisposableBean {
private String url;
public TestClient(String url) {
System.out.println("생성자 호출.");
this.url = url;
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("초기화 메서드 실행.");
}
public void connect() {
System.out.println("클라이언트를" + url + "로 연결.");
}
@Override
public void destroy() throws Exception {
System.out.println("종료 메서드 실행.");
}
}
@Configuration
public class ClientConfig {
@Bean
public TestClient testClient() {
// 생성자로 url 주소값 전달
TestClient testClient = new TestClient("www.codestates.com");
return testClient;
}
}
: 빈 객체가 InitialzingBean과 DisposableBean 인터페이스를 구현하면 스프링 컨테이너는 초기화, 소멸과정 각각 빈 객체의 afterPropertiesSet() 메서드와 destroy() 메서드를 실행함
→ 메서드 오버라이딩을 통해 적절한 기능 구현 가능
* InitialzingBean인터페이스와 DisposableBean 인터페이스의 한계
- 스프링 전용 인터페이스 이기 때문에, 초기화와 소멸 메서드 이름을 개발자가 변경하지 못함
- 직접 구현한 클래스가 아닌, 외부에서 받은 라이브러리나 클래스에 두가지 인터페이스를 적용할 수 없음
▪ @Bean 태그의 속성 값 활용 (한계를 없애기 위한 수정)
public class TestClient {
private String url;
public TestClient(String url) {
System.out.println("생성자 호출.");
this.url = url;
}
public void init() {
System.out.println("init() 초기화 메서드 실행");
}
public void connect() {
System.out.println("클라이언트를 " + url + "로 연결");
}
public void close() {
System.out.println("println() 종료 메서드 실행");
}
}
@Configuration
public class ClientConfig {
@Bean(initMethod = "init", destroyMethod = "close")
public TestClient testClient() {
TestClient testClient = new TestClient("www.codestates.com");
return testClient;
}
}
destroyMethod 속성 : 디폴트값이 (inferred), 즉 추론되도록 등록되어 있음
→ destroyMethod를 사용하지 않아도 빈번하게 사용되는 close 메서드 || shutdown 메서드를 자동 호출
→ destroMethod = "" 처럼 빈 공백으로 두면 close() 메서드가 호출되지 않음
▪ @PostConstruct와 @PreDestory 애너테이션 (가장 권장하는 방법)
public class TestClient {
private String url;
public TestClient(String url) {
System.out.println("생성자 호출.");
this.url = url;
}
@PostConstruct
public void init() {
System.out.println("init() 초기화 메서드 실행.");
}
public void connect() {
System.out.println("클라이언트를 " + url + "로 연결.");
}
@PreDestroy
public void close() {
System.out.println("close() 종료 메서드 실행.");
}
}
- 빈 객체의 관리 범위
스프링 빈은 스프링 컨테이너의 생성과 종료를 같이 함
이유 : 빈 객체가 별도의 설정이 없는 경우 싱글톤 범위(scope)를 가짐
빈객체의 스코프 : 빈 객체가 존재할 수 있는 범위
▪ 종류
싱글톤 (Singleton) : 제일 많이 사용
프로토 타입 (Prototype) : 스프링 컨테이너는 프로토타입 빈의 생성, 의존성 주입, 초기화 단계까지만 관여하고 그 이후에는 더 이상 관여하지 않음
세션 (Session)
리퀘스트 (Request)
그 중 프로토 타입 범위를 예시로 설명
(1) 싱글톤 범위
package com.codestates.burgerqueenspring.scope;
import org.junit.jupiter.api.Test;
import org.assertj.core.api.Assertions;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class ScopeTest {
@Test
public void scopeTest() {
// 컨테이너 생성
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(TestBean.class);
// 컨테이너 사용
TestBean bean = annotationConfigApplicationContext.getBean(TestBean.class);
TestBean bean2 = annotationConfigApplicationContext.getBean(TestBean.class);
System.out.println("bean = " + bean);
System.out.println("bean2 = " + bean2);
// 검증
Assertions.assertThat(bean).isSameAs(bean2);
// 컨테이너 종료
annotationConfigApplicationContext.close();
}
static class TestBean {
// 초기화 메서드 생성
@PostConstruct
public void init() {
System.out.println("init() 초기화 메서드 실행.");
}
// 종료 메서드 생성
@PreDestroy
public void close() {
System.out.println("close() 종료 메서드 실행.");
}
}
// 먼저 static으로 선언된 테스트용 TestBean 클래스를 생성하고 그 안에 초기화 메서드와 종료 메서드를 각각 선언
// 다음으로, TestBean 클래스를 구성 정보로 하는 스프링 컨테이너를 생성한 다음,
// getBean() 메서드를 통해 빈을 두 번 조회하여 동일한 객체를 반환하는지 출력하고
// Assertions 클래스의 isSameAs() 메서드를 통해 다시 검증
// 마지막으로 이렇게 컨테이너 사용이 끝나면 close() 메서드를 통해 컨테이너를 종료
}
(2) 프로토타입 범위
init() 초기화 메서드 실행.
bean = co m.codestates.burgerqueenspring.scope.ScopeTest$TestBean@b91d8c4
bean2 = co m.codestates.burgerqueenspring.scope.ScopeTest$TestBean@4b6166aa
7. 컴포넌트 스캔과 의존성 자동 주입
-
:
→
8. @Autowired
-
:
→
*****
- 객체지향 프로그램의 핵심
- 객체 지향 패러다임 (OOP; Object-oriented Programming Paradigm)의 출발점은 객체이다.
- 각각의 객체가 적절한 역할과 책임을 가지고 특정한 기능을 수행하기위해 협력하도록 만드는 일
- 객체 지향적 설계 : 변화와 확장에 유연하도록 프로그램을 고안하는 것 (인터페이스를 활용한 역할과 구현의 분리)
- 객체 간의 의존 관계가 높은 경우 그 관계의 결합도가 높다고 할 수 있음 (유연한 코드 설계에 위배되기에 지양해야 함)
- 캡슐화를 통해 각 객체의 자율성 보장
- 응집도를 높이고 다른 객체와의 강한 결합도를 낮춰 유기적인 협력관계에 참여할 수 있도록 코드를 설계 해야 함
- 스프링 프레임워크의 핵심
- 프레임워크 (Framework)란 어떤 애플리케이션을 만들기 위한 틀 또는 구조를 의미
- 코드 흐름의 제어권이 개발자가 아닌 프레임워크에 있음
- 개발자가 주도권을 가지는 라이브러리 (Library)와 구분됨
- 스프링 프레임워크는 POJO 프로그래밍을 지향하면서 IoC/DI, AOP, PSA라는 세가지축을 가짐
- 스프링 프레임워크는 다양한 기능들을 제공하는 모듈들의 묶음
- 스프링 부트는 의존 라이브러리의 자동 관리, 설정의 자동구성, 손쉬운 빌드 및 배포등의 장점을 가짐
- 개발자가 비즈니스 로직에만 집중할 수 있도록 도와줌
Tomorrow Chapter
# AOP (Aspect Oriented Programming)
↓ 이전 글 ↓
↓ 코트스테이츠 부트캠프 관련 글 한번에 보기 ↓