Spring 에서 컨테이너는 스프링컨테이너 / IOC 컨테이너 / DI Container 와 같이 다양한 부르고 있는것 같다.
(공식문서에는 IOC container 로 목차에 있다)
이 스프링 컨테이너는 BeanFactory 혹은 ApplicationContext 를 구현함으로써 만들수 있는데 ApplicationContext가 더 큰 범위의 기능을 포함하고 있다. (ApplicationContext는 BeanFactory의 완전한 상위 집합이며, BeanFactory를 직접 구현하는 경우는 드물다고 한다.)
이러한 스프링 컨테이너에 의해 관리되는 객체들을 Bean이라고 말하고 빈은 컨테이너에 의해 인스턴스화되어진다.
그럼 컨테이너를 최초 생성되는 시점은 언제일까?
한번 spring boot initialize 를 사용해서 프로젝트를 한번 만들어봐야겠다.
spring_240128 로 프로젝트를 생성하고 src/java/Spring240128Application 들어가서 보니
SpringApplication.run(Spring240128Application.class, args);
이게 실행되어있다.
그리고 김영한님 강의 자료를 보면
//스프링 컨테이너 생성
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
이렇게 되어있는데 이 둘의 차이는 뭘까.
관련 해서 확인해보니 차이는
AnnotationConfigApplicationContext 는 기본적인 Spring framework 에서 ApplicationContext 를 생성하는 방식이고 (좀더 전통적인 방식 혹은 spring boot를 사용 안하고 좀더 세밀한 제어를 원할때),
SpringApplication.run() 는 Spring boot에서 생성하는 방식으로 ApplicationContext 뿐만아니라 다른 내장서버, 로깅 등 다른 기능을 포함해 설정해준다.
각 방법에 대해 좀더 디테일하게 알아보고 직접 실행해보자.
먼저 AnnotationConfigApplicationContext 로 직접 ApplicationContext 사용
일단 이방법은 @Configuration 방법을 써서 설정클래스를 주입시켜준다.
(설정 클래스에서는 bean을 연동시켜준다. 그럼 그 bean이 컨테이너에 등록되는 방법)
처음이라 생각하고 이건 스프링부트 initailize 를 안쓰고 그냥 기본 gradle 프로젝트만 만들어서 해봐야겠다.
먼저 프로젝트 만들기
그다음 springframework 불러오기
// build.gradle 의 dependencies 에 추가 하고 빌드
dependencies {
implementation("org.springframework:spring-context:6.1.3")
}
자바를 아직 많이 안써봐서 버전 빼고 먼저 빌드하면 알아서 최근 버전으로 될줄 알았는데 버전을 안쓰면 빌드가 안되더랑.. 그래서 현재 가장 최근 spring 버전 넣음
그다음 main 에서 컨텍스트를 생성해보겠다.
// org/example/Main.java
package org.example;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
}
}
이렇게 하면 정상 생성은 되겠지만 뭐 보이는게 없으니 아무 의미가 없다..
그래서 아직 bean 설명 전이지만 설정 클래스를 만들어서 bean을 간단하게 주입 해봐야겠다.
먼저 bean 클래스 생성
// org/example/SampleBean.java
package org.example;
public class SampleBean {
public void doSomething() {
System.out.println("Doing something in SampleBean");
}
}
그다음 설정 클래스 생성
// org/example/AppConfig.java
package org.example;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
public SampleBean myBean() {
return new SampleBean();
}
}
그다음 main 에서 다시 설정 파일 주입 및 빈 가져와서 메소드 호출
package org.example;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
SampleBean myBean = context.getBean(SampleBean.class);
myBean.doSomething();
context.close();
}
}
이걸 실행하면
이렇게 정상적으로 context에 주입된 bean의 메소드가 호출되는걸 볼수 있다.
근데 Appconfig 에서 내가 설정한걸 보면 출력 클래스는 SampleBean 이지만 메소드 명은 myBean 으로 등록했었다.
그래서 컨텍스트에 등록된 모든 빈을 봐보자
package org.example;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
SampleBean myBean = context.getBean(SampleBean.class);
myBean.doSomething();
// 모든 빈 이름을 가져옵니다.
String[] beanNames = context.getBeanDefinitionNames();
// 빈 이름들을 출력합니다.
System.out.println("등록된 모든 빈:");
for (String beanName : beanNames) {
System.out.println(beanName);
}
context.close();
}
}
역시 myBean으로 있다.
그럼 이름으로도 불러볼까?
package org.example;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
SampleBean myBean = context.getBean(SampleBean.class);
myBean.doSomething();
// 빈을 이름으로 불러보기
SampleBean myBean2 = (SampleBean) context.getBean("myBean");
myBean2.doSomething();
context.close();
}
}
똑같이 된다. 이처럼 context에 있는 bean을 클래스 타입이나 이름으로 불러오는게 가능하다.
그다음에는 Spring boot에서 컴포넌트 스캔을 사용하는 방법 (SpringApplication.run()
바로 spring boot initialize로 프로젝트 만들어준다.
빌드도 되고 잘 실행도 된다. (아무 것도 하지 않지만)
아까랑 차이는 @SpringBootApplication 이거밖에 없다. (아까 거기서 이것만 붙여도 된다. springboot starter 만 build.gradle에 추가하고)
그럼 그냥 아까 거기프로젝트에서 해볼까?
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.2'
id 'io.spring.dependency-management' version '1.1.4'
}
group = 'org.example'
version = '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework:spring-context:6.1.3")
implementation 'org.springframework.boot:spring-boot-starter'
}
test {
useJUnitPlatform()
}
먼저 build.gradle 에 추가
지금 보니 dependencies에 버전 안쓰면 plugins 에 버전을 써줘야하네... (dependency-management도 추가해줘야함. 아마 관리해주는건겠지. 귀찮으니 찾는건 pass)
그러면 이제 빌드가 성공적으로 되고.
이처럼 따로 메인 클래스 만들어서 실행하니 똑같이 된다.
일단 SpringApplication.run() 메소드는 어노테이션 @SpringBootConfiguration 와 함께 사용된다.
이 어노테이션은 @Configuration, @EnableAutoConfiguration, @ComponentScan 어노테이션의 조합
@ComponentScan은 지정된 패키지 내의 @Component, @Service, @Repository, @Controller 등의 어노테이션이 붙은 클래스를 스캔하여 빈으로 등록한다. (아까는 설정파일을 통해 사용할 bean을 등록해야했는데 이건 그냥 클래스 만들고 위에 어노테이션만 붙이면 알아서 찾아서 등록해준다는 뜻)
그러면 아까 만든 SampleBean에 어노테이션 붙이고 사용해볼까
붙이고
메인에서 전체 빈을 봤더니 SampleBean이 안뜬다. 흠......
계속 찾아보고 다른거랑 비교해도 안되어서, spring boot intialize로 생성한 프로젝트에서는 된다.
이렇게 생성자가 실행된게 보인다.
doSomething 함수도 메인문에서 사용하려 했더니 @Autowire 어노테이션이 스태틱 클래스에서는 생성이 안되어서 다른 runner용 클래스를 만들어서 component로 심어보겠다.
package com.example.springbootex;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
@Component
public class SampleBeanRunner implements ApplicationRunner {
@Autowired
SampleBean sampleBean;
@Override
public void run(ApplicationArguments args){
sampleBean.doSomething();
}
}
이렇게 하니 정상적으로 실행되는것이 보인다.
(컴포넌트가 정상적으로 스프링 컨테이너에도 주입되고, 활용하는 클래스에서도 자동으로 해당 컴포넌트를 사용할수 있는것을 확인할수 있다.)
어떻게 Component를 가져온건지. ApplicationRunner는 무엇인지는 다음글에서 설명해보도록 하겠다.
(일반 자바 프로젝트에서 spring boot만 implement한 프로젝트는 왜 안되는지도 다음에 확인해서 수정해야 겠다...)
'Spring' 카테고리의 다른 글
[Spring] 03. Bean 등록 방법 (0) | 2024.01.24 |
---|---|
[Spring] 01. 기본개념 : IOC / DI / DI Container / Bean (2) | 2024.01.24 |