티스토리 뷰
반응형
스프링 기본 개념을 정리해보고자 한다.
Q1. Spring Container vs Spring Context vs IOC Container vs Application Context
- Spring Container : 스프링 빈과 각 빈의 생명주기를 관리
- Spring Container는 여러 이름으로 불려지는데 Spring Context, IOC Container
- Spring Container 에는 2가지 종류가 있음.
- Bean Factory : 기본 Spring Container
- Application Context : 엔터프라이즈에 특화된 고급 Spring Container
- 손쉬운 웹 애플리케이션 사용 지원
- 손쉬운 국제화 지원
- 손쉬운 Spring AOP와 통합 지원
- 많이 사용되는 컨테이너 : Application Context
- 웹 어플리케이션, 웹서비스, REST API, Microservice에 사용
- Bean Factory : 메모리에 한정적인 IOT 애플리케이션에 주로 사용
Q2. Java Bean vs Spring Bean vs POJO
Java Bean | POJO(Plain Old Java Object) | Spring Bean |
3가지 제약조건 * public no-args constructor * getter & setter * implement java.io.Serializable |
* 생성자 없어도 무관 * 모든 자바 Object는 POJO!! |
*IoC Container(Bean Factory or Application Context)가 관리하는 모든 Java 객체 |
1) POJO(Plain Old Java Object)
// POJO(Plain Old Java Object) : 모든 Java 객체는 POJO
class Pojo {
private String text;
private int number;
public String toString() {
return "Pojo{" +
"text='" + text + '\'' +
", number=" + number +
'}';
}
}
2) Java Bean
- EJB(Enterprise Java Bean) : 15년 전 가장 인기 있는 접근 방식, Java 어플리케이션 구현하는 아키텍처 중 하나
- EJB은 JavaBean이라는 개념을 도입
- Java Bean의 3가지 제약조건
- public no-arg constructor
- getter and setter
- Serializable 상속 및 구현
- Java Bean 개념은 더 이상 중요하지 않음. Enterprise Java Bean 사용률 저하!
class JavaBean implements Serializable { // 3. Serializable 인터페이스 상속 및 구현
// 1. public No argument Constructor
public JavaBean(){
}
// 2. getter and setter
public String getText() {
return text;
}
public int getNumber() {
return number;
}
public void setText(String text) {
this.text = text;
}
public void setNumber(int number) {
this.number = number;
}
private String text;
private int number;
}
Q3. How can I list all beans managed by Spring Framework?
(스프링 프레임워크가 관리하는 모든 Bean을 나열하려면?)
package com.in28miniutes.learnspringframework;
import java.util.Arrays;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@SpringBootApplication
public class App02HelloWorldSpring {
public static void main(String[] args) {
SpringApplication.run(App02HelloWorldSpring.class, args);
// Spring Context 생성 : @Configuration 을 선언한 클래스르 파라미터로 입력받아 생성
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
HelloWorldConfiguration.class);
// context.getBeanDefinitionNames() 를 이용해 IoC Container에 있는 빈 출력!
Arrays.stream(context.getBeanDefinitionNames()).forEach(System.out::println);
}
}
* 출력 결과
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
helloWorldConfiguration
name
age
person
person2
address2
person2MethodCall
person3MethodCall
Q4. What if multiple matching beans available?
(여러 개의 매칭되는 Bean을 사용하려면?) : Use the annotaions of @Primary, @Qualifier
- 아래 @Configuration class를 보면 Address 클래스를 기준 2개의 각기 다른 이름으로 @Bean을 등록했습니다.
package com.in28miniutes.learnspringframework;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
// record : JDK 16에 추가된 기능, Java Bean을 쉽게 생성(Incl. getter, setter, constructer)
record Address(String firstLine, String city) { };
@Configuration // @Configuration : Spring 설정 클래스 선언 어노테이션
public class HelloWorldConfiguration {
@Bean
public Address address(){
return new Address("Baker Street", "London");
}
@Bean("address3")
public Address address3(){
return new Address("olympic-ro", "Seoul");
}
}
- AnnotaionConfigApplicationContext 를 이용해 IoC Container에 있는 Bean을 출력할 때, NoUniqueBeanDefinitionException 이 발생합니다.
- 원인 : context.getBean(Address.class) 와 같이 class로 Bean을 찾을 경우 Address 클리스로 생성된 모든 인스턴스를 찾기 때문에 에러가 발생합니다.
- 현재 Address.class로 생성된 Bean은 2개 (address, address3)
NoUniqueBeanDefinitionException : No qualifying bean of type 'com.in28miniutes.learnspringframework.Address' available: expected single matching bean but found 2: address,address3
NoUniqueBeanDefinitionException: 적절한 'Address'타입이 없음
: 단일 매칭 Bean을 기대했으나 2개를 발견
package com.in28miniutes.learnspringframework;
import java.util.Arrays;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@SpringBootApplication
public class App02HelloWorldSpring {
public static void main(String[] args) {
SpringApplication.run(App02HelloWorldSpring.class, args);
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(HelloWorldConfiguration.class);
// 메서드명으로 Bean 출력
System.out.println(context.getBean("address3"));
// Address.class로 Bean 출력
System.out.println(context.getBean(Address.class));
}
}
// Exception 발생
Exception in thread "main" org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.in28miniutes.learnspringframework.Address' available: expected single matching bean but found 2: address,address3
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1299)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveBean(DefaultListableBeanFactory.java:484)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:339)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:332)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1184)
at com.in28miniutes.learnspringframework.App02HelloWorldSpring.main(App02HelloWorldSpring.java:18)
해결방법은 @Primary & @Qualifier
1) @Primary : Bean의 우선순위를 주어 getBean(Address.class) 호출 시 해당 Bean을 출력!
@Configuration // @Configuration : Spring 설정 클래스 선언 어노테이션
public class HelloWorldConfiguration {
@Bean("address2")
@Primary
public Address address(){
return new Address("Baker Street", "London");
}
@Bean("address3")
@Qualifier
public Address address3(){
return new Address("olympic-ro", "Seoul");
}
}
// 출력 결과
Address[firstLine=olympic-ro, city=Seoul]
Address[firstLine=Baker Street, city=London]
2) @Qualifier : IoC Container에 등록된 여러 Bean 중 구분할 수 있는 추가 정보제공(한정자 제공)
// record : JDK 16에 추가된 기능, Java Bean을 쉽게 생성(Incl. getter, setter, constructer)
record Address(String firstLine, String city) { };
record Person(String name, int age, Address address) { };
@Configuration // @Configuration : Spring 설정 클래스 선언 어노테이션
public class HelloWorldConfiguration {
@Bean
public String name(){
return "gomshiki";
}
@Bean
public int age(){
return 29;
}
@Bean
public Person person(String name, int age, @Qualifier("address3Qualifer") Address address) {
return new Person(name, age, address);
}
@Bean("address2")
@Primary
public Address address(){
return new Address("Baker Street", "London");
}
@Bean("address3")
@Qualifier("address3Qualifer")
public Address address3(){
return new Address("olympic-ro", "Seoul");
}
}
// 출력 결과 : address3 Bean을 사용!!!
Person[name=gomshiki, age=29, address=Address[firstLine=olympic-ro, city=Seoul]]
Q5. Spring is managing objects and performing auto-wiring.
( 스프링은 object를 관리하고 자동 주입해줍니다. )
- BUT aren't we writing the code to create objects? 하지만 object를 생성하려고 직접 코드를 작성하지 않았나요?
- How do we get Spring to create objects for us? 스프링으로 객체를 어떻게 생성할 수 있을 까요?
1) 기존 설정
그동안 클래스에 @Configuration 적용, Object 생성 메서드 작성 @Bean 적용을 통해 IoC 컨테이너에 등록해왔습니다.
- 등록된 Spring Bean은 AnnotaionConfigApplicationContext.getBean(class or "Name of Bean") 을 통해 불러왔죠.
@Configuration
public class GamingConfiguration {
@Bean
public GamingConsole game(){
return new PacmanGame();
}
@Bean
public GameRunner gameRunner(GamingConsole game){ // 위 game 메서드 호출
return new GameRunner(game);
}
}
@Configuration
public class GamingAppLauncherApplication {
public static void main(String[] args) {
try(
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
GamingAppLauncherApplication.class);
)
{
context.getBean(GamingConsole.class).up();
context.getBean(GameRunner.class).run();
}
}
}
2) @ComponentScan 을 이용하여 Spring이 Object 생성해 Bean을 생성하도록 코드 개선
- Spring Bean 생성을 위해 해당하는 클래스에 @Component 적용 : GameRunner, PacmanGame 클래스
* @Component : 이 어노테이션이 적용되면 @Configuration과 Classpath 스캔 시, 자동을 객체를 생성하고, Bean으로 등록
- @ComponentScan : 이 어노테이션을 이용해 @Component 스캔 대상 경로를 지정해줘야 Spring 이 @Component 인식함.
package com.in28miniutes.learnspringframework;
import com.in28miniutes.learnspringframework.game.GameRunner;
import com.in28miniutes.learnspringframework.game.GamingConsole;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
// Spring이 Spring bean을 찾을 수 있게 특정 패키지 경로를 알려줘야함.
//
@Configuration
@ComponentScan("com.in28miniutes.learnspringframework.game")
public class GamingAppLauncherApplication {
public static void main(String[] args) {
try(
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
GamingAppLauncherApplication.class);
)
{
context.getBean(GamingConsole.class).up();
context.getBean(GameRunner.class).run();
}
}
}
package com.in28miniutes.learnspringframework.game;
import org.springframework.stereotype.Component;
@Component
public class GameRunner {
private GamingConsole game;
public GameRunner(GamingConsole game) {
this.game = game;
}
public void run() {
System.out.println("Running game: " + game);
game.up();
game.down();
game.left();
game.right();
}
}
package com.in28miniutes.learnspringframework.game;
import org.springframework.stereotype.Component;
@Component
public class PacmanGame implements GamingConsole {
public void up() {
System.out.println("up");
}
public void down(){
System.out.println("down");
}
public void left() {
System.out.println("left");
}
public void right() {
System.out.println("right");
}
}
3) 비교 Table
직접 객체 생성 및 Bean 등록 | Spring 객체 생성 및 Bean 등록 |
@Configuration public class GamingConfiguration { @Bean public GamingConsole game(){ return new PacmanGame(); } @Bean public GameRunner gameRunner(GamingConsole game) { return new GameRunner(game); } } |
@Component public class PacmanGame implements GamingConsole { public void up(){ System.out.println("up"); } } |
@Component public class GameRunner { private GamingConsole game; public GameRunner(GamingConsole game) { this.game = game; } } |
|
public class App03GamingSpringBeans{ AnnotaionConfigApplicationContext context = new AnnotaionConfigApplicationContext(등록된 빈.class) } |
@Configuration @ComponentScan("GameRunner, GameRunner 의 패키지 경로") public class App03GamingSpringBeans{ AnnotaionConfigApplicationContext context = new AnnotaionConfigApplicationContext(등록된 빈.class) } |
이상 정리 끝!
반응형
'프레임워크 > Spring & Spring boot' 카테고리의 다른 글
[학습테스트로 배우는 Spring] 코드리뷰 (feat. Entity와 Dto 의존관계, 자료구조) (0) | 2024.06.14 |
---|---|
[SpringJDBC] JDBC를 이용한 데이터베이스 ACID 개념 살펴보기 (0) | 2024.04.28 |
Spring Security 와 JWT를 이용한 로그인 구현기(feat. Flutter) (0) | 2024.03.17 |
[Spring Security] Let's dig into the Security World (0) | 2024.03.13 |
Spring Framework의 배경지식 (0) | 2022.12.02 |
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- 항해99
- 챗봇
- RASA
- 취업리부트코스
- 자바
- 백준
- 유데미
- 나만의챗봇
- 전자정부프레임워크
- 취리코
- NLU
- 글또
- thymeleaf
- JWT
- 개발자취준
- 재기동
- dxdy
- BufferedReader
- BufferedWriter
- script
- Spring
- Java
- 회고록
- Comparator
- BFS
- springboot
- Comparable
- 객체정렬
- 코딩테스트
- 코드트리
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
글 보관함
반응형