Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- Inverted Page Table
- 알고리즘
- 웹개발
- springboot
- 2단계 Page Table
- jpa
- Segmentation with Paging
- 리눅스
- 메모리의 불연속적 할당
- 자바 알고리즘
- 프로세스 할당
- annotation
- linux
- 웹 프로그래밍
- spring
- 운영체제
- 메모리 관리
- 문제풀이
- 스프링부트
- Allocation of Physical Memory
- CS
- 프로세스 동기화
- Page Table의 구현
- 스프링
- Shared Page
- 프로세스 불연속 할당
- 다단계 페이지 테이블
- 자바 문제풀이
- 코드스테이츠 백엔드 과정 39기
- Effective Access Time
Archives
- Today
- Total
GrowMe
[Spring]DI를 코드 + a로 쉽게 이해해보자 본문
DI(Dependency Injection)
# DI
# 스프링 컨테이너
# 빈 컨테이너
# 의존성 주입
# Component
# Bean
# 빈 등록법
# 빈 조회법
*DI란?
- 의존성 주입(Dependency Injection) : 사용할 객체를 외부에서 주입받는 것
- 기존처럼
new 연산자로 객체를 새로 생성하는 것이 아닌, 미리 만들어둔 객체를 불러오는 것!
*외부 어디에서 불러오는데?? : Spring Container
📦Spring Container의 종류(1) : BeanFactory
- 스프링 컨테이너의 최상위 인터페이스
- BeanFactory는 빈을 등록하고 생성하고 조회하고 돌려주는 등 빈을 관리하는 역할을 합니다.
- getBean() 메소드를 통해 빈을 인스턴스화할 수 있습니다.
📦Spring Container의 종류(2) : ApplicationContext
- BeanFactory를 상속받아 기능을 확장하여 제공합니다.
- 부가 기능(참고)
- MessageSource: 메세지 다국화를 위한 인터페이스
- EnvironmentCapable: 개발, 운영 등 환경변수 등으로 나눠 처리하고, 애플리케이션 구동 시 필요한 정보들을 관리하기 위한 인터페이스
- ApplicationEventPublisher: 이벤트 관련 기능을 제공하는 인터페이스
- ResourceLoader: 파일, 클래스 패스, 외부 등 리소스를 편리하게 조회
📦컨테이너를 인스턴스화하여 사용하기
1. AnnotationConfigApplicationContext (Annotation)
public static void main(String[] args) {
// 빈이 등록된 컨테이너를 인스턴스화하여 사용할 준비시키기!
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
// 등록된 빈을 가져와 담기
MyService myService = ctx.getBean(MyService.class);
// 빈을 사용하기(내부 메서드)
myService.doStuff();
}
2. ClassPathXmlApplicationContext (XML)
// 빈이 등록된 컨테이너를 인스턴스화하여 사용할 준비시키기!
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
// 등록된 빈을 가져오기
PetStoreService service = context.getBean("cmarket", cmarketService.class);
// 객체의 이름만 따로 저장하기
List<String> userList = service.getUsernameList();
*Bean이 뭔데? : 사용할 객체(미리 등록되있는)
- Spring 컨테이너가 관리하는 자바 객체(인스턴스화된 객체를 의미)
- 스프링 컨테이너에 등록된 객체 = Spring Bean
- 빈은 클래스의 등록정보, getter/setter 메서드 등의 정보를 포함한다.
*Bean은 그럼 어떻게 등록하면 될까?
implementation('org.springframework.boot:spring-boot-starter-web')
- 먼저 build.gradle 파일에 위 의존성을 추가해준다. -> 관련 라이브러리들이 자동으로 받아진다.
1. 원초적 방법(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="bookService"
class="me.wordbe.springgoahead.BookService">
<property name="bookRepository" ref="bookRepository" />
</bean>
<bean id="bookRepository"
class="me.wordbe.springgoahead.BookRepository" />
</beans>
- xml 설정 파일에 등록할 객체의 클래스를 각각 빈으로 등록한다.
- 사용할 장소(bookService)의 특성(property)의 참조로 사용할 객체(boorRepository)를 등록한다.
- bookService 클래스에서 boorRepository를 선언할 경우, 여기 등록된 boorRepository 객체가 불러와져 주입이 된다.
2. Spring 2.5 버전 (Component-scan 기능 추가)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="me.wordbe.springgoahead" />
</beans>
패키지의 각각 클래스에 어노테이션을 붙여서 빈을 등록한다.
import org.springframework.stereotype.Repository;
@Component
public class BookRepository {
}
@Component
public class BookService {
@Autowired
BookRepository bookRepository;
public void setBookRepository(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
}
- xml에 등록된 <context:component-scan base-package= 패키지경로>의 하위 클래스들 중, @Component가 붙은 클래스들을 모두 스캔하여 빈에 자동등록 시켜준다.
3. Java 기반 컨테이너 설정
사용할 클래스들과 같은 패키지에 설정파일(java)을 만든다.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ApplicationConfig {
@Bean
public BookRepository bookRepository() {
return new BookRepository();
}
@Bean
public BookService bookService(BookRepository bookRepository) {
BookService bookService = new BookService();
// 의존성 주입 setter 이용
bookService.setBookRepository(bookRepository);
return bookService;
}
}
- @Configuration : 빈 설정 클래스라는 것을 명시한다. 이 클래스는 컨테이너에서 불러와 사용될 수 있다.
- @Bean : 이 어노테이션이 붙은 메서드의 메서드명을 이름으로 하여 객체를 빈으로 등록한다.
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);
BookService bookService = context.getBean(BookService.class);
bookService.doStuff();
}
}
}
- ApplicationContext를 구현한 객체인 AnnotationConfigApplicationContext를 통해 설정해주었던, 빈 설정 클래스(ApplicationConfig)를 등록해주어 컨테이너를 생성해 사용할 수 있다.
- doStuff()는 BookService 클래스의 내부 메서드
4. 자바 Config, ComponentScan 활용
- 3번에서는 Config파일에 사용할 클래스들을 모두 @Bean을 통해 일일이 등록해야 했다.
- 이를 해결하기 위한 방법 : ComponentScan 활용하기
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackageClasses = SpringApplication.class) // 최상단 메인 클래스
public class ApplicationConfig {
}
- @ComponentScan : 2번에서 설명한 ComponentScan을 xml 설정파일에 추가한 것과 동일한 기능을 제공한다.
-> basePackageClasses로 메인 클래스를 지정해주면, 동일 패키지 및 그 하위 패키지에 @Component가 붙은 클래스 Or @Bean이 붙은 메서드들을 자동으로 스캔해주고, 등록해준다. - @Bean은 메서드 단위로, @Component는 클래스 단위로 스캔되며 통상 두 방식 중 하나만 사용한다.
5. @SpringBootApplication
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
- @SpringBootApplication 내부에는 @ComponentScan 과 @Configuration이 포함되어 있다. 즉, @SpringBootApplication와 같은 경로의 패키지 or 그 하위 패키지의 빈들을 찾아서 스캔하고 등록하여준다.
*Bean을 조회하는 방법
import hello.core.AppConfig;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
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.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
public class ApplicationContextBasicFindFirst {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
@Test
@DisplayName("빈 이름으로 조회")
void findBeanByName() {
MemberService memberService = ac.getBean("memberService", MemberService.class);
assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
@Test
@DisplayName("빈을 타입으로만 조회")
void findBeanByType() {
MemberService memberService = ac.getBean(MemberService.class);
assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
@Test
@DisplayName("동일한 타입이 둘 이상인 스프링 빈을 타입으로 조회할 빈 이름을 지정한다.")
void findBeanByName() {
DiscountPolicy discountPolicy = ac.getBean("fixDiscountPolicy", DiscountPolicy.class);
assertThat(discountPolicy).isInstanceOf(FixDiscountPolicy.class);
}
@Test
@DisplayName("특정 타입을 모두 조회한다.")
void findAllBeanType() {
Map<String, DiscountPolicy> beansOfType = ac.getBeansOfType(DiscountPolicy.class);
for (String key : beansOfType.keySet()) {
System.out.println("key = " + key + "value = "+ beansOfType.get(key));
}
System.out.println("beansOfType = " + beansOfType);
assertThat(beansOfType).hasSize(2);
}
}
- 빈 이름으로 조회
- 빈 타입으로 조회
- 동일한 타입이 둘 이상의 빈은?? : 이름으로 부르거나, 타입들 모두 부르거나
'About Spring' 카테고리의 다른 글
[Spring] Mapper와 MapStruct에 대해 알아보자 (0) | 2022.06.28 |
---|---|
[Spring] DTO의 개념과 그 활용 방법 (0) | 2022.06.27 |
[Spring]AOP를 코드 + a 로 쉽게 이해해보자 (0) | 2022.06.21 |
SpringBoot 주요 애너테이션과 메서드 및 주의사항(지속 업데이트 중) (0) | 2022.06.19 |
[Spring 설정]Mybatis와 SqlSessionTemplate (2) | 2022.06.12 |
Comments