#스프링 IoC
토비의 스프링에서 먼저 공부한 스프링 IoC에 대해 다시 한번 리마인드를 해보자.
First, IoC stands for Inversion Of Control 즉 제어의 역전이라는 뜻이다.
스프링 프레임워크 안에서의 객체들은 자신들이 사용할 객체들을 스스로 생성하지도 않고, 자기 자신들도 어디서 사용되는지 알 수가 없다. 오브젝트들의 생성과 책임에 대한 제어가 오브젝트 스스로에게 있지 않고, 이 권한을 위임한 다른 특별한 오브젝트에게 있다!
오브젝트의 입장에서는 그 특별한 오브젝트로부터 생성과 책임에 대해 제어를 받으니 control의 방향이 inversed 된 것이다.
그리고 이러한 IoC방식에서 말하는 특별한 Object를 Application Context, 제어권이 없는 오브젝트들을 Bean이라고 부른다.
Application Context는 Bean을 관리하는 Bean Factory의 기능 + Spring의 부가적인 기능을 담당하는 역할을 한다.
우선 Bean에 대해 알아보자.
#스프링의 Bean
Bean이란, 스프링 IoC 컨테이너가 관리하는 객체들을 말한다. IoC컨테이너들에 등록된 Bean들은 의존 객체들을 직접 만들지 않고도 Spring에서 제공하는 어노테이션을 사용하여 주입받아 사용할 수 있다.
스프링 IoC 컨테이너의 가장 최상위에 위치한 인터페이스는 BeanFactory 인터페이스고, 이 인터페이스에는 Bean들의 다양한 라이프사이클에 관한 메소드들이 담겨있다.
Spring에서 제공하는 공식문서에 따르면 Bean factory의 구현은 빈의 라이프사이클 인터페이스에 따라야 한다. 그리고 그 순서는 아래와 같다.(https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/BeanFactory.html)
Bean factory implementations should support the standard bean lifecycle interfaces as far as possible. The full set of initialization methods and their standard order is:
- BeanNameAware's setBeanName
- BeanClassLoaderAware's setBeanClassLoader
- BeanFactoryAware's setBeanFactory
- EnvironmentAware's setEnvironment
- EmbeddedValueResolverAware's setEmbeddedValueResolver
- ResourceLoaderAware's setResourceLoader (only applicable when running in an application context)
- ApplicationEventPublisherAware's setApplicationEventPublisher (only applicable when running in an application context)
- MessageSourceAware's setMessageSource (only applicable when running in an application context)
- ApplicationContextAware's setApplicationContext (only applicable when running in an application context)
- ServletContextAware's setServletContext (only applicable when running in a web application context)
- postProcessBeforeInitialization methods of BeanPostProcessors
- InitializingBean's afterPropertiesSet
- a custom init-method definition
- postProcessAfterInitialization methods of BeanPostProcessors
On shutdown of a bean factory, the following lifecycle methods apply:
- postProcessBeforeDestruction methods of DestructionAwareBeanPostProcessors
- DisposableBean's destroy
- a custom destroy-method definition
그리고 이 Bean들은 시스템이 구동되면 스프링 IoC 컨테이너에 의해 관리가 되는데 그 때 아래와 같은 특징들을 가진다.
1. 싱글톤 스코프
: Spring에서는 애플리케이션 구동 시 JVM 안에서 bean마다 하나의 객체만을 생성한다. 그러므로 Bean 호출시 매번 동일객체가 참조된다. Bean 설정에서 Prototype으로 설정해줄 수 있지만, default는 Singleton Scope를 가진다.
2. 라이프 사이클 인터페이스를 가진다.
: 아래의 코드와 같이 BookServce라는 Bean은 construct 되기 이전에 Print라는 함수가 자동으로 호출된다.
@Service
public class BookService {
....
@PostConstruct
public void Print() {
System.out.println("Bean이 Construct 되기 전에 호출되는 함수");
}
}
#스프링의 Application Context
: Application Context는 BeanFactory를 상속받아 스프링 IoC에 등록된 빈들을 관리함과 동시에,
- ApplicationEventPublisher
- EnvironmentCapable
- HierarchicalBeanFactory
- ListableBeanFactory
- MessageSource
- ResourceLoader
- ResourcePatternResolver
라는 인터페이스들을 상속받고 있다.
ApplicationContext에서 Bean을 설정해주는 방법은 여러가지가 있다.
1. XML에서 직접 명시해주는 방식
아래와 같이 application.xml 파일에 빈의 아이디와 경로, 그리고 참조하는 오브젝트가 있다면 ref 속성을 넣어주는 방식이다.
##application.xml file
<bean id="bookService"
class="spring.BookService">
<property name="bookRepository" ref="bookRepository">
</bean>
<bean id="bookRepository"
class="spring.BookRepository">
</bean>
2. XML에서 component scan 방식으로 가져오는 방식
component 스캔방식으로 빈들을 가져오기 위해서는 application.xml에 아래와 같이 작성해주어야 한다.
##application.xml
<beans xmlns~>
<context:component-scan base-package="src">
</beans>
그리고 각각의 클래스에서
@Component나, @Component를 확장한 @Service, @Repository 애노테이션을 붙여줘야 한다.
단, 이런 방식에서는 자동으로 주입이되지 않기 때문에 @Autowired 컴포넌트를 사용하여 BookService와 BookRepository의 의존관계를 설정해주어야 한다.
// #1. BookRepository.class
@Repository
public class BookRepository {
}
// #2. BookService.class
@Service
public class BookService {
@Autowire
BookRepository bookRepository;
}
3. Java에서 직접 명시해주는 방식
Java로 Bean을 관리하는 방식은 유연하게 빈을 관리할 수 있다는 장점이 있다.
@Configuration 애노테이션을 붙인 ApplicationConfig 파일에서 빈을 관리한다.
의존관계는 아래와 같이 생성자를 통해 주입된다(or 메소드 파라미터로도 주입받을 수 있음)
// ApplicationConfig.java
@Configuration
public class ApplicationConfig {
@Bean
public BookRepository bookRepository(){
return new BookRepository();
}
@Bean
public BookService bookService(){
BookService bookService = new BookService();
bookService.setBookRepository(bookRepository());
return bookService;
}
}
그리고 이 ApplicationConfig가 Bean 설정파일로써 사용되기 위해서는 ApplicationContext 생성자가 호출되는 곳에서 (메인 함수)
AnnotationConfigApplicationContext의 메소드에 해당 클래스를 주입해주는 과정이 필요하다.
// main 함수
public static void main (String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);
}
4. Java에서 component scan 방식으로 가져오는 방식
아까 작성했던 ApplicationConfig를 component scan방식으로 변경하기 위해서는
@ComponentScan 애노테이션을 사용하면 된다. 컴포넌트의 파라미터는 basePackages와 basePackageClasses를 넣어줄 수 있다.
- basePackages : 경로
- basePackageClass : Application.class 이름. 이 클래스를 기준으로 하위 클래스들을 다 탐색해라
// #1. basePackage
@Configuration
@ComponentScan(basePackage="src")
public class ApplicationConfig{
}
// #2. basePackageClasses
@Configuration
@ComponentScan(basePackage="Application")
public class ApplicationConfig{
}
5. SpringBoot에서 자동으로 해결해 주는 방법
Application.class 에 @SpringBootApplication애노테이션을 붙여주면 이 모든 과정을 스프링이 알아서 해준다.
@SpringBootApplication //#####1. 이 애노테이션. 돼지꼬리 땡땡
public class Application {
public static void main (String[] args){
}
}
@SpringBootApplication 인터페이스 파일을 열어보면 다음과 같이 @SpringBootConfiguration과 @ComponentScan 애노테이션이 붙어있는 것을 확인할 수 있다. Config.class 파일 없이 이 자체로 config의 역할을 하면서 componentScan의 시작점이 되고 있는 것이다.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
}
@Component 애노테이션에는 아래의 네가지 종류가 있다.
- @Repository
- @Service
- @Controller
- @Configuration
그리고 Component 스캔 시
@ComponentScan(excludeFilters = ) 속성을 통해, 특정 클래스들을 Bean으로 등록하지 않을 수 있다.
'Study > Spring' 카테고리의 다른 글
스프링 핵심기술 05. 추상화 (0) | 2022.02.13 |
---|---|
스프링 핵심기술 04. ApplicationContext가 상속받는 인터페이스들 (0) | 2022.02.06 |
스프링 핵심기술 03. 스프링 IoC 컨테이너 - Bean의 Scope (0) | 2022.02.03 |
스프링 핵심기술 02. 스프링 IoC 컨테이너 - @Autowire (0) | 2022.02.02 |
토비의 스프링 01. 오브젝트와 의존 관계 (0) | 2021.12.15 |