Study/spring

Spring Triangle [IoC, AOP, PSA] - 1편 IOC편

에디개발자 2020. 12. 13. 07:00
반응형

Java개발자로 전향한지 4년차가 되었습니다. 문득 저에 대해서 돌아보는 시간을 강제로 갖게되었고 난 개발자로써 살아가고 있는가에 대해서 궁금해졌습니다.  

모든 소스는 github에 올려두었습니다.

나를 닮았다고 한다...

나에게 질문을 해보았습니다. 

기초는 튼튼한가? 
자바에 대해서 얼만큼 알고 있지? Spring은?

블로그를 시작한지 한달이 조금 넘어가는 시점에서 다시 개념을 정리하고 복습하는 의미에서 되돌아가기로 하였습니다.

 

이번 글에서는 Spring Triangle 중 하나인 IoC에 대해서 정리해보겠습니다.

 

IoC란?

Inversion Of Control

그대로 해석하자면 제어의 역전입니다. 말 그대로 제어를 역전시키는 방법입니다. 개발자는 소스로 얘기하자는 주의라서 예제소스를 작성하면서 코멘트를 달아보겠습니다.

 

일반적인 제어

public class IocController {
    private IocService iocService;

    public void run() {
        iocService.run();
    }
}

run 메서드를 실행하면 NullPointException이 발생할 것 입니다. 이유는 SampleService에 의존성 주입을 하지 않아서 입니다. 그럼 의존성을 주입해보겠습니다. 

 

public class IocController {
    private IocService iocService;

    public IocController() {
        iocService = new IocService();
    }
    
    public void run() {
        iocService.run();
    }
}

코드를 수정하여 실행하면 정상 작동이 될 것입니다. 

이 코드가 일반적인 경우입니다. Sample 클래스가 사용하려는 SampleService를 생성하려면 클래스 내부에서 생성하여 사용합니다.

 

제어의 역전

그럼 IoC를 적용한 코드를 살펴보겠습니다. 

@RestController
public class IocController {
    @Autowired
    private IocService iocService;

    public void run() {
        iocService.run();
    }
}
@Slf4j
@Service
public class IocService {
    public void run() {
        log.info("");
    }
}

이렇게 작성되있으면 에러는 발생하지 않습니다. 이유는 SampleService가 Bean에 등록되있고 Sample 클래스에서는 Bean에 이미 등록되있는 SampleService를 가져와서 사용합니다.

Sample 클래스에서 SampleService를 생성하지 않고 이미 생성되어 Bean에 등록되어있는 클래스를 가져옵니다.
Sample 클래스에서 SampleService를 사용하는 데 Sample 클래스에서 생성하지 않았습니다. 이것을 제어의 역전이라고 합니다.

 

제어의 역전 원리

Spring project를 실행할 때 main메서드가 존재하는 클래스에 @SpringBootApplication이 존재합니다. 이 어노테이션은 @ComponentScan을 사용합니다. 

@SpringBootApplication
public class PracticeApplication {

	public static void main(String[] args) {
		SpringApplication.run(PracticeApplication.class, args);
	}
}

@ComponentScan은 선언된 클래스 하위 패키지에서 @Component가 달려있는 클래스를 찾아 singleton방식으로 Bean에 등록합니다.

@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 {

}
singleton이란?

instance가 오직 한개뿐입니다. 다시 말해서 메모리에 생성된 instance를 등록하고 필요할 때마다 새로 생성하지 않고 메모리에서 가져와서 사용합니다. instance한개로 여기저기서 쓰는 것! 이라고 생각하면 이해하기 쉽습니다.
@Controller, @Service, @Repository, @Configuration 어노테이션은 모두 @Component를 사용하고 있는 어노테이션입니다.

 

그럼 위 소스 기준으로 SampleService는 이미 Bean에 등록되어있다는 것을 알 수 있습니다. 그럼 Sample 클래스에서 Bean에 등록되어있는 SampleService를 @Autowired를 이용하여 가져올 수 있습니다.

물론 다른방법인 ApplicationContext 객체에서도 getBean을 하여 가져올 수 있지만 이 방법은 사용하지 않는 방법입니다.

@Autowired 어노테이션은 필드에 붙힐 수 있고 생성자에도 붙힐 수 있습니다. 

@RestController
public class IocController {
    private IocService iocService;
    
    @Autowired
    public IocController(IocService iocService) {
        this.iocService = iocService;
    }

    public void run() {
        iocService.run();
    }
}

생성자에 붙혀서 사용하면 SampleService 객체를 bean에서 가져옵니다. 

Tip!
Spring 4.. 5.? 버전 이후로는 하나의 생성자만 있을 경우 @Autowired를 달지 않아도 파라미터인 ServiceService는 bean에서 가져옵니다. 

 

제어의 역전 다른 방법

setter를 사용할 수도 있습니다.

@RestController
public class IocController {
    private IocService iocService;

    public void setService(IocService iocService) {
        this.iocService = iocService;
    }

    public void run() {
        iocService.run();
    }
}
public class IocTest {

    public void run() {
        IocController iocController = new IocController();
        IocService service = new IocService();
        
        iocController.setService(service);
        iocController.run();
    }
}

SampleTest 클래스에서 SampleService 클래스를 생성한 후 Sample 클래스에 Setter로 주입시키는 방법입니다.

이 방법도 굳이 추천하지않는 방법입니다.

전 비슷한 코드를 보았는데 p6spy 오픈소스에서 logFormat을 설정하는 클래스를 주입받을 수 있게 setter로 받고 있었습니다. 
내가 원하는 logFormat 클래스를 만들고 set으로 주입할 수 있는 경우였습니다.

 

여기까지 IoC에 대해서 알아보았습니다.

다음글에서는 AOP에 대해서 정리해보겠습니다!

 

기초 튼튼!!

반응형

'Study > spring' 카테고리의 다른 글

@Autowired vs @Inject vs @Resource  (4) 2021.02.18
[Hateoas] Rest API를 구현해보자  (0) 2020.12.17
Rest API란?  (0) 2020.12.16
Spring Triangle [IoC, AOP, PSA] - 3탄 PSA편  (0) 2020.12.15
Spring Triangle [IoC, AOP, PSA] - 2탄 AOP편  (0) 2020.12.14