본문 바로가기
Everyday Study

2024.08.09 (금) { 싱글턴패턴, 애노테이션에서의 속성, registerSingleton, AnnotationConfigApplicationContext, 어노테이션 }

by xogns93 2024. 8. 11.

싱글턴 패턴 적용 단계

  1. 자기 자신을 참조하는 스태틱 필드를 선언하고 초기화:
    • 클래스 내부에서 자신의 인스턴스를 참조하는 정적(스태틱) 필드를 선언하고, 초기화합니다.
  2. 생성자를 프라이빗으로 변경:
    • 생성자를 private으로 선언하여, 외부에서 new 키워드를 통해 인스턴스를 생성하지 못하도록 막습니다.
  3. 외부에서 인스턴스에 접근할 수 있도록 스태틱 메서드 제공:
    • 인스턴스를 반환하는 정적 메서드를 정의합니다. 이 메서드를 통해 외부에서 유일한 인스턴스에 접근할 수 있습니다.
public class Singleton {
    // 1. 자기 자신을 참조하는 스태틱 필드를 선언하고 초기화
    private static final Singleton instance = new Singleton();

    // 2. 생성자를 프라이빗으로 변경하여 외부에서 인스턴스를 생성하지 못하게 함
    private Singleton() {
        // 추가적인 초기화 작업이 필요하면 여기에 작성
    }

    // 3. 외부에서 유일한 인스턴스에 접근할 수 있도록 스태틱 메서드 제공
    public static Singleton getInstance() {
        return instance;
    }

    // 싱글턴 클래스에서 제공하는 기능을 여기에 작성
    public void showMessage() {
        System.out.println("Hello, I am a Singleton!");
    }
}

@BeforeEach 애노테이션이 수행하는 작업은 테스트 픽스처(Test Fixture)를 설정하는 것

 

테스트 픽스처 (Test Fixture)란?

**테스트 픽스처(Test Fixture)**는 테스트를 실행하기 전에 필요한 객체들을 초기화하거나 상태를 설정하는 작업을 의미합니다. 즉, 테스트를 위한 "준비 작업"이라고 할 수 있습니다. 예를 들어, 테스트에서 사용할 객체를 생성하고, 이 객체들이 필요로 하는 초기 상태를 설정하는 등의 작업이 포함됩니다.

@BeforeEach와 테스트 픽스처

  • **@BeforeEach**는 JUnit 5에서 제공하는 애노테이션으로, 각 테스트 메서드가 실행되기 전에 실행되어야 할 메서드에 적용됩니다.
  • 이 애노테이션을 사용하여 정의된 메서드는 각 테스트 메서드가 실행되기 전에 호출되며, 이를 통해 테스트 메서드들이 동일한 초기 상태에서 시작되도록 보장할 수 있습니다.

예시 :

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;

class CalculatorTest {

    private Calculator calculator;

    @BeforeEach
    void setUp() {
        // 테스트 픽스처 설정: Calculator 객체 초기화
        calculator = new Calculator();
    }

    @Test
    void testAddition() {
        assertEquals(5, calculator.add(2, 3));
    }

    @Test
    void testSubtraction() {
        assertEquals(1, calculator.subtract(4, 3));
    }
}

@Component는 스프링 프레임워크에서 제공하는 애노테이션으로, 스프링 IoC 컨테이너에 의해 관리되는 빈(Bean)으로 등록될 클래스를 정의할 때 사용됩니다. 이 애노테이션을 클래스에 붙이면, 스프링이 해당 클래스를 자동으로 감지하여 인스턴스를 생성하고 관리합니다.

