IoC (Inversion of Control)
스프링에서는 일반적인 Java 객체를 new로 생성하여 개발자가 관리하는 것이 아닌 Spring Container에 모두 맡긴다.
즉, 개발자에서 프로임워크로 제어의 객체관리의 권한이 넘어 갔음으로 "제어의 역전"이라고 합니다.
@SpringBootApplication 어노테이션을 붙이면 스프링 부트로 동작하게 한다는 뜻입니다.
@SpringBootApplication 어노테이션 내부에는 다음과 같은 어노테이션이 존재합니다.
@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) })
@SpringBootConfiguration 어노테이션 내부에는 또 다시 다음과 같은 어노테이션이 존재합니다.
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
@Configuration 어노테이션 내부에는 @Component 어노테이션이 존재합니다.
이는 스프링 Bean에 등록될 수 있게 해줍니다.
클래스에 @Component 어노테이션을 기술하면, 프로젝트가 실행되면 @Component 어노테이션을 찾아서 해당 클래스를 싱글톤 형태로 만들어서 스프링 컨테이너에서 관리하게 됩니다.
스프링 어플리케이션 컨택스트(application context)를 통해서 등록된 클래스를 사용할 수 있습니다.
cf) 스프링 어플리케이션 컨택스트 - https://derekpark.tistory.com/81
new 지시어를 통해서 개발자가 직접 생성했던 객체를 스프링 어플리케이션 컨택스트의 빈에 등록하여, 스프링에 권한을 넘김으로서 제어의 역전(IoC)가 일어납니다.
객체관리는 스프링이 하고 개발자는 등록된 빈을 사용을 하면 됩니다.
Bean으로 등록해서 Ioc구현 코드
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class IocApplication {
public static void main(String[] args) {
SpringApplication.run(IocApplication.class, args);
ApplicationContext context = ApplicationContextProvider.getContext();
// Bean 호출
Encoder encoder = context.getBean(Encoder.class);
String url = "www.naver.com/books/it?page=10&size=20&name=spring-boot";
String result = encoder.encode(url);
System.out.println(result);
}
}
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static ApplicationContext getContext() {
return context;
}
}
bean 객체를 호출하기 위해 ApplicationContextProvider 클래스를 작성합니다.
// IEncoder.java
// 인터페이스
public interface IEncoder {
String encode(String message);
}
// Base64Encoder.java
import org.springframework.stereotype.Component;
import java.util.Base64;
@Component
public class Base64Encoder implements IEncoder {
@Override
public String encode(String message) {
return Base64.getEncoder().encodeToString(message.getBytes());
}
}
@Component 어노테이션을 붙여서 bean으로 등록합니다.
@Component("빈으로 등록할 명칭")과 같이 명칭을 지정할 수 있으며, 생략 시 클래스명(Base64Encoder)이 빈 명칭으로 등록됩니다.
// Encoder.java
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component
public class Encoder {
private IEncoder iEncoder;
public Encoder(@Qualifier("base64Encoder") IEncoder iEncoder) {
this.iEncoder = iEncoder;
}
public void setIEncoder(IEncoder iEncoder) {
this.iEncoder = iEncoder;
}
public String encode(String message) {
return iEncoder.encode(message);
}
}
@Component 어노테이션을 붙여서 bean으로 등록합니다.
인터페이스를 파라미터를 받을 경우 해당 인터페이스를 상속해서 등록한 Bean의 명칭을 지정해줘야합니다.
@Qualifier("base64Encoder")과 같이 @Qualifier 어노테이션에 사용할 등록된 빈의 명칭을 기술합니다.
여러 객체를 Bean으로 등록해서 관리하는 코드
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class IocApplication {
public static void main(String[] args) {
SpringApplication.run(IocApplication.class, args);
ApplicationContext context = ApplicationContextProvider.getContext();
// Bean을 호출합니다.
Encoder encoder = context.getBean("base64Encode", Encoder.class);
String url = "www.naver.com/books/it?page=10&size=20&name=spring-boot";
String result = encoder.encode(url);
System.out.println(result);
}
}
getBean 메소드를 사용하여 Bean을 호출 시 등록된 Bean의 명칭(base64Encode)을 기술하여 Bean을 호출합니다.
입력하지 않으면 클래스명으로 Bean을 찾지만 같은 클래스를 사용하는 여러 빈이 등록되었을 경우 Bean을 찾지 못하는 에러가 발생합니다.
이 경우에 Bean의 명칭을 지정해주면 됩니다.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
// 한 개의 클래스에서 여러개의 빈을 등록하는 방법
@Configuration
public class AppConfig {
@Bean("base64Encode")
public Encoder encoder(Base64Encoder base64Encoder) {
return new Encoder(base64Encoder);
}
@Bean("urlEncode")
public Encoder encoder(UrlEncoder urlEncoder) {
return new Encoder(urlEncoder);
}
}
Bean에 등록할 클래스명이 겹치는 경우 반드시 빈의 명칭을 기술해야합니다. 예시 @Bean("base64Encode")
빈의 명칭을 기술하지 않으면 클래스명이 자동으로 등록됩니다.
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
public class Encoder {
private IEncoder iEncoder;
public Encoder(IEncoder iEncoder) {
this.iEncoder = iEncoder;
}
public void setIEncoder(IEncoder iEncoder) {
this.iEncoder = iEncoder;
}
public String encode(String message) {
return iEncoder.encode(message);
}
}
// Base64Encoder.java
@Component
public class Base64Encoder implements IEncoder {
@Override
public String encode(String message) {
return Base64.getEncoder().encodeToString(message.getBytes());
}
}
@Component 어노테이션을 붙여서 bean으로 등록합니다.
// UrlEncoder.java
import org.springframework.stereotype.Component;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
@Component
public class UrlEncoder implements IEncoder {
@Override
public String encode(String message) {
try {
return URLEncoder.encode(message, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return null;
}
}
}
@Component 어노테이션을 붙여서 bean으로 등록합니다.
cf) @Component 참고 - https://programmingrecoding.tistory.com/13
두 어노테이션 모두 빈을 등록하는 기능을 합니다.
하지만 @Bean은 클래스에 붙일 수 없고 메소드에만 붙일 수 있습니다.
그렇기에 @Configuration을 사용한 클래스의 메소드로써 여러가지의 빈을 등록합니다.
@Component 어노테이션은 클래스에 붙여 빈을 등록할 수 있습니다.
해당 클래스의 메소드가 자동으로 빈으로 등록되게 됩니다.
메소드명이 빈 명칭으로 등록됩니다.
'Spring Boot' 카테고리의 다른 글
Spring Boot - Exception 개괄 (0) | 2021.09.10 |
---|---|
Spring Boot - Validation (0) | 2021.09.09 |
Spring Boot - Annotation 참고자료 (0) | 2021.09.07 |
Spring Boot - AOP (Aspect Oriented Programming) (0) | 2021.09.03 |
Spring Boot - DI (Dependency Injection) (0) | 2021.09.02 |
댓글