티스토리 뷰
Spring Annotation - Inversion of Control & Dependency Injection
junojuno 2021. 1. 31. 00:351. Spring Annotation - Inversion of Control
1) Java Annotation이란 ?
간단히 말하면 class에 대한 meta-data라 보면 된다.
- special labels / markers added to java classes
- provide meta-data about the class
- processed at compile time or run-time for special processing
* Meta-data(메타데이터)란? (출처 : wikipedia)
데이터에 관한 구조화된 데이터로 다른 데이터를 설명해 주는 데이터이다.
대량의 정보 가운데에서 찾고 있는 정보를 효율적으로 찾아내서 이용하기 위해 일정한 규칙에 따라 콘텐츠에 대하여 부여되는 데이터이다.
어떤 데이터 즉 구조화된 정보를 분석, 분류하고 부가적 정보를 추가하기 위해 그 데이터 뒤에 함께 따라가는 정보를 말한다.
예를들어 @override 또한 annotation 중 하나인데, compilation time에 처리된다.
컴파일러에게 이 메소드가 우리는 compliant이고 부모클래스나 인터페이스의 method를 override할 것이라고 알려주는것. -> 그리고 compilation time에 complie하면서 클래스를 체크하고 실제로 method를 override하는지 확인한다.
2) Annotation으로 spring configuration을 하는 이유
xml file로 configuration을 하면 매우 큰 프로젝트에 있어서 너무 장황해진다.
예를들어 30개의 bean, 100개의 bean이 있는 스프링 프로젝트에서, 모든 bean의 리스트들을 config file에 적어야 한다.
이 과정을 annotation을 사용함 으로서 xml configuration을 최소화 시켜준다.
(상자에 도착지를 적어주는 것이라 생각하면된다. 이 클래스는 어디에 쓰일것이다 어디에 쓰일것이다..)
3) @Component
Spring이 특별한 annotation이 붙어 있는 나의 java 클래스들을 scan할것이고, 찾으면 자동으로 spring container에서 bean을 등록해 줄 것이다.
Development Process
1. Enable component scanning in spring config file.
2. add @Component annotation to your java classes.
3. retrieve bean from spring container.
사용방법
클래스 이름위에 @Component 또는 @Component("bean ID")를 적어준다.
특정 bean ID를 정해주지 않으면 자동생성되는 default bean ID는 클래스 이름에서 맨 첫번째 글자를 소문자로 바꾼것이다. 만약 URL처럼 두번째 글자또한 대문자이면, 클래스 이름 그대로가 default bean ID이다.
e.g) Class name : TennisCoach -> Default bean ID : tennisCoach
* 코드 예시)
<!-- add entry to enable component scanning -->
<context:component-scan base-package="com.luv2code.springdemo"/>
package com.luv2code.springdemo;
import org.springframework.stereotype.Component;
@Component
public class TennisCoach implements Coach {
@Override
public String getDailyWorkout() {
return "Practice your backhand volley";
}
@Override
public String getDailyFortune() {
return fortuneService.getFortune();
}
}
package com.luv2code.springdemo;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AnnotationDemoApp {
public static void main(String[] args) {
///read spring config file
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
//get the bean from spring container
Coach theCoach = context.getBean("tennisCoach", Coach.class);
//thatSillyCoach(explicit bean id)-> tennisCoach (default bean id)
//call a method on the bean
System.out.println(theCoach.getDailyWorkout());
//call method to get the daily fortune
System.out.println(theCoach.getDailyFortune());
// close the context
context.close();
}
}
* 기존 코드)
<bean id="myCoach"
class="com.luv2code.springdemo.TennisCoach">
</bean>
위 코드에서 확인 할 수 있듯,
<context:component-scan base-package="com.luv2code.springdemo"/>로 component를 Spring이 스캔할 패키지만 xml에 파일에 등록하여 주면, bean을 spring이 뒤에서 자동으로 등록시켜 주는것을 알 수 있다.
2. Spring Annotation - Dependency Injection
지난 xml을 통한 dependency injection을 했을때와 마찬가지로, Coach interface는 dailyFortuneService()를 제공하기 위해 새로운 helper인 fortuneService 인터페이스를 만든다(이것이 dependency)
(1) Spring autowiring이란?
Dependency injection을 위해서, Spring은 autowiring을 사용할 수 있는데, Spring이 해당 property에 맞는 클래스를 찾아서 자동으로 injection을 시켜주는 기능이다. 따라서 auto wired되는것이다.
xml 코드를 통해서 bean을 만들고 setter나 constructor injection 통해서 직접 property에 ref로 해당 bean을 넘겨주었어야 했다. 하지만 @Autowired annotation을 통해서 spring이 자동으로 dependency를 찾아서 injection 시켜준다.
1) Autowiring 예시
① Coach implementation에 FortuneService interface를 inject 시킬 것이다.
② 그러면 Spring이 @Component를 스캔할 것이다.
③ Spring이 FortuneService interface를 implement 하고있는것을 찾는다.
④ 있다면 그것을 찾아서 inject 시킨다.
2) Autowiring Injection Types
① Constructor Injection
② Setter Injection
③ Field Injection
(2) Constructor Injection Development Process
① Define the dependency interface and class
(FortuneService interface 만들고 HappyFortuneService를 상속받는 클래스로 만든다음 @Component 기입)
② Create constructor in your class for injection
(TennisCoach에 Constructor통해서 dependency를 넘긴다.)
③ Configure the dependency injection with @Autowired Annotation
(constructor위에 @Autowired라고 적는다. 이것이 핵심)
-> 알아서 spring이 dependency 찾아서 주입도 해주고 @Component를 찾아서 자동으로 bean도 생성해 주기 때문에 조립할 필요가 없어진다.
* 코드 예시)
private FortuneService fortuneService;
// constructor injection
@Autowired
public TennisCoach(FortuneService thefortuneService) {
fortuneService = thefortuneService;
}
TennisCoach 클래스에 다음과 같이 injection 시켜줄 인터페이스를 가지고와서 constructor를 통해 parameter로넘겨주는것은 xml 파일과 동일한데, 따로 xml 파일에 bean을 등록하고 ref로 injection시켜줄 필요없이 @Autowired를 적어주면 FortuneService 인터페이스를 implement 받고 있는 객체를 자동으로 등록시켜 준다.
implement 받고 있는 객체가 여러개일때는 app 실행시 NoUniqueBeanDefinitionException이라는 예외가 발생하며 @Component로 bean에 등록되어 연결 될 수 있는 bean list 또한 보여준다.
이럴때는 @Qualifier("bean name")을 통해 다음과 같이 문제를 해결 할 수 있다.
private FortuneService fortuneService;
// constructor injection
@Autowired
public TennisCoach(@Qualifier("happyFortuneService")FortuneService thefortuneService) {
fortuneService = thefortuneService;
}
(3) Setter Injection Development Process
① Create setter method in your class for injections
② Configure the dependency injection with @Autowired Annotation
* Setter method 뿐만 아니라 다른 어떠한 method라도 주입가능하다. @Autowired만 적어 주면 된다.
* 코드 예시)
private FortuneService fortuneService;
//define a setter method
@Autowired
@Qualifier("happyFortuneService")
public void doSomeCrazyStuff(FortuneService fortuneService) {
System.out.println(">> TennisCoach : inside doSomeCrazyStuff() method");
this.fortuneService = fortuneService;
}
위 코드는 setsetFortuneService를 doSomeCrazyStuff로 이름을 바꾸어 준것인데, 볼수 있듯이 메소드 이름은 중요 하지 않고, Autowired로 통해 Spring이 자동으로 injection 시켜주는것을 확인할 수 있다.
마찬가지로 FortuneService를 implement받는 bean이 여러개일 때, @Qualifier("bean name")을 위에 써줌으로서 특정 bean을 injection 시킬 수 있다.
(4) Field Injection Development Process
① Configure the dependency injection with Autowired annotation
- applied directly to the field
- no need for setter methods
1) Field Injection이란 :
dependencies를 class의 필드 값에 세팅해줌으로서 직접적으로 inject시키는 방법(심지어 private 필드도 가능하다)
Java reflection이라는 기술을 사용해 behind the scene에서 일어난다.
FortunService field를 setter method나 constructor, method로 injection을 하지 않고 필드 그 자체로 주입시킬수 있다.
* 코드 예시)
@Autowired
@Qualifier("happyFortuneService")
private FortuneService fortuneService;
간단하게 이렇게 필드 명위에 @Autowired를 써줘도 Java reflection이라는 방법때문에 넘어간다.
또한 @Qualifier("bean name")을 통해서 어떤 bean을 injection시킬지 특정 지을 수 있다.
이렇게 @Autowired annotation을 통해 dependency injection을 할 수 있는 세 가지 방법을 알아보았다.
그럼 어떤 걸 써야 할까?
-> 어떤게 더 낫다고 할 수는 없다. 그냥 편한대로 쓰되, 프로젝트에서 일관성있게 쓰면 된다고 한다.
'Programming > Spring & Hibernate' 카테고리의 다른 글
Spring Configuration with Java code (0) | 2021.01.31 |
---|---|
Bean Scope Annotation & Bean Life Cycle (0) | 2021.01.31 |
Spring Bean Scope and Life Cycle (0) | 2021.01.28 |
Dependency Injection(DI) - Setter Injection & injecting literal value (0) | 2021.01.27 |
Dependency Injection(DI) - Constructor Injection (0) | 2021.01.26 |
- Total
- Today
- Yesterday