@Component의 주요 특징

  1. 빈 등록
    • @Component 애노테이션이 붙은 클래스는 스프링의 구성 요소(빈)로 등록됩니다. 스프링 IoC 컨테이너는 애플리케이션이 시작될 때 @Component가 붙은 클래스를 자동으로 스캔하고, 이를 빈으로 등록합니다.
    • 등록된 빈은 스프링 애플리케이션 전역에서 사용할 수 있습니다.
  2. 자동 탐지
    • @Component는 클래스패스를 스캔하는 과정에서 자동으로 탐지됩니다. 스프링 부트 애플리케이션에서는 일반적으로 @SpringBootApplication 애노테이션이 붙은 클래스의 패키지 및 그 하위 패키지를 스캔하여 @Component가 붙은 클래스를 찾습니다.
  3. 의존성 주입
    • @Component로 등록된 빈은 다른 빈에 의존성으로 주입될 수 있습니다. 스프링의 @Autowired 애노테이션이나 생성자 주입 등을 사용하여 @Component 빈을 주입할 수 있습니다.

 

@Autowired는 스프링 프레임워크에서 제공하는 애노테이션으로, 스프링의 IoC 컨테이너에 의해 관리되는 빈(Bean)들 사이의 의존성을 자동으로 주입하는 데 사용됩니다.

@Autowired의 역할

  • 의존성 주입(Dependency Injection): @Autowired는 스프링이 관리하는 빈을 자동으로 주입(Inject)하는 역할을 합니다. 즉, 특정 클래스의 필드, 생성자, 또는 메서드에 @Autowired 애노테이션을 붙이면, 스프링 IoC 컨테이너는 해당 타입의 빈을 찾아서 자동으로 주입합니다.
  • 자동으로 주입(Autowiring): 스프링은 @Autowired가 붙은 필드, 생성자, 또는 메서드에 대해 해당 타입의 빈을 자동으로 찾아 주입해 줍니다. 주입되는 빈이 여러 개일 경우, 스프링은 이름이나 특정한 주입 방법을 사용해 구체적으로 어떤 빈을 주입할지 결정할 수 있습니다.

3가지 주입방법 : 필드 주입, 생성자 주입, 메서드 주입

 

생성자 주입이 선호되는 중요한 이유 중 하나는 불변성을 보장할 수 있다는 점입니다.

  • 불변성(Immutable Object): 불변 객체는 생성된 이후 상태가 변경되지 않는 객체를 의미합니다. 생성자 주입을 통해 의존성을 주입하면, 객체가 생성된 이후에는 해당 의존성을 변경할 수 없게 만들 수 있습니다.

 


애노테이션에서의 속성

 

애노테이션에서도 속성이라는 개념이 존재합니다. 애노테이션을 정의할 때, 애노테이션에 포함된 요소들 속성이라고 부릅니다. 이러한 속성은 애노테이션을 사용할 때 값을 설정할 수 있습니다.

 

메서드인지 속성인지 헷갈리지 마라 !!!!

속성이 하나면 value라고 하고 생략가능

 

예를 들어

public @interface MyAnnotation {
    String value();  // 속성
    int number() default 0;  // 속성
}

이렇게 정의된 애노테이션을 사용할 때 속성에 값을 설정할 수 있습니다:

@MyAnnotation(value = "Hello", number = 5)
public class MyClass {
    // 클래스 내용
}

 

속성이 하나일 때 value 속성의 생략

애노테이션에서 속성이 하나이고 그 속성의 이름이 value인 경우, 애노테이션을 사용할 때 value를 생략할 수 있습니다. 예를 들어:

public @interface MyAnnotation {
    String value();
}

// 사용 예시
@MyAnnotation("Hello")
public class MyClass {
    // 클래스 내용
}

위의 경우 "Hello" value 속성에 자동으로 할당됩니다.

 


@interface

 

@interface는 **자바에서 애노테이션(Annotation)**을 정의할 때 사용하는 키워드입니다. 자바 애노테이션은 주석처럼 코드에 추가하는 메타데이터로, 컴파일러에게 추가적인 정보를 제공하거나 런타임 시에 특정 동작을 수행하도록 지시하는 데 사용됩니다.

 

애노테이션 정의하기

애노테이션은 @interface 키워드를 사용하여 정의됩니다. 여기서 @interface는 새로운 애노테이션을 선언하기 위한 자바 구문입니다. 애노테이션은 마치 인터페이스처럼 동작하지만, 실제로는 메서드가 아니라 속성을 정의합니다.

 

