티스토리 뷰

Spring Bean Container



안녕하세요 오늘은 스프링 빈 컨테이너에 대해서 알아보겠습니다.



스프링 빈 컨테이너 역할

- 스프링 객체를 관리한다 : 컨테이너가 스스로 객체를 생성한다

1) @ComponentScan : @Component가 붙은 클래스들을 읽어서 객체로 생성한다

2) @Bean : @Bean을 이용하여 개발자가 생성하는 코드를 작성한다.



Java Configure

- 이전 버전의 스프링에서는 XML로 설정을 하였으나, 현재 스프링 버전에서는 어노테이션으로 지원한다.


그렇다면 우리가 메인 실행파일에서 보는 @SpringBootApplication이란 무엇일까?

웹 어플리케이션을 실행할 때 자주 보지만 그 의미에 대해서는 깊이 생각한 적이 없었다.


@SpringBootApplication은 3가지 성격을 가진 어노테이션으로 구성된다.

1) @Configuration : 클래스에 이 어노테이션이 붙어 있으면 스프링은 해당 클래스를 Java config로 간주한다.

2) @ComponentScan : 컴포넌트 검색기능을 가진 어노테이션이다. 스프링은 기본적으로 객체를 자동으로 생성하여 관리하기 때문에 @Component 어노테이션이 있는 클래스들을 스프링 컨테이너가 생성해준다. @ComponentScan는 특별히 basePackage를 지정하지 않아도 main class가 위치한 패키지를 Root package로 하여 그 이하의 모든 컴포넌트 클래스들을 검색하여 빈으로 등록한다.

FirstApplication.class는 메인 클래스이다. 이 클래스는 examples.boot.first 패키지에 위치하고 있고 이곳이 컴포넌트 스캔의 루트 패키지가 된다. 즉 FirstApplication이 위치하고 있는 example.boot.first 패키지가 기준이 되어 그 하위에 있는 모든 컴포넌트들을 검색한다. 


3) @EnableAutoConfiguration : 어플리케이션에 추가된 설정들을 자동으로 추가해주는 어노테이션



스프링에 없어서는 안되는 @SpringBootApplication 어노테이션을 살펴보자

@SpringBootApplication
public class FirstApplication {
// 프로그램 시작점
public static void main(String[] args) {
SpringApplication.run(FirstApplication.class, args);
}
}

@SpringBootApplication을 클릭하고 들어가면 

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(

@SpringBootConfiguration 어노테이션을 확인할 수 있다. 이 어노테이션을 클릭하면

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}

다음과 같이 @Configuration 어노테이션이 붙은 인터페이스가 나온다.

위와 같이 클래스에 @Configuration이 있으면 스프링은 Java Configure 설정 클래스로 간주하여 Bean으로 등록한다.





컴포넌트 스캔 : @Component를 검색

@ComponentScan : 

- 루트 패키지 이하의 클래스 중 @Component 어노테이션이 붙은 클래스들을 검색한다.


@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}

@Configuration 어노테이션을 클릭하면 

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
@AliasFor(
annotation = Component.class
)
String value() default "";
}

@Component 어노테이션을 확인할 수 있다.


즉 이 뜻은 @Configuration 클래스도 컴포넌트로서 스캔의 대상이 된다.




위와 같이 @Configuration, @ComponentScan, @Component 어노테이션에 대해 알아보았습니다. 그렇다면 누가 빈을 생성해주는 역할을 하는 것일까요?? 바로 스프링 빈 컨테이너가 해줍니다. 

스프링 빈 컨테이너는 인스턴스의 생명주기를 관리합니다. 컨테이너의 종류는 ApplicationContext와 BeanFactory 2가지로 나누어지는데, 둘의 차이점은 쉽게 말하면 ApplicationContext가 BeanFactory의 향상된 버전입니다.



ApplicationContext

