Spring Boot 3 & Spring Framework 6 - section 1~2

TopOfTheHead·2024년 5월 30일

Spring FrameWork 개념

  • Tight Coupling : 구현한 class
  • Loose Coupling : 특정 class가 interface 같이 일반화된 구성요소에 의존 시 class 간의 Loose Coupling이 발생했다고 볼 수 있다.
  • Dependency Injection
  • IoC( Inversion Of Control ) Container
  • Application Context
  • Component Scan
  • Spring Beans
  • Auto Wiring ( 종속성 )

스프링 프로젝트 생성

  • https://start.spring.io/ 에서 생성하기

    주의사항 : SNAPSHOT 버전은 Spring Boot Team이 현재 개발하는 버전으로서 새로운것을 배울때 사용은 부적합.

Tightly Coupled Java Code 예제

// AppGamingBasicJava.java

package com.wjdtn747.springframework;

import com.wjdtn747.springframework.game.GameRunner;
import com.wjdtn747.springframework.game.MarioGame;

public class AppGamingBasicJava {
    public static void main(String[] args) {
        var marioGame = new MarioGame();
        var gameRunner = new GameRunner(marioGame);
        gameRunner.run();
    }
}
// GameRunner.java

package com.wjdtn747.springframework.game;

public class GameRunner {
    MarioGame game;
    public GameRunner(MarioGame game){
        this.game = game;
    }
    public void run(){
        System.out.printf("Running game:%s",game);

        game.up();
        game.down();
        game.left();
        game.right();
    }
}
// MarioGame.java

package com.wjdtn747.springframework.game;

public class MarioGame {
    public void up(){
        System.out.println("jump");
    }
    public void down(){
        System.out.println("go into a hole");
    }
    public void left(){
        System.out.println("go back");
    }
    public void right(){c
        System.out.println("go forward");
    }
}

각 MarioGame , GameRunner , AppGaingBasicJava class간에는 강한 결합으로 연결되어있음!

Loose Coupling - Interface 예제

// GamingConsole.java

package com.wjdtn747.springframework.game;

public interface GamingConsole {
    public void up();
    public void down();
    public void left();
    public void right();
}
// AppGamingBasicJava.java

package com.wjdtn747.springframework;

import com.wjdtn747.springframework.game.GameRunner;
import com.wjdtn747.springframework.game.MarioGame;
import com.wjdtn747.springframework.game.SuperContraGame;

public class AppGamingBasicJava {
    public static void main(String[] args) {
        var marioGame = new MarioGame();
        var scg = new SuperContraGame();
        var gameRunner1 = new GameRunner(scg);
        var gameRunner2 = new GameRunner(marioGame);
        gameRunner1.run();
        gameRunner2.run();
    }
}
// GameRunner.java

package com.wjdtn747.springframework.game;

public class GameRunner {
    GamingConsole game;
    public GameRunner(GamingConsole game){
        this.game = game;
    }
    public void run(){
        System.out.printf("Running game:%s",game);

        game.up();
        game.down();
        game.left();
        game.right();
    }
}
// MarioGame.java

package com.wjdtn747.springframework.game;

public class MarioGame implements GamingConsole {
    public void up(){
        System.out.println("jump");
    }
    public void down(){
        System.out.println("go into a hole");
    }
    public void left(){
        System.out.println("go back");
    }
    public void right(){
        System.out.println("go forward");
    }
}
// SuperContraGame.java
package com.wjdtn747.springframework.game;
public class SuperContraGame implements GamingConsole {
    public void up(){
        System.out.println("jump");
    }
    public void down(){
        System.out.println("sit down");
    }
    public void left(){
        System.out.println("go back");
    }
    public void right(){
        System.out.println("shoooooot");
    }
}

  • 각 class 간에는 interface를 활용해서 약한결합으로 연결되어있다.
  • 강한결합에서 약한결합 변환하는 과정이 필요!

결합(Coupling) :

  • 무언가를 변경 시 얼마나 많은 작업이 연관되어있는지에 대한 측도를 말한다
  • 양질의 프로그램을 구축하기 위해서 강한결합보다 약한결합일수록 좋다.

강한결합(Tight Coupling) : 예를 들어, AppGamingBasicJava class의 GameRunner() 생성자에는 매개변수로 MarioGame 객체만 들어갈 수 있고, 다른 객체의 경우 생성자에 활용되지 못함을 의미.
ex) 차량의 경우 엔진은 다른 엔진으로 함부로 교체를 못한다.
약한결합(Loose Coupling) : 예를 들어 생성자의 매개변수가 Interface인 경우 그 Interface를 상속하는 class 객체가 다 들어갈 수 있는것을 말함.
ex) 차량의 경우 타이어는 기본 규격만 같으면 교체가 가능하다.


