BackEnd/spring

SpringBean

연향동큰손 2025. 2. 11. 17:39

 

스프링 빈이란 스프링 컨테이너에 의해 관리되는 재사용 가능한 소프트웨어 컴포넌트이다.

즉, 스프링 컨테이너가 관리하는 자바 객체를 뜻하며, 하나 이상의 빈(Bean)을 관리한다.

 

 

스프링 빈(Bean)의 필요성

 

스프링빈을 사용하는 이유는 크게 객체 관리의 효율성, 의존성 주입(DI), 객체의 생명주기 관리, 애플리케이션의 유지보수성 향상 때문이다.

 

1. 객체 생성을 자동으로 관리해준다.

 

스프링을 사용하지 않은 경우

public class Main {
    public static void main(String[] args) {
        MyService myService = new MyService();
        System.out.println(myService.getMessage());
    }
}

class MyService {
    public String getMessage() {
        return "Hello, world!";
    }
}

 

위 코드는 MyService객체를 사용할때 new MyService()를 통해 객체를 직접 생성해야 한다.

 

이는 객체가 많아질수록 코드가 복잡해지고, 관리가 어려워질 수 있다.

 

 

 

스프링빈을 사용한 경우

import org.springframework.stereotype.Service;

@Service
public class MyService {
    public String getMessage() {
        return "Hello, Spring Bean!";
    }
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MyComponent {
    private final MyService myService;

    @Autowired
    public MyComponent(MyService myService) {
        this.myService = myService;
    }

    public void printMessage() {
        System.out.println(myService.getMessage());
    }
}

 

@Service를 붙여서 MyService객체가 스프링 컨테이너에 자동으로 생성되고 관리된다.

 

@Autowired를 이용해 스프링이 MyService 객체를 자동으로 주입해주기 때문에, 직접 객체를 생성하지 않아도 되고 코드가 간결해진다.

 

 

 

2. 싱글톤 패턴 적용으로 메모리 효율 향상

 

스프링 빈은 기본적으로 싱글톤(Singleton)으로 관리된다!!

✔️ 싱글톤패턴(Singleton Pattern) 이란?
객체의 인스턴스가 오직 1개만 생성되는 패턴
생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 하나이며 이후에 호출된 생성자는 최초의 생성자가 객체를 리턴하는 것

 

 

스프링을 사용하지 않은 경우

public class Main {
    public static void main(String[] args) {
        MyService service1 = new MyService();
        MyService service2 = new MyService();

        System.out.println(service1);
        System.out.println(service2);
    }
}

 

위 코드를 보면 service1과 service2는 서로 다른 객체로 생성되어 메모리가 불필요하게 낭비된다.

 

 

스프링 빈을 사용한 경우(싱글톤 적용)

import org.springframework.stereotype.Service;

@Service
public class MyService {
    public MyService() {
        System.out.println("MyService 객체 생성!");
    }
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MyComponent {
    private final MyService myService1;
    private final MyService myService2;

    @Autowired
    public MyComponent(MyService myService1, MyService myService2) {
        this.myService1 = myService1;
        this.myService2 = myService2;
    }

    public void checkSingleton() {
        System.out.println(myService1);
        System.out.println(myService2);
    }
}

 

<출력 결과>

MyService 객체 생성!
com.example.MyService@5a07e868
com.example.MyService@5a07e868

 

위 결과를 보면 스프링 빈을 통해 객체가 한번만 생성되고, 여러 곳에서 동일한 객체를 공유하는 것을 확인할 수 있다.

 

따라서 메모리 사용이 효율적이고, 객체 관리가 쉬워진다.

 

 

 

3.의존성 주입(DI)으로 결합도 낮추기

 

 

스프링을 사용하지 않는 경우

public class MyComponent {
    private MyService myService;

    public MyComponent() {
        this.myService = new MyService(); // 직접 객체 생성
    }

    public void printMessage() {
        System.out.println(myService.getMessage());
    }
}

 

위 코드를 보면 MyComponent가 MyService의 객체를 직접 생성하여 두 객체가 강하게 결합되어 있다.

 

따라서 MyService의 구현이 변경되면 MyComponent도 수정해야된다.

 

 

스프링 빈을 사용한 경우

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MyComponent {
    private final MyService myService;

    @Autowired
    public MyComponent(MyService myService) {
        this.myService = myService; // 스프링이 자동 주입
    }

    public void printMessage() {
        System.out.println(myService.getMessage());
    }
}

 

위 코드처럼 해주면 MyCompoent는 MyService의 객체를 직접 생성하지않고, 스프링이 알아서 주입 해주기 때문에 

코드의 결합도가 낮아지며 유지보수가 쉬워진다.

 

 

 

4. 객체의 생명주기 관리

 

스프링 빈은 객체의 생성부터 소멸까지의 생명주기를 관리해주고, 이에 필요한 애노테이션을 제공한다.

