군만두의 IT 공부 일지

[스터디7] 01. 스프링 컨텍스트: 빈 정의 본문

프로그래밍/Java

[스터디7] 01. 스프링 컨텍스트: 빈 정의

mandus 2025. 4. 11. 21:02

 

 

 

 

 

  제목: 스프링 마스터

  저자: 로렌티우 스필카, 정성권 번역

  출판사: 길벗

  가격: 33,000원

 

 

기초부터 탄탄하게 배워서 바로 쓰는 스프링 입문

 

 

 

 

 

 

'이것이 자바다' 스터디가 끝나고, 이번에는 스프링 스터디를 진행하려고 한다. 해당 용어에 대해 부족한 점이 많은 것 같아, 여러 책들을 분석한 결과 적절한 구성의 책을 선정하였다.

2장. 스프링 컨텍스트: 빈 정의

이 장에서 다룰 내용
- 스프링 컨텍스트의 필요성 이해하기
- 스프링 컨텍스트에 새로운 객체 인스턴스 추가하기
  • 컨텍스트: 프레임워크가 관리할 모든 객체 인스턴스를 추가하는 앱의 메모리 공간
  • 스프링이 객체를 볼 수 있게 하려면 컨텍스트에 객체를 추가해야 한다.
  • 객체 인스턴스를 빈(Bean)이라고 한다.

2.1 메이븐 프로젝트 생성

  • 메이븐(Maven): 사용하는 프레임워크에 관계없이 앱의 빌드 프로세스를 쉽게 관리하는 데 사용하는 도구
  • 빌드 도구: 앱을 더 쉽게 빌드하는 데 사용하는 소프트웨어. 앱 빌드 일부인 작업을 수동으로 수행하는 대신 빌드 도구가 수행하도록 구성한다.
  • 앱 빌드에 포함되는 작업
    • 앱에 필요한 의존성 내려받기
    • 테스트 실행
    • 구문이 정의한 규칙 준수 여부 검증
    • 보안 취약점 확인
    • 앱 컴파일
    • 실행 가능한 아카이브에 앱 패키징
  • 먼저, 통합 개발 환경(Integrated Development Enviroment, IDE)가 필요하다. IntelliJ에서 File > New > Project를 선택하여 새 프로젝트를 생성한다.
    • 그룹 ID(Group ID): 관련된 여러 프로젝트를 그룹화하는 데 사용
    • 아티팩트 ID(Artifact ID): 현재 애플리케이션 이름
    • 버전(Version): 현재 구현 상태의 식별자

  • 프로젝트를 생성하면 다음 사항을 관찰할 수 있다.
    • src 폴더: 소스 폴더라고 하며, 앱에 속한 모든 것을 넣을 수 있다.
      • main 폴더: 애플리케이션의 소스 코드를 저장한다. 이 폴더에는 자바 코드와 구성 정보가 java 및 resources라는 두 하위 폴더에 개별적으로 포함된다.
      • test 폴더: 단위 테스트의 소스 코드를 저장한다.
    • pom.xml 파일: 새 종속성 추가처럼 메이븐 프로젝트 구성을 작성하는 파일이다. 모든 의존성은 <dependencies>와 </dependencies> 태그 사이에 작성한다.

2.2 스프링 컨텍스트에 새로운 빈 추가

  • 다음 방법으로 컨텍스트 빈을 추가할 수 있다.
    • @Bean 애너테이션 사용
    • 스테레오타입(stereotype) 애너테이션 사용
    • 프로그래밍 방식

메이븐 프로젝트를 생성하고 클래스를 정의한다. Parrot 클래스를 만들고, 이름을 나타내기 위해 String 속성을 추가한다.

package main;

public class Parrot {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

그리고 Parrot 클래스 인스턴스를 생성할 수 있는 main 메서드가 포함된 클래스를 정의한다.

package main;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {

    public static void main(String[] args) {
        var context = new AnnotationConfigApplicationContext();

        Parrot p = new Parrot();
    }
}

이제 프로젝트에 필요한 의존성을 추가한다.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>sq-ch2-ex1</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.1.6</version>
        </dependency>
    </dependencies>

</project>

2.2.1 @Bean 애너테이션을 사용하여 스프링 컨텍스트에 빈 추가

  • 스프링에서 빈을 추가하는 방법을 배우는 이유는 스프링이 빈 일부인 객체만 관리할 수 있기 때문이다.
  • @Bean 애너테이션을 사용하여 스프링 컨텍스트에 빈을 추가하는 단계
    1. 프로젝트 구성 클래스를 정의한다. 스프링의 컨텍스트를 구성하는 데 사용할 구성 클래스를 정의한다.
    2. 컨텍스트에 추가하려는 객체 인스턴스를 반환하는 메서드를 구성 클래스에 추가하고 @Bean 애너테이션으로 메서드에 주석을 추가한다.
    3. 스프링이 구성 클래스를 사용하게 한다. 구성 클래스를 사용하여 다양한 프레임워크 구성을 작성한다.
// 구성 클래스
package config;

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

@Configuration	// 이 클래스를 스프링 구성 클래스로 정의함
public class ProjectConfig {

