<
Spring IOC / DI - 의존성 주입 편
>
🌠다음 포스팅🌠

Spring AOP 관점지향 프로그래밍
☄이전 포스팅☄

내부 클래스와 익명 클래스 차이
의존성 주입 DI에 대해 알아보자

목차
의존성관계주입
Spring ICO (Inversion Of Control)
IOC 예제
@Component 를 입력했더니 에러가 발생했다.
번외 실무에서는 잘 사용하지 않는다는 말

의존성관계주입

Spring IOC

스프링에서 일반적인 Java 객체를 new로 생성하여 개발자가 관리하는 것이 아닌 Spring Container에 모두 맡긴다.

따라서 개발자의 직접 관리 없없도 Spring Container는 객체의 생명주기를 관리할 수 있게되며 개발자가 원하는 요청에 따라 DI의 요청을 수행할 수도 있다.

개발자 중심의 관리 ➡ 프레임워크 중심의 객체관리 권한 제공

그렇다면 Spring Container가 객체를 관리하면 개발자는 어떻게 Container로 부터 객체를 가져와야할까?

IOC 예제

이전 포스팅에서는 DI를 구현하여 개발자가 직접 주입하는 방식을 따랐지만 이번 포스팅에서는 Container가 자동으로 주입하는 방식을 구현한다.

IOC - 적용 전


@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에 주입까지 완료했다면 더 나아가 컨테이너가 자동 관리 및 주입 과정을 수행할 수 있도록 구성해야한다.

IOC - 적용 후

@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 를 입력했더니 에러가 발생했다.

다음 코드에서 @Component를 가지는 클래스가 EncoderBase54Encoder 두가지가 있다.

여기서 에러가 발생하는데 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);

    }
}

🧾 Reference

Top
Foot