티스토리 뷰

 

 

 

 

스프링 기본 개념을 정리해보고자 한다.

 

 

Udemy - Spring Boot 3 & Spring Framework 6 마스터하기! 강의 질문 캡처

 

 

 

Q1. Spring Container vs Spring Context vs IOC Container vs Application Context


  • Spring Container : 스프링 빈과 각 빈의 생명주기를 관리
    • Spring Container는 여러 이름으로 불려지는데 Spring Context, IOC Container
  • Spring Container 에는 2가지 종류가 있음.
    1. Bean Factory : 기본 Spring Container
    2. Application Context : 엔터프라이즈에 특화된 고급 Spring Container
      • 손쉬운 웹 애플리케이션 사용 지원
      • 손쉬운 국제화 지원
      • 손쉬운 Spring AOP와 통합 지원
    3. 많이 사용되는 컨테이너 : Application Context
      • 웹 어플리케이션, 웹서비스, REST API, Microservice에 사용
    4. 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가지 제약조건
    1. public no-arg constructor
    2. getter and setter
    3. 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)

}

 

 

 

 

 

 

 

 

 

 

 


 

 

이상 정리 끝!

 

 

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/07   »
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
글 보관함