  • @PostConstruct : 초기화 메서드 실행
  • @PreDestroy : 소멸 직전 메서드 실행

 

스프링 빈 생명주기

 

  • 객체 생성 (@Component, @Service, @Bean)
  • 의존성 주입 (DI)
  • 초기화 메서드 실행 (@PostConstruct)
  • 사용
  • 소멸 직전 메서드 실행 (@PreDestroy)
  • 객체 제거

 

<예시 코드>

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.stereotype.Component;

@Component
public class MyService {

    public MyService() {
        System.out.println("MyService 객체 생성!");
    }

    @PostConstruct
    public void init() {
        System.out.println("MyService 초기화!");
    }

    @PreDestroy
    public void destroy() {
        System.out.println("MyService 소멸!");
    }
}

 

 

 

 

스프링 빈을 Spring IoC Container에 등록하는 방법

 

1. 관련 애노테이션

 

@ComponentScan 

어는 지점부터 컴포넌트를 찾으라고 알려주는 역할을 한다.

@ComponenetScan이 붙어있는 클래스가 있는 패키지에서부터 모든 하위 패키지의 모든 클래스를 훑어 보며 @Component가 붙은 클래스를 찾는다.

 

@Component

자동으로 스프링 빈으로 등록해줌

@Controller, @Service, @Repository 들은 @Component를 포함하고 있다.

 

@Bean

스프링 컨테이너에 객체를 등록하는 애노테이션

 

@Configuration

스프링에서 설정 클래스임을 나타내는 어노테이션이다.

이 애노테이션이 붙은 클래스는 스프링 빈을 등록하는 설정 파일 역할을 한다는 의미이다.

 

 

2. 빈 설정파일에 직접 Bean 등록하는 방법

@Configuration
public class SpringConfig {

	@Bean
    public MemberService memberService() {
    	return new MemberService();
    }
}

 

위 코드는 스프링 컨테이너에 빈을 직접 등록하는 방법이다.

 

 

3. 자동으로 빈 등록하는 방법

 

@Bean을 통해 수동으로 빈 등록을 하는 방법 외에 @ComponentScan을 이용해서 자동으로 빈 등록을 하는 방법이 있다.

 

자동 빈 등록을 하기 위해서는 각 클래스에 특정 애노테이션을 추가해야 한다.

@Component 기본적인 스프링 빈 등록 (부모 개념)
@Service 서비스 레이어의 빈 등록 (비즈니스 로직 담당)
@Repository 데이터 접근(DAO, Repository) 관련 빈 등록
@Controller MVC 패턴에서 컨트롤러 역할 빈 등록
@RestController REST API 컨트롤러 빈 등록 (@Controller + @ResponseBody)

 

위 애노테이션을 사용했다면 ComponentScan의 대상이 된다.

 

이제 Configuration 클래스에서 @ComponentScan을 이용하여 자동 빈 등록을 하면 된다.

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

@Configuration
@ComponentScan(basePackages = "com.example.service") // 해당 패키지 스캔
public class AppConfig {
}

 

 


 

@Autowired

 

@Autowired는 스프링에서 의존성 주입을 자동으로 수행하는 애노테이션이다.

 

즉, 스프링 컨테이너에 등록된 빈을 자동으로 찾아서 주입해주는 역할을 한다.

@Controller
@RequestMapping("/member")
public class MemberController {

    private final MemberService memberService;

    @Autowired // 스프링이 MemberService 빈을 자동으로 주입
    public MemberController(MemberService memberService) {
        this.memberService = memberService;
    }

    @GetMapping("/info")
    @ResponseBody
    public String getMemberInfo() {
        return memberService.getMember();
    }
}

 

 

 

※Spring 4.3이상부터는 생성자가 하나만 있는 경우 @Autowired를 생략해도 자동으로 의존성이 주입된다.

 

@Controller
@RequestMapping("/member")
public class MemberController {

    private final MemberService memberService;

    // 생성자가 하나만 있을 경우, @Autowired 없이도 자동으로 주입됨
    public MemberController(MemberService memberService) {
        this.memberService = memberService;
    }

    @GetMapping("/info")
    @ResponseBody
    public String getMemberInfo() {
        return memberService.getMember();
    }
}