ApplicationContext를 구현하고 있는 클래스들이 객체 관리 및 의존성 주입 가능하게 해준다. 오브젝트 생성, 관계 설정, 만들어지는 방식, 자동 생성, 후처리 등 여러가지 일들을 한다. 그리고 BeanFactory를 상속 받고 있다.




Spring의 역할


1. 스프링은 객체를 관리한다.


- 1. 객체 생성 : @Component 어노테이션을 포함한 클래스들의 인스턴스를 자동으로 생성한다.


@Component의 종류

1. @Contoller - @RestController

2. @Service

3. @Repository

 ** 3가지 종류의 컴포넌트가 다른 이름을 가진 이유는 레이어를 구분하기 위함


@RestController : @RestController -> @Controller 안으로 들어가면 @Component 어노테이션이 있다. @Component 어노테이션이 붙어 있으면 스프링 Bean Container가 모두 객체를 생성한다(개발자가 직접 new()를 사용하는 것과 같은 역할을 한다.)


이 때 스프링의 객체 생성의 가장 큰 특징으로는 Singleton 패턴이라는 것입니다. 어떻게 하는 것 일까요?




@Bean을 이용하여 개발자가 생성하는 코드를 작성


public class FirstApplication {
// 프로그램 시작점
public static void main(String[] args) {
SpringApplication.run(FirstApplication.class, args);
}


run()에 넣어야 하는 것은 Java Config 클래스이다. 즉 FirstApplication.class를 넣는다. Java Config가 되려면 @Configuration이 붙어 있어야 한다.

@SpringBootApplication 내부에 @Configuration이 포함되어 있기 때문에 Java configure로 가능.


그럼 Java configure는 누가 읽는가? Application Context가 읽는다. 이것은 run() 안에 구현되어 있다.


examples.boot. first ---> 이하로 컴포넌트를 찾는다

    FirstApplication이 examples.boot.first에 있기 때문.


examples.boot.first.service 라는 패키지 아래에 컴포넌트가 있어도 찾을 수 있다.


examples.boot.first.main 패키지에 FirstApplication 클래스가 있다면?

examples.boot.first.service 패키지의 클래스는 찾을 수 있을까? No!!



스프링은 기본적으로 객체를 관리할 때 Singleton으로 한다.

객체를 메모리에 1번만 올린다.


2. 스프링은 의존성을 관리

- setter 주입

- 생성자 주입

- @Autowired




웹에서의 스레드와 공유객체

웹에서 싱글톤 객체를 사용하게 되면 망가질 수 있다.

 - 객체의 필드가 변할 수 있기 때문이다.

 - synchronized 키워드를 붙이면 thread에서 발생하는 문제를 예방할 수 있다.



Spring Bean Container

FirstApplication : 설정 파일


@Bean

todayBean()

--> 첫 번째 호출할 때는 super.todayBean() 한번 호출


2번째 호출할 때는 프록시 객체를 바로 리턴한다.


동적생성할 때 사용하는 CGLIB를 사용한다.




http://localhost:8080/hello


1) 접속(ip, 포트번호)

2) 요청정보

- 요청라인 : GET /hello(path) 버전

- 헤더(이름의 값)

- Body : GET 방식으로 보낼 땐 없고 POST일 때 있다

- path = context path + path

1) context path : Tomcat started on port(s): 9090 (http) with context path ''

* 톰캣에는 여러개의 웹 어플리케이션이 있는데 그것들을 구분할 수 있는것이 context path이다.

2) path : 웹 어플리케이션 내부에서 맵핑

- DispatcherServlet : 모든 요청은 이곳에서 처리하도록 설정함

- DefaultServlet : 디스패쳐가 해결하지 못하는 것은 Default서블릿이 함. 

--> 이 요청 정보들이 HttpServletRequest에 입력되는 것이다. 

HttpServletResponse 객체는 응답을 위한 객체이다. 이것은 WAS가 만든다. 그래야 어디로 응답할지 알기 때문



<이번주 할일>

1. Java config 중심으로 찾기

2. DI 컨테이너

3. 의존성 주입 예제









댓글