예시: 애노테이션 정의 및 사용

// 애노테이션 정의
public @interface MyAnnotation {
    String value();
    int number() default 0;  // 기본값 설정 가능
}

// 애노테이션 사용
@MyAnnotation(value = "Example", number = 10)
public class MyClass {
    // 클래스 내용
}

주요 개념

  1. 애노테이션 속성:
    • 애노테이션 내에서 정의된 메서드는 실제로는 속성(Property)을 정의하는 것입니다. 애노테이션을 사용할 때 이 속성에 값을 설정할 수 있습니다.
  2. 기본값:
    • 애노테이션 속성에는 기본값을 설정할 수 있습니다. 예를 들어, int number() default 0;은 number속성에 기본값으로 0을 설정합니다. 사용자가 이 속성에 값을 지정하지 않으면 기본값이 사용됩니다.
  3. value 속성:
    • 애노테이션에 value라는 이름의 속성이 있고, 다른 속성이 없거나 사용되지 않으면 value 속성의 이름을 생략할 수 있습니다. 예를 들어, @MyAnnotation("Example")은 @MyAnnotation(value = "Example")과 동일합니다.
  4. 메타 애노테이션:
    • 애노테이션을 다른 애노테이션에 적용할 수 있습니다. 이러한 애노테이션을 메타 애노테이션이라고 부릅니다. 예를 들어, @Retention, @Target, @Documented 등이 메타 애노테이션입니다.

registerSingleton

 

registerSingleton은 스프링 프레임워크에서 사용되는 메서드로, 스프링의 빈 팩토리(BeanFactory) 또는 **애플리케이션 컨텍스트(ApplicationContext)**에 **싱글턴 빈(Singleton Bean)**을 수동으로 등록하는 데 사용됩니다.

빈 등록하는데 쓰는 메서드

 

사용 시나리오

스프링에서는 일반적으로 XML 설정 파일, 자바 설정 클래스, 또는 컴포넌트 스캔을 통해 빈을 등록합니다. 하지만, 특정 경우에는 애플리케이션 실행 중에 프로그래밍 방식으로 빈을 등록해야 할 때가 있습니다. 이때 registerSingleton 메서드를 사용하여 직접 빈을 등록할 수 있습니다.

registerSingleton 사용 예시

스프링의 DefaultListableBeanFactory 클래스에서 제공하는 registerSingleton 메서드를 사용하여 싱글턴 빈을 등록하는 예시입니다:

import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.SimpleInstantiationStrategy;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class RegisterSingletonExample {

    public static void main(String[] args) {
        // 빈 팩토리 생성
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) context.getBeanFactory();

        // 싱글턴 인스턴스 생성
        MySingletonBean myBean = new MySingletonBean();

        // 싱글턴 빈 등록
        beanFactory.registerSingleton("mySingletonBean", myBean);

        // 컨텍스트 새로고침 (수동으로 빈을 등록한 후에는 컨텍스트를 새로고침해야 함)
        context.refresh();

        // 빈을 가져와서 사용
        MySingletonBean beanFromContext = (MySingletonBean) context.getBean("mySingletonBean");
        beanFromContext.doSomething();

        context.close();
    }
}

class MySingletonBean {
    public void doSomething() {
        System.out.println("Singleton Bean is doing something!");
    }
}

코드 설명

  1. DefaultListableBeanFactory 사용: DefaultListableBeanFactory는 스프링에서 가장 많이 사용되는 빈 팩토리 구현체 중 하나입니다. 이 팩토리는 수동으로 빈을 등록하고 관리할 수 있는 기능을 제공합니다.
  2. 싱글턴 인스턴스 생성: MySingletonBean 클래스의 인스턴스를 생성합니다.
  3. registerSingleton 메서드 호출: registerSingleton 메서드를 사용하여 빈 팩토리에 MySingletonBean 인스턴스를 싱글턴 빈으로 등록합니다. 첫 번째 매개변수는 빈의 이름이고, 두 번째 매개변수는 등록할 인스턴스입니다.
  4. 컨텍스트 새로고침: 프로그래밍 방식으로 빈을 등록한 후에는 context.refresh()를 호출하여 스프링 컨텍스트를 새로고침해야 합니다. 이렇게 해야 수동으로 등록된 빈이 컨텍스트에서 사용 가능해집니다.
  5. 빈 사용: 컨텍스트에서 mySingletonBean이라는 이름으로 등록된 빈을 가져와 사용합니다.