사전지식 :

public class AppGamingBasicJava {
    public static void main(String[] args) {
        var gm = new MarioGame(); // 1: 객체생성
        var gameRunner1 = new GameRunner(gm);  
        // 2: 객체생성 + Dependencies(의존성)을 Wiring(종속)
        // ex ) gm 은 GameRunner의 Dependency임.
        gameRunner1.run();
    }
}

Spring Container
(= IoC Container, Spring Context )

  • Spring Bean과 Bean들의 Life Cycle을 관리
  • input : 일반 POJO 객체 또는 @Configuration으로 선언된 java를 input으로 받는다.
  • output : Spirng context를 제작하고 모든 Bean들을 관리하는 runtime system을 구축.
  • Web application , REST API , Spring AOP 등 대부분의 Spring Framework의 기능에서 주로 사용됨.

IoC Container 종류

  • Bean Factory :
    。기본적인 형식의 Spring Container.
    。현재는 사용하지 않는다.
  • Application Context :
    。Enterprise 기능이 존재하는 발전된 Spring Container

관련 기능 및 Annotation :

  • AnnotationConfigApplicationContext():
    。@Component로 선언된 class 또는 class 내 method가 @Bean으로 선언한 class로 부터 객체정보를 가져와서 Spring Context를 생성.
    。Spring Container를 생성하고 인자로 전달된 class를 기반으로 Spring Bean들을 등록.
  • @Configuration :
    。외부 라이브러리 혹은 내장 클래스를 Bean으로 등록 시 사용 ( 개발자가 직접 제어가 불가능 )
    。1개 이상의 @Bean을 제공하는 class는 반드시 @Configuration를 선언.

자바 객체

  • POJO( Plain Old Java Object ) :
    。특정 기술(ex . Framework)에 종속되어있지 않은 상태로 개발하는 개념을 위해 등장한 언어.
    。필드와 Getter ,Setter와 같은 기본 기능을 가지는 객체.
  • Java Bean :
    。반복작업을 효율적으로 수행하기위한 Java의 재사용가능한 Class.
    。POJO에 비해 더 많은 제약사항 존재.
    。EJB(Enterprise Java Bean)에 의해 영향을 받는다.
    。모든 field는 private로 구성되어있으며 getter & setter 로만 접근.
    。전달 인자가 없는 기본생성자(no-arg)만을 가지는 형태의 class.
    。Serialzable 이라는 interface 상속.
    // Java Bean 예시.
    class JavaBean implements Serializable {
        private int age;
        public JavaBean(){}
        public int getAge(){
            return this.age;
        }
        public void setAge(int a){
            this.age = a;
        }
    }
- **Spring Bean** : 
。Spring IoC Container가 관리하는 Java 객체. =Spring FrameWork에서 관리되는 모든것들은 전부 Spring Bean
。Spring에 의해 생성된 후 **Life Cycle(수명주기)**, **Dependencies(의존성)**이 관리되어짐.
。@Configuration으로 선언된 class 내부에 메소드를 @Bean으로 선언하여 Bean 생성.
。Spring Container인 Bean Factory 또는 Application Context에 의해 관리.

JVM(Java Virtual Machine)

  • Java bytecode를 실행하기위한 가상프로세서
  • 어느 플랫폼( CPU or OS ) 에서든 bytecode가 호환되게한다.

    bytecode는 JVM이 존재하는 플랫폼이면 전부 실행이 가능하다.
    ex ) java byte code(= compiled code) -> JVM -> Platfrom

이전까지는 JVM을 이용하여 객체를 생성하게 될 경우 사용자가 객체를 생성하고 결합 및 관리하는 코드를 직접 작성.
-> 수동으로 코딩하여 객체를 생성, 관리, 실행하는 대신 Spring FrameWork를 활용하여 자동으로 모두 관리하는 상태를 구축하고자함.

Java가 아닌 Spring 사용 시 이점

  • 여러개의 Bean을 정의 가능.
  • Spring에서 관리하는 객체를 검색할 수 있는 다양한 접근 방식을 제공.
  • Spring framework에서 관리하는 기존 Bean을 재활용 할 수 있음.
  • Bean에는 사용자가 지정한 이름을 설정 할 수 있다.
  • Bean을 class 이름의 type으로 호출하거나 , Bean의 이름으로 호출할 수 있다.
  • 기존 Bean을 활용해서 새로운 Bean을 구축할 수 있다.

