일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
- string과 stringbuilder 성능 최적화
- 정보처리기사 필기 벼락치기
- 비전공자 정처기 필기
- 프로그래머스
- 프로그래머스 문자열 정렬하기(1)
- 펙토리얼
- 스프링 부트 배너 설정
- 정처기 필기 벼락치기
- cursor 설치
- 스프링 부트 프로젝트 세팅
- cursor 우클릭 메뉴
- 배열 순환
- 소인수분해 구하는 공식
- 정보처리기사 필기
- 스프링부트 의존성 설정
- 자바 소인수분해
- 자바 팩토리얼
- 피그마 썸네일
- 숨어있는 숫자의 덧셈 (1) 자바
- 왓챠피디아 클론 코딩
- spring boot 배너 설정
- 오블완
- 배열 순환 문제 공식
- 경우의 수 자바
- 접속 url 출력
- 비전공자 정보처리기사 필기
- 배열 순환 자바
- 티스토리챌린지
- 자바 합성수 찾기
- 프로그래머스 공 던지기 게임
- Today
- Total
여름 언덕에서 배운 것
[스프링기본편1]스프링 컨테이너와 스프링 빈 본문
스프링 핵심 원리 - 기본편 - 인프런 | 강의
스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다., 스프링 핵심 원리를 이해하고, 성장하는 백엔드 개발자가 되어보세요! 📢
www.inflearn.com
스프링 빈 조회 -기본
package hello.core.beanfine;
import hello.core.AppConfig;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import static org.assertj.core.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.*;
public class ApplicationContextBasicFindTest {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
@Test
@DisplayName("빈 이름 조회")
void findBeanByName(){
MemberService memberService = ac.getBean("memberService", MemberService.class);
// System.out.println("memberService = " + memberService);
//System.out.println("memberService = " + memberService.getClass());
//멤버 서비스가 멤버서비스Impl의 인스턴스면 성공!
assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
@Test
@DisplayName("이름 없이 타입으로만 조회")
void findBeanByType(){
MemberService memberService = ac.getBean(MemberService.class);
assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
@Test
@DisplayName("구체 타입으로 조회")
void findBeanByName2(){
MemberService memberService = ac.getBean(MemberServiceImpl.class);
assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
@Test
@DisplayName("빈 이름으로 조회가 X ")
void findBeanByNameX(){
//ac.getBean("zz", MemberService.class); 멤버 서비스(?) 에 없다.
MemberService xxx = ac.getBean("zz", MemberService.class);
assertThrows(NoSuchBeanDefinitionException.class,
()->ac.getBean("zz", MemberService.class));
//화살표 오른쪽에 있는 코드가 실행이 되면 왼쪽에 있는 예외가 터져야 한다는 뜻
}
}
스프링 빈 조회 - 동일한 타입이 둘 이상
타입으로 조회시 같은 타입의 스프링 빈이 둘 이상이면 오류가 발생한다. 이때는 빈 이름을 지정하자.
package hello.core.beanfine;
import hello.core.AppConfig;
import hello.core.discount.DiscountPolicy;
import hello.core.member.MemberRepository;
import hello.core.member.MemoryMemberRepository;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
public class ApplicationContextSameBeanFindTest {
//이걸 사용하면 AppConfig 손봐야 하니까 , 여기서만 사용할 class static으로 선언하기
// AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SameBeanConfig.class);
@Test
@DisplayName("타입으로 조회시 같은 타입이 둘 이상있으면 , 중복오류가 발생한다")
void findBeanByTypeDuplicate(){
MemberRepository bean = ac.getBean(MemberRepository.class);
}
@Configuration // Java 구성 클래스를 선언할 때 사용
static class SameBeanConfig{ //클래스 안에서 클래스를 썼다는 것은 여기 안에서만 scope을 사용하겠단 뜻입니다.
@Bean
public MemberRepository memberRepository1(){
return new MemoryMemberRepository();
}
@Bean
public MemberRepository memberRepository2(){
return new MemoryMemberRepository();
}
}
}
CTRL SHIFT ENTER 코드로 넘어가게 해주는 단축키
CTRL ALT V 변수 지정명(?) 해주는 단축키
package hello.core.beanfine;
import hello.core.AppConfig;
import hello.core.discount.DiscountPolicy;
import hello.core.member.MemberRepository;
import hello.core.member.MemoryMemberRepository;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class ApplicationContextSameBeanFindTest {
//이걸 사용하면 AppConfig 손봐야 하니까 , 여기서만 사용할 class static으로 선언하기
// AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SameBeanConfig.class);
@Test
@DisplayName("타입으로 조회시 같은 타입이 둘 이상있으면 , 중복오류가 발생한다")
void findBeanByTypeDuplicate(){
// MemberRepository bean = ac.getBean(MemberRepository.class);
assertThrows(NoUniqueBeanDefinitionException.class,
() -> ac.getBean(MemberRepository.class));
}
@Test
@DisplayName("타입으로 조회시 같은 타입이 둘 이상있으면,빈 이름을 지정하면 된다")
void findBeanByName(){
//빈 이름을 지정하여 조회, 지정된 이름을 사용하여 repository를 가져오면서 이 빈이 클래스의 인스턴스인지 확인
MemberRepository repository = ac.getBean("memberRepository1", MemberRepository.class);
assertThat(repository).isInstanceOf(MemberRepository.class);
}
@Test
@DisplayName("특정타입을 모두 조회하기")
void findAllBeansByType() {
//MAP 키, 밸류 값
Map<String, MemberRepository> beansOfType = ac.getBeansOfType(MemberRepository.class);
/여기서 String은 빈의 이름(빈 ID)이 되고, MemberRepository는 빈의 인스턴스
for(String key : beansOfType.keySet()){
System.out.println("key = " + key + "value = " + beansOfType.get(key));
}
System.out.println("beansOfType = " + beansOfType);
assertThat(beansOfType.size()).isEqualTo(2);
}
@Configuration // Java 구성 클래스를 선언할 때 사용
static class SameBeanConfig { //클래스 안에서 클래스를 썼다는 것은 여기 안에서만 scope을 사용하겠단 뜻입니다.
@Bean
public MemberRepository memberRepository1() {
return new MemoryMemberRepository();
}
@Bean
public MemberRepository memberRepository2() {
return new MemoryMemberRepository();
}
}
}
`keySet()`은 자바에서 `Map` 인터페이스를 구현한 컬렉션에서 사용되는 메서드 중 하나입니다.
`keySet()` 메서드는 해당 `Map` 객체에서 모든 키(key)를 가져와서 그 키들을 포함한 `Set` 컬렉션을 반환합니다.
여기서 각 용어에 대한 설명은 다음과 같습니다:
- **Map**: `Map`은 키(key)와 값(value)을 쌍으로 저장하는 자료구조입니다. 키를 사용하여 값을 검색할 수 있습니다.
예를 들어, 전화번호부의 이름과 전화번호가 저장된다면, 이름이 키이고 전화번호가 값입니다.
- **keySet()**: `keySet()` 메서드는 `Map`에서 모든 키(key)를 추출하여 이를 `Set` 컬렉션으로 반환합니다.
`Set`은 중복된 요소를 허용하지 않는 자료구조로, 각 키는 중복되지 않고 유일합니다.
예를 들어, 다음은 `Map` 객체에서 `keySet()`을 사용하는 간단한 예제입니다:
Map<String, Integer> ageMap = new HashMap<>();
ageMap.put("Alice", 30);
ageMap.put("Bob", 25);
ageMap.put("Charlie", 35);
Set<String> names = ageMap.keySet();
System.out.println(names); // 출력: [Alice, Bob, Charlie]
위 코드에서 `ageMap.keySet()`을 호출하면 `ageMap`에서 모든 키를 추출하여 `Set`으로 반환합니다.
따라서 `names` 변수에는 모든 이름이 중복 없이 저장되어 있습니다.
이렇게 추출된 키를 사용하여 `Map`에서 값을 검색하거나 수정할 수 있습니다.
`keySet()`은 많은 경우에 `Map`의 키를 반복적으로 접근할 때 유용하며,
반복문을 통해 `Map`의 키를 순회하거나 특정 키를 검색하는 작업에 자주 활용됩니다.
스프링 빈 조회 - 상속 관계
부모 타입으로 조회하면, 자식 타입도 함께 조회한다.
그래서 모든 자바 객체의 최고 부모인 Object 타입으로 조회하면, 모든 스프링 빈을 조회한다.
package hello.core.beanfine;
import hello.core.discount.DiscountPolicy;
import hello.core.discount.FixDiscountPolicy;
import hello.core.discount.RateDiscountPolicy;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class ApplicationContextExtendsFindTest {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);
@Test
@DisplayName("부모타입으로 조회시 자식이 둘 이상 있으면 중복오류가 발생한다")
void findBeanByParentTypeDuplicate(){
assertThrows(NoUniqueBeanDefinitionException.class,
() -> ac.getBean(DiscountPolicy.class));
}
@Test
@DisplayName("부모타입으로 조회시 자식이 둘 이상 있으면 빈 이름을 지정한다.")
void findBeanByParentTypeBeanName(){
DiscountPolicy rateDiscountPolicy = ac.getBean("rateDiscountPolicy", DiscountPolicy.class);
//ac.getBean("rateDiscountPolicy", DiscountPolicy.class)은 스프링 컨테이너에서 이름이 "rateDiscountPolicy"인 빈을 찾아서 반환합니다.
assertThat(rateDiscountPolicy).isInstanceOf(RateDiscountPolicy.class);
}
@Test
@DisplayName("특정 하위타입으로 조회") // 좋은 방법은 아니다.
void findBeanBySubType(){
RateDiscountPolicy bean = ac.getBean(RateDiscountPolicy.class);
assertThat(bean).isInstanceOf(RateDiscountPolicy.class);
}
@Test
@DisplayName("부모타입으로 모두 조회하기")
void findAllBeansByParentType(){
Map<String, DiscountPolicy> beansOfType = ac.getBeansOfType(DiscountPolicy.class);
assertThat(beansOfType.size()).isEqualTo(2);
for (String key : beansOfType.keySet()) {
System.out.println("key = " + key + "value = " + beansOfType.get(key));
}
}
@Test
@DisplayName("부모타입으로 모두 조회하기 - Object")
void findAllBeansByObjectType(){
Map<String,Object> beansOfType = ac.getBeansOfType(Object.class);
for (String key : beansOfType.keySet()) {
System.out.println("key = " + key + "value = " + beansOfType.get(key));
}
}
@Configuration
static class TestConfig{
@Bean
public DiscountPolicy rateDiscountPolicy(){
return new RateDiscountPolicy();
}
//
// @Bean 위의 처럼 하는 이뉴는 역할과 구현의 구분을 위해서! 할인 정책이구나를 쉽게 알려고 하는거다.
// public RateDiscountPolicy rateDiscountPolicy(){
// return new RateDiscountPolicy();
// }
@Bean
public DiscountPolicy fixDiscountPolicy(){
return new FixDiscountPolicy();
}
}//TestConfig
} // 클래스
Object 타입으로 조회하면 자바 객체는 모든게 object 타입이라서 스프링 빈에 등록되어 있는 모든 객체가 튀어 나온다.
빈 조회기능은 기본 기능이기도 해서 거의 쓸 일은 없다.
부모타입으로 조회할 때 자식이 어디 까지 조회되는지 알기 위해서~
BeanFactory와 ApplicationContext
beanfactory는 스프링컨테이너의 최상위 인터페이스
ApplicationContext는 beanFactory에서 부가 기능을 더한 것
1.메시지소스를 활용한 국제화 기능
예를 들어서 한국에서 들어오면 한국어로, 영어권에서 들어오면 영어로 출력
2.환경변수
로컬, 개발, 운영(실제 production에 나가는 것)등을 구분해서 처리
3.애플리케이션 이벤트
이벤트를 발행하고 구독하는 모델을 편리하게 지원
4.편리한 리소스 조회
파일, 클래스패스, 외부 등에서 리소스를 편리하게 조회
정리
ApplicationContext는 BeanFactory의 기능을 상속받는다.
ApplicationContext는 빈 관리기능 + 편리한 부가 기능을 제공한다.
BeanFactory를 직접 사용할 일은 거의 없다. 부가기능이 포함된 ApplicationContext를 사용한다.
BeanFactory나 ApplicationContext를 스프링 컨테이너라 한다.
다양한 설정 형식 지원 - 자바 코드, XML (가볍게)
스프링 컨테이너는 다양한 형식의 설정 정보를 받아드릴 수 있게 유연하게 설계되어 있다.
자바 코드, XML, Groovy 등등
애노테이션 기반 자바 코드 설정 사용
지금까지 했던 것이다.
new AnnotationConfigApplicationContext(AppConfig.class)
AnnotationConfigApplicationContext 클래스를 사용하면서 자바 코드로된 설정 정보를 넘기면 된다.
XML(문서) 설정 사용
최근에는 스프링 부트를 많이 사용하면서 XML기반의 설정은 잘 사용하지 않는다.
아직 많은 레거시 프로젝트 들이 XML로 되어 있고, 또 XML을 사용하면 컴파일 없이 빈 설정 정보를 변경할 수 있는 장점도 있으므로 한번쯤 배워두는 것도 괜찮다.
GenericXmlApplicationContext 를 사용하면서 xml 설정 파일을 넘기면 된다.
빈 등록하는 과정!
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://
www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="memberService" class="hello.core.member.MemberServiceImpl">
<constructor-arg name="memberRepository" ref="memberRepository" />
//생성자
</bean>
<bean id="memberRepository"
class="hello.core.member.MemoryMemberRepository" />
<bean id="orderService" class="hello.core.order.OrderServiceImpl">
<constructor-arg name="memberRepository" ref="memberRepository" />
<constructor-arg name="discountPolicy" ref="discountPolicy" />
</bean>
<bean id="discountPolicy" class="hello.core.discount.RateDiscountPolicy" />
</beans>
스프링 빈 설정 메타 정보 - BeanDefinition
스프링은 어떻게 이런 다양한 설정 형식을 지원하는 것일까? 그 중심에는 BeanDefinition 이라는 추상화가 있다.
쉽게 이야기해서 역할과 구현을 개념적으로 나눈 것이다!
XML을 읽어서 BeanDefinition을 만들면 된다.
자바 코드를 읽어서 BeanDefinition을 만들면 된다.
스프링 컨테이너는 자바 코드인지, XML인지 몰라도 된다. 오직 BeanDefinition만 알면 된다.
BeanDefinition을 직접 생성해서 스프링 컨테이너에 등록할 수 도 있다. 하지만 실무에서 BeanDefinition을
직접 정의하거나 사용할 일은 거의 없다. 어려우면 그냥 넘어가면 된다^^!
BeanDefinition에 대해서는 너무 깊이있게 이해하기 보다는, 스프링이 다양한 형태의 설정 정보를
BeanDefinition으로 추상화해서 사용하는 것 정도만 이해하면 된다.
'가랑비에 옷 젖는 줄 모른다 💻 > 스프링' 카테고리의 다른 글
[스프링기본편1]섹션 5 - 싱글톤 컨테이너 (0) | 2023.10.15 |
---|---|
[스프링기본1] 컨테이너에 등록된 모든 빈 조회 , 스프링 빈 기본 조회 (0) | 2023.10.13 |
[스프링기본편1] 객체 지향 원리 적용 (2) (1) | 2023.10.11 |
[스프링 핵심 원리 - 기본편] 객체 지향 원리 적용, AppConfig(DI) (0) | 2023.10.10 |
[스프링핵심원리-기본편] 스프링 핵심원리 이해1- 예제만들기 (0) | 2023.10.09 |