AnnotationConfigApplicationContext

 

AnnotationConfigApplicationContext는 스프링 프레임워크에서 Java 기반의 설정을 사용하여 애플리케이션 컨텍스트(ApplicationContext)를 구성하는 데 사용되는 클래스입니다. 스프링에서는 애플리케이션 컨텍스트가 빈(Bean)들을 관리하는 핵심 컨테이너 역할을 합니다.

AnnotationConfigApplicationContext는 XML 파일 대신 자바 클래스를 사용하여 스프링 설정을 구성할 수 있게 해줍니다. 이를 통해 더 유연하고 타입 안전한 방식으로 스프링 애플리케이션을 설정할 수 있습니다.

 

주요 기능 및 사용 방법

  1. Java 기반 설정 클래스 로드:
    • @Configuration 애노테이션이 붙은 자바 클래스를 로드하여, 해당 클래스에 정의된 빈들을 스프링 애플리케이션 컨텍스트에 등록합니다.
  2. 빈 등록:
    • @Bean 애노테이션을 사용하여 메서드 단위로 빈을 정의하고 등록할 수 있습니다.
    • @ComponentScan을 사용하여 특정 패키지를 스캔하고, 해당 패키지 내에 있는 @Component, @Service, @Repository, @Controller 애노테이션이 붙은 클래스를 자동으로 스프링 컨텍스트에 빈으로 등록할 수 있습니다.

@Configuration

1. 정의

@Configuration은 스프링에서 설정 클래스를 정의할 때 사용하는 애노테이션입니다. 이 애노테이션을 사용하면 해당 클래스가 하나 이상의 @Bean 메서드를 포함하고 있다는 것을 스프링에게 알립니다. 스프링 컨테이너는 @Configuration이 붙은 클래스를 스캔하고, 내부에 정의된 @Bean 메서드를 호출하여 애플리케이션 컨텍스트에 빈을 등록합니다.

2. 특징

  • @Configuration 클래스를 사용하면, 해당 클래스는 스프링 IoC 컨테이너에 의해 관리되는 설정 클래스가 됩니다.
  • 이 클래스는 전통적인 XML 설정 파일을 대체하며, 자바 코드를 통해 스프링 빈을 정의할 수 있습니다.
  • @Configuration 클래스 내부에 정의된 모든 @Bean 메서드는 스프링 컨테이너가 관리하는 빈을 반환합니다.

 

@Bean

1. 정의

@Bean 애노테이션은 메서드 수준에서 사용되며, 해당 메서드가 생성하고 반환하는 객체를 스프링 컨테이너에서 관리하는 빈으로 등록합니다. 이 메서드가 반환하는 객체는 스프링의 IoC 컨테이너에 의해 관리되며, 다른 빈에서 의존성 주입을 통해 사용할 수 있습니다.

2. 특징

  • @Bean 애노테이션이 붙은 메서드는 스프링 컨테이너에서 자동으로 호출되며, 메서드의 반환값은 빈으로 등록됩니다.
  • 메서드 이름이 빈의 이름이 됩니다. 필요하면 @Bean(name = "customBeanName")과 같이 이름을 지정할 수도 있습니다.
  • @Bean 메서드 내에서는 종종 다른 @Bean 메서드에서 생성된 빈을 참조하여 의존성을 주입할 수 있습니다.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean
    public MyService myService() {
        return new MyService(myRepository());
    }

    @Bean
    public MyRepository myRepository() {
        return new MyRepository();
    }
}