Spring Boot (4)

ysh·2023년 7월 21일
0

Spring Boot

목록 보기
38/53

Spring Bean

  • Spring IoC 컨테이너가 관리하는 자바 객체
  • 생성 방법만 명시하면 스프링이 알아서 객체를 생성하고 유지하고 소멸시킨다

Bean 등록

  • @Bean - 외부 라이브러리 객체
  • @Component - 내가 만든 객체
  • @Configuration - 설정
  • @Controller - 주소 매핑
  • @Service - 비지니스 로직
  • @Repository - DB, 데이터 소스

Bean 스캔 및 생성

  • @ComponentScan
    @ComponentScan 어노테이션이 붙은 패키지 하위의 모든 @Bean과 @Component를 스캔하여
    객체를 생성

제어 역전(IoC)

객체의 생성과 관리를 개발자가 아닌 프레임워크 또는 컨테이너가 담당하는 디자인 패턴

  • 개발자가 어떤 클래스를 사용하고 싶다면, 그 클래스가 필요로 하는 의존성들을 스프링 컨테이너에 알려주면 됨. 그러면 스프링 컨테이너가 필요한 의존성을 생성하고 객체를 관리

의존성 주입(DI)

객체가 필요로 하는 다른 객체를 직접 생성하는 것이 아니라, 외부에서 해당 객체를 주입하여 사용하는 것

  • @Autowired - 타입으로 주입 (없으면 이름으로)
  • @Inject - 타입으로 주입 (없으면 이름으로)
  • @Resource - 이름으로 주입 (없으면 타입으로)

디자인 패턴

싱글톤

클래스의 인스턴스를 하나만 생성하도록 보장하는 디자인 패턴

  • 어디서든 동일한 인스턴스 접근 가능, 자원의 낭비 방지
  • 설정값, 로깅, 데이터베이스 연결 등 전역적으로 사용되는 객체에 많이 사용

예시

public class AppConfig {
    private static AppConfig instance;

    private AppConfig() {} // private 생성자로 외부에서 인스턴스 생성 방지

    public static AppConfig getInstance() {
    	// 인스턴스가 없을 때만
        if (instance == null) {
        	// 생성
            instance = new AppConfig();
        }
        return instance;
    }
}

팩토리

객체 생성을 캡슐화하여 객체를 생성하는 방식을 유연하게 만드는 디자인 패턴

  • 인터페이스를 통해 객체를 요청하고, 팩토리는 요청에 맞는 객체를 생성하여 반환

예시

interface Shape {
    void draw();
}

class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("Drawing a circle.");
    }
}

class Square implements Shape {
    @Override
    public void draw() {
        System.out.println("Drawing a square.");
    }
}
// 팩토리 패턴을 이용해 Shape 인터페이스 구현
// createShape("(타입명)")을 통해 원하는 객체로 생성 후 반환
class ShapeFactory {
    public Shape createShape(String type) {
        if (type.equals("circle")) {
            return new Circle();
        } else if (type.equals("square")) {
            return new Square();
        } else {
            throw new IllegalArgumentException("Invalid shape type: " + type);
        }
    }
}

빌더

복잡한 객체의 생성 과정을 캡슐화하여 객체를 조립하는 방식을 제공하는 디자인 패턴

  • 객체의 생성과 속성 설정을 분리하여 가독성을 높이고, 다양한 옵션을 설정할 수 있게 함
  • 복잡한 생성자 대체, 코드의 가독성 높이기, 유지 보수를 용이하게 함

예시

class Car {
    private String brand;
    private String model;
    private String color;
    private int year;

    private Car(Builder builder) {
        this.brand = builder.brand;
        this.model = builder.model;
        this.color = builder.color;
        this.year = builder.year;
    }

    // Getter 메서드들...
    
    // Builder 클래스 정의
    static class Builder {
        private String brand;
        private String model;
        private String color;
        private int year;

        public Builder brand(String brand) {
            this.brand = brand;
            return this;
        }

        public Builder model(String model) {
            this.model = model;
            return this;
        }

        public Builder color(String color) {
            this.color = color;
            return this;
        }

        public Builder year(int year) {
            this.year = year;
            return this;
        }

        public Car build() {
            return new Car(this);
        }
    }
}

public class Main {
    public static void main(String[] args) {
        // 빌더 패턴으로 Car 객체 생성
        Car car = new Car.Builder()
                .brand("Toyota")
                .model("Corolla")
                .color("Blue")
                .year(2022)
                .build();

        // 생성된 Car 객체의 정보 출력
        System.out.println(car.getBrand());
        System.out.println(car.getModel());
        System.out.println(car.getColor());
        System.out.println(car.getYear());
    }
}

프록시

다른 객체에 대한 대리자 역할을 하는 객체를 제공하여 접근을 제어하는 디자인 패턴

  • 원래 객체에 대한 접근을 제어하거나 보조 작업을 수행하고, 필요한 경우에만 원래 객체를 생성

예시

: display() 메서드를 호출할 때, 실제로 이미지를 로드하는 것이 아니라 프록시를 통해 이미지를 로드하여 필요한 경우에만 RealImage를 생성하고 display() 메서드를 호출

interface Image {
    void display();
}

class RealImage implements Image {
    private String filename;

    public RealImage(String filename) {
        this.filename = filename;
        loadImageFromDisk();
    }

    private void loadImageFromDisk() {
        System.out.println("Loading " + filename);
    }

    @Override
    public void display() {
        System.out.println("Displaying " + filename);
    }
}

class ProxyImage implements Image {
    private RealImage realImage;
    private String filename;

    public ProxyImage(String filename) {
        this.filename = filename;
    }

    @Override
    public void display() {
        if (realImage == null) {
            realImage = new RealImage(filename);
        }
        realImage.display();
    }
}
profile
유승한

1개의 댓글

comment-user-thumbnail
2023년 7월 21일

잘 읽었습니다. 좋은 정보 감사드립니다.

답글 달기