Spring 활용 예제 #1

  • Spring context를 생성.
    AnnotationConfigApplicationContext() 활용.
  • Spring Framework에 의해 관리할 수 있도록함
    • @Configuration으로 생성한 Class를 정의하여 활용하고 @Bean으로 Spring Bean을 생성.
    • JVM 내에서 Spring이 특정객체 name , age , person , person2 , address 를 bean으로 관리!
// App02HelloWorldSpring.java
package com.wjdtn747.springframework;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class App02HelloWorldSpring {
    public static void main(String[] args) {
//        1. Spring context를 생성. -> AnnotationConfigApplicationContext 활용

//        2. Spring Framework가 관리할 수 있게끔 설정하기.
//           JVM내에 Spring Context 생성하기 위해 @configuration으로 미리 정의한 HelloWorldConfiguration class를 전달하여 새 instance를 생성.
//           이때 , 해당 class 내에는 data가 @Bean으로 정의되어있음.
        var context = new AnnotationConfigApplicationContext(HelloWorldConfiguration.class);
        // Spring Context 생성됨!

//        3. Spring Framework를 이용하여 Bean들을 참조하기.
        System.out.println(context.getBean("name")); // context.getBean("변수명") : Bean 을 호출.
        System.out.println(context.getBean("age"));
        System.out.println(context.getBean(Person.class)); // 문자열로 변수명을 쓰는거 말고도 class 로 호출이 가능.
        System.out.println(context.getBean("address2"));
    }
}
// HelloWorldConfiguration.java
package com.wjdtn747.springframework;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

// record 생성
record Person (String name , int age){};
record Address (String firstLine,String city){};
@Configuration
public class HelloWorldConfiguration {
    @Bean
    public Person person(){
        return new Person("김정수", 18);
    }
    @Bean
    public String name(){
        return "이정수";
    }
    @Bean
    public int age(){
        return 27;
    }
    @Bean(name = "address2")
    public Address address(){
        return new Address("봉산동","원주");
    }
}

@Configuration으로 미리 정의한 class
=> AnnotationConfigApplicationContext()에 전달하여 Spring Context 제작.

Record :

  • JDK 16에서 추가된 새로운 기능.
  • Java Bean을 제작 시 Getter , Setter , 생성자를 따로 정의하는 번거로움을 줄이기 위해서 제작!
    => 이들 메소드가 자동으로 생성됨.
// record 생성
record Person (String name , int age){};
@Configuration
public class HelloWorldConfiguration {
    @Bean
    public Person p(){
        var p = new Person("김정수", 18);
        System.out.println(p.age()); // get method도 사용 가능!
        return p; // return 을 통해 record에서 생성자가 자동으로 생성되어서 받는다!
    }

@Bean이 정의된 Bean의 이름 수정하기

@Bean(name = "address2")
public Address address(){
    return new Address("봉산동","원주");
기존 address 로 정의된 Bean의 이름이 address2로 변경됨.

기존 Spring Bean과 관계가 존재하는 새로운 Spring Bean 제작하는 방법

  • #1. 메소드 호출을 통해서 새로운 spring bean 구축.
@Bean
public Person person2MethodCall(){
    return new Person(name(),age(),address());
}
System.out.println(context.getBean("person2MethodCall"));

이 경우 Bean으로 정의된 name 과 age와 address를 활용해서 method를 제작!

  • #2. Parameter를 수정하여 spring Bean을 구축.
@Bean
public Person person3Parameters(String name , int age , Address address2){
    return new Person(name,age,address2);
}

person3Parameters 의 매개변수에 각 Bean들의 type과 명칭을 적고 이를 이용해 Person 객체를 제작 후 return.

@Component 와 @Configuration의 차이점?

  • @Component :
    。개발자가 직접 작성한 class를 Bean으로 등록할 때 사용
    。@Controller , @Service , @Repository : @Component에서 구체화 된 형태.
  • @Configuration :
    。외부 라이브러리 혹은 내장 클래스를 Bean으로 등록 시 사용 ( 개발자가 직접 제어가 불가능 )
    。1개 이상의 @Bean을 제공하는 class는 반드시 @Configuration 사용.
  • 두 Annotation은 큰 차이가 없음.
profile
공부기록 블로그

0개의 댓글