본문 바로가기
Java/Spring

[1] 간략한 스프링 개요 - IoC

by Riverandeye 2020. 11. 26.

이 레포 를 기반으로 학습합니다. 

 

1. Petclinic 프로젝트 실행

 

- 해당 레포를 클론 한 후 Intellij를 해당 폴더를 basedir 로 엽니다.

- Intellij가 자동적으로 dependency와 plugin들을 설치해줍니다.

- Cli에 ./mvnw package를 통해 패키지를 빌드해 줍니다

- maven에 packaging 옵션이 없어서 기본적으로 jar 패키지가 되므로, 빌드하여 생성된 jar 파일을 java로 실행하면 동작합니다. 

 

2. Properties 변경을 통한 환경 설정

 

src > main > resource 의 application.properties 에서 spring 관련 옵션을 지정해줍니다. 

# database init, supports mysql too
database=h2
spring.datasource.schema=classpath*:db/${database}/schema.sql
spring.datasource.data=classpath*:db/${database}/data.sql

# Web
spring.thymeleaf.mode=HTML

# JPA
spring.jpa.hibernate.ddl-auto=none
spring.jpa.open-in-view=false

# Internationalization
spring.messages.basename=messages/messages

# Actuator
management.endpoints.web.exposure.include=*

# Logging
logging.level.org.springframework=INFO
logging.level.org.springframework.web=DEBUG
logging.level.org.springframework.context.annotation=TRACE

logging.level.org.springframework.context.anno
# Maximum time static resources should be cached
spring.resources.cache.cachecontrol.max-age=12h

 

3. 서버 요청

 

/owners/new 경로로 요청시 요청을 핸들링하는 컨트롤러

DispatcherServlet -> Controller의 메소드 호출 -> Owner 객체 생성 후 모델에 등록 -> 리턴할 view의 경로를 반환

-> templates 에 있는 html을 반환

 

4. IoC

의존성을 주입해주는 걸 Dependency Injection 이라고 하는데

그 제어권을 다른 대상에게 넘겨주는 것이 Inversion of Control 입니다.

 

스프링이 관리하는 객체인 Bean 을 등록하면

해당 객체에 대해 의존성 주입을 대신 수행해줍니다

Bean은 Annotation을 통해 등록해줍니다. 

 

5. IoC Container

- ApplicationContext (BeanFactory)

 

bean을 만들고 의존성을 엮어주며(의존성 주입) 제공해줍니다.

그치만 실제로 소스코드에서 직접 참고해서 쓸 일은 많이 없습니다. 

 

Controller, Repository 들은 이 Ioc Container (ApplicationContext) 에 들어있습니다.

물론 모든 객체로 등록되어 있는 것은 아닙니다.

Entity, Dto 이런 것들은 그렇지 않습니다.

 

왼쪽 아이콘을 통해 Bean임을 알 수 있다 

생성자에 명시된 인자와 동일한 타입의 Bean을 찾아서 주입해줍니다.

의존성 주입은 Spring IoC Container 에 있는 Bean 들끼리만 가능합니다. 

 

ApplicationContext를 Bean에 주입해서 가져다 쓸 수도 있지만, 거의 그럴 일은 없다고 보면 됩니다. 

 

어떤 인스턴스 하나를 어플리케이션 전반에서 재사용함으로써

멀티쓰레드 상황에서 Singleton 을 매우 손쉽게 적용할 수 있습니다. 

 

6. Bean

 

스프링에서 Bean은 ApplicationContext가 알고 관리하는 객체들입니다. 

오로지 이런 Bean들만 서로 의존성 주입이 가능합니다. 

Bean을 등록하는 방법은 2가지가 있는데요,

하나는 Component Scanning이고 (일반적인 방식)

다른 하나는 XML 및 자바 설정 파일에 등록하는 것입니다. (구닥다리 방식)

 

Component Scanning은 Component라는 Annotation이 되어있는 객체를 찾는 것인데요

Annotation Processor 중에 Spring IoC Container가 빈을 등록할 때 사용하는 여러 인터페이스가 있는데

그런 인터페이스들을 Lifecycle Callback 이라고 합니다.

여러 Lifecycle Callback 중에는 이런 Component 라는 Annotation 이 붙어있는 모든 클래스를 찾아서

그 클래스의 인스턴스를 만들어 Bean으로 등록해주는 것이 있습니다. 

 

Controller에는 Component 어노테이션이 등록되어 있습니다

위와 같이 @Component 어노테이션이 적용된 어노테이션들은 다양합니다

@Controller @Repository @Service @Configuration ..etc

 

Spring Boot 의 경우엔 @SpringBootApplication Annotation 엔

내부적으로 @ComponentScan Annotation이 그 역할(Bean을 등록)을 하는 라이프사이클을 제공합니다. 

덕분에 @SpringBootApplication 이라는 어노테이션이 붙은 빈이

위치한 폴더의 하위 폴더에 있는 모든 컴포넌트를 스캔합니다. 

 

SpringBootApplication 어노테이션엔 @ComponentScan이 있습니다

ComponentScan은 어느 지점부터 찾을지를 알려주고

Component는관리할 대상을 알려줍니다.

 

어노테이션이 아니라 Configuration을 이용해도 되는데 요즘에 xml로 작성하는 일은 거의 없고

다음과 같이 직접 메소드 단에서 Bean을 만들어 줄 수 있습니다.

@Configuration
public class SampleConfig {
	
    @Bean
    public SampleController sampleController(){
    	return new SampleController();
    }
}

@Configuration 이 Bean이여서 먼저 Context에서 관리되고

그 후에 다음 메소드들이 호출되어 생성된 객체가 Bean으로 등록되게 됩니다.

 

7. 의존성 주입

 

의존성 주입을 명시하는 방법은 여러가지가 있습니다.

- 생성자에 @Autowired 어노테이션을 붙여줍니다.

- 멤버변수(field)에 @Autowired 어노테이션을 붙여줍니다. (그냥 해줍니다)  

- 스프링 4.3부터는 그냥 생성자만 선언해도, 인자가 Bean으로 등록되어 있으면 자동으로 Bean으로 관리해줍니다.

- Setter를 지정하여 그 Setter에 @Autowired를 붙여주는 방법도 있습니다. 

 

물론 @Autowired를 붙였다는건 그 대상이 Bean임을 전제하는 거라, Bean이 아니면 주입이 안됩니다. 

 

여러 방법 중에서 생성자를 사용하는 방법을 권장합니다. 

필수적으로 사용해야 하는 레퍼런스 없이 객체를 만들지 못하도록 강제할 수 있기 때문입니다.

특정 의존성이 없을 때 해당 객체가 정상적으로 동작하지 않는다면

생성자를 선언함으로써 주입을 보장할 수 있습니다. 

 

Field Injection 이나 Setter Injection 은 의존성이 없이도 강제로 만들 수 있습니다. 

물론 그게 장점이 되는 경우도 있습니다. (순환 참조의 경우)

만약 상호 의존적인 객체가 둘다 생성자를 사용하면.. 노답입니다. 가급적으로 의존성 조율을..

조율이 안되면 reflection 으로 해결..

 

 

댓글