목차
의존성관계주입
Spring ICO (Inversion Of Control)
IOC 예제
@Component 를 입력했더니 에러가 발생했다.
번외 실무에서는 잘 사용하지 않는다는 말
스프링에서 일반적인 Java 객체를 new
로 생성하여 개발자가 관리하는 것이 아닌 Spring Container
에 모두 맡긴다.
따라서 개발자의 직접 관리 없없도 Spring Container
는 객체의 생명주기를 관리할 수 있게되며 개발자가 원하는 요청에 따라 DI
의 요청을 수행할 수도 있다.
개발자 중심의 관리 ➡ 프레임워크 중심의 객체관리 권한 제공
그렇다면 Spring Container
가 객체를 관리하면 개발자는 어떻게 Container
로 부터 객체를 가져와야할까?
이전 포스팅에서는 DI
를 구현하여 개발자가 직접 주입하는 방식을 따랐지만 이번 포스팅에서는
Container
가 자동으로 주입하는 방식을 구현한다.
@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;
}
}
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
public class Base64Encoder implements IEncoder {
public String encode(String message) {
return Base64Encoer.getEncoer()
.encodeToString(message.getByres());
}
}
@Component
public class Encoder {
private IEncoder iEncoder;
//TODO: 호출한 인터페이스를 Encoder 자체에 주입했다.
public Encoder(IEncoder iEncoder){
this.iEncoder=iEncoder;
}
public void setIEncoder(IEncoder iEncoder){
this.iEncoder = iEncoder;
}
public String encode(String message) {
return iEncoder.encode(message);
}
}
@SpringBootApplication
public class Main() {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
//TODO: Spring Container 호출
ApplicationContext context = ApplicationContextProvider.getContext();
//TODO: 컨테이너가 관리중인 특정 Bean을 가져온다.
Base64Encoder encoder = context.getBean(Base64Encoder.class);
UrlEncoder urlEncoder = context.getBean(UrlEncoder.class);
String url = "www.google.com";
Encoder encoder = new Encoder();
String result = encoder.encode(url);
System.out.println(result);
encoder.setIEncoder(urlEncoder);
String urlresult = encoder.encode(url);
System.out.println(result);
}
}
@Component
어노테이션 이 달려있는 클래스는 앞으로 Spring Container
에서 Bean으로서 관리하도록 지정한다.
Container
에 주입까지 완료했다면 더 나아가 컨테이너가 자동 관리 및 주입 과정을 수행할 수 있도록 구성해야한다.
@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;
}
}
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
public class Base64Encoder implements IEncoder {
public String encode(String message) {
return Base64Encoer.getEncoer()
.encodeToString(message.getByres());
}
}
@Component
public class Encoder {
private IEncoder iEncoder;
//TODO: @Component 에러 발생
public Encoder(IEncoder iEncoder){
this.iEncoder=iEncoder;
}
//TODO: 어떤 Bean을 사용할지 지정해주자!
public void setIEncoder(@Qualifier("urlEncoder")IEncoder iEncoder){
this.iEncoder = iEncoder;
}
public String encode(String message) {
return iEncoder.encode(message);
}
}
@SpringBootApplication
public class Main() {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
//TODO: Spring Container 호출
ApplicationContext context = ApplicationContextProvider.getContext();
//Base64Encoder encoder = context.getBean(Base64Encoder.class);
//UrlEncoder urlEncoder = context.getBean(UrlEncoder.class);
String url = "www.google.com";
Encoder encoder = context.gerBean(Encoder.class);
String result = encoder.encode(url);
//TODO: @Qualifier 어노테이션에 주입한 Bean에 따라 출력 결과가 달라진다.
System.out.println(result);
}
}
다음 코드에서 @Component
를 가지는 클래스가 Encoder
와 Base54Encoder
두가지가 있다.
여기서 에러가 발생하는데 Spring 에서는 두가지의 @Component
에서 어떤 Bean 사이에 충돌이 발생하는데
우리는 @Qualifier
어노테이션을 통해 변수를 지정해주어야한다.
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
public class Base64Encoder implements IEncoder {
public String encode(String message) {
return Base64Encoer.getEncoer()
.encodeToString(message.getByres());
}
}
@Component
public class Encoder {
private IEncoder iEncoder;
//TODO: @Component 에러 발생
public Encoder(IEncoder iEncoder){
this.iEncoder=iEncoder;
}
//TODO: 어떤 Bean을 사용할지 지정해주자!
public void setIEncoder(@Qualifier("urlEncoder")IEncoder iEncoder){
this.iEncoder = iEncoder;
}
public String encode(String message) {
return iEncoder.encode(message);
}
}
그렇다면 왜 발생하는 걸까?
IEncoder
를 상속받은 두 클래스를 본다면 Spring
입장에서는 어떤 두 클래스 중에서 객체를 받아야 하는지 궁금할 것이기
때문에 지정해 주어야한다. 라고 나는 생각한다.
난 두개의 Encoder
를 모두 사용하고 싶다면 어떻게 해야할까?
직접 등록할 클래스의 @Component
를 지우고 직접 Bean
으로 등록하면 가능하다!
@Configuration : 한개의 클래스에서 여러개의 Bean을 관리할 것을 명시
@Configuration
class AppConfig{
@Bean("base64Encode")
public Encoder encoder(Base64Encoder base64Encoder){
return new Encoder(base64Encoder);
}
@Bean("urlEncode")
public Encoder encoder(UrlEncoder urlEncoder){
return new Encoder(urlEncoder);
}
}
@SpringBootApplication
public class Main() {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
//TODO: Spring Container 호출
ApplicationContext context = ApplicationContextProvider.getContext();
String url = "www.google.com";
Encoder encoder = context.gerBean("urlEncode", Encoder.class);
String result = encoder.encode(url);
//TODO: @Qualifier 어노테이션에 주입한 Bean에 따라 출력 결과가 달라진다.
System.out.println(result);
}
}