    @Bean	// 스프링 컨텍스트가 초기화될 때 이 메서드를 호출하고 반환된 값을 컨텍스트에 추가하라고 지시함
    Parrot parrot() {
        var p = new Parrot();
        p.setName("Koko");
        return p;
    }

    @Bean
    String hello() {
        return "Hello";
    }

    @Bean
    Integer ten() {
        return 10;
    }
}
// 스프링 컨텍스트 초기화
package main;

import config.ProjectConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {

    public static void main(String[] args) {
        var context = new AnnotationConfigApplicationContext(ProjectConfig.class);	// 스프링 컨텍스트 인스턴스가 생성될 때 구성 클래스를 매개변수로 전송하여 스프링이 이를 사용하도록 지시함

        Parrot p = context.getBean(Parrot.class);	// 스프링 컨텍스트에서 Parrot 타입의 빈 참조를 가져옴

        System.out.println(p.getName());

        String s = context.getBean(String.class);

        System.out.println(s);

        Integer n = context.getBean(Integer.class);

        System.out.println(n);
    }
}
package main;

public class Parrot {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

2.2.2 스테레오타입 애너테이션으로 스프링 컨텍스트에 빈 추가

  • 스테레오타입 애너테이션을 사용하려면 스프링 컨텍스트에 추가해야 할 인스턴스의 클래스 위에 @Component 애너테이션을 추가해야 한다. 이 방식을 사용하려면 스테레오타입 애너테이션으로 지정된 클래스를 찾을 위치를 스프링에 알려주는 구성(configuration) 클래스가 필요하다.
  • 클래스를 컴포넌트로 표시하는 과정
    1. @Component 애너테이션으로 스프링이 해당 컨텍스트에 인스턴스를 추가할 클래스를 표시한다.
    2. 구성 클래스 위에 @ComponentScan 애너테이션으로 표시한 클래스를 어디에서 찾을 수 있는지 스프링에 지시한다.
package main;

import org.springframework.stereotype.Component;

@Component // 스프링은 이 클래스의 인스턴스를 생성하고 스프링 컨텍스트에 추가함
public class Parrot {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
package config;

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

@Configuration
@ComponentScan(basePackages = "main")	// 스프링에 스테레오타입 애너테이션이 지정된  클래스를 찾을 위치를 알려줌
public class ProjectConfig {

}
package main;

import config.ProjectConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {

    public static void main(String[] args) {
        var context = new AnnotationConfigApplicationContext(ProjectConfig.class);

        Parrot p = context.getBean(Parrot.class);

        System.out.println(p);
        System.out.println(p.getName());
    }
}

스프링 컨텍스트에 빈을 추가하는 두 가지 방법을 비교하면 다음과 같다.

@Bean 애너테이션 사용 스테레오타입 애너테이션 사용
1. 스프링 컨텍스트에 추가할 인스턴스의 생성을 완전히 제어할 수 있다. 스프링은 해당 인스턴스만 받아 컨텍스트에 그대로 추가한다.
2. 이 메서드를 사용하면 동일한 타입의 인스턴스를 스프링 컨텍스트에 더 추가할 수 있다.
3. @Bean 애너테이션을 사용하여 스프링 컨텍스트에 모든 객체 인스턴스를 추가할 수 있다.
3. 생성하는 각 빈에 대해 별도의 메서드를 작성해야 하므로 앱에 상용구 코드가 추가된다. 이런 이유로 프로젝트에서 @Bean을 사용하기보다는 스테레오타입 애너테이션을 선호한다.
1. 프레임워크가 인스턴스를 생성한 후에만 인스턴스를 제어할 수 있다.
2. 이렇게 하면 컨텍스트에 클래스의 인스턴스를 하나만 추가할 있다.
3. 스테레오타입 애너테이션은 애플리케이션이 소유한 클래스의 빈을 생성하는 데만 사용할 수 있다.
4. 스테레오타입 애너테이션을 사용하여 스프링 컨텍스트에 빈을 추가해도 앱에 상용구 코드가 추가되지 않는다.

2.2.3 프로그래밍 방식으로 스프링 컨텍스트에 빈 추가

스프링 5에서는 스프링 컨텍스트에 프로그래밍 방식으로 빈을 추가할 수 있다. 컨텍스트에 빈을 추가하는 사용자 재정의 방법을 요구하고 싶지만, @Bean 또는 스테레오타입 애너테이션 방식이 요구에 충족되지 않을 때 사용한다.

package main;

import config.ProjectConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.function.Supplier;

public class Main {

    public static void main(String[] args) {
        var context = new AnnotationConfigApplicationContext(ProjectConfig.class);

        Parrot x = new Parrot();
        x.setName("Kiki");

        Supplier<Parrot> parrotSupplier = () -> x;

        //context.registerBean("parrot1", Parrot.class, parrotSupplier);

        context.registerBean("parrot1",
                Parrot.class,
                parrotSupplier,
                bc -> bc.setPrimary(true));

        Parrot p = context.getBean(Parrot.class);

        System.out.println(p.getName());
    }
}
package main;

public class Parrot {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
package config;

import org.springframework.context.annotation.Configuration;

@Configuration
public class ProjectConfig {
}

 

이 글은 『스프링 교과서』 책을 학습한 내용을 정리한 것입니다.
Comments