Spring DI Container 공부 해놓고 정리 안 해놓으니 이틀만에 까먹는 나를 위해 작성하는 블로그
1. Dependency Injection
2. DI Container
3. Spring DI Container
하나의 객체를 생성 또는 사용하기 위해 다른 객체에 의존하고 있을 때 우리는 의존성을 가진다고 한다. 의존성을 가지는 객체의 경우 의존하고 있는 객체의 코드가 수정되었을 때 영향을 받게 된다. 이 영향을 최대한 줄이기 위해 우리는 외부에서 객체를 생성하여 주입해줄 수 있다.
// 주입 전
public class Student {
private Person person;
public Student (int ssn) {
person = new Person(ssn);
}
}
// main
public static void main() {
int ssn = 12456;
Student student1 = new Student(ssn);
// 주입 후
public class Student {
private Person person;
public Student (Person person) {
this.person = person;
}
}
// main
public static void main() {
int ssn = 12456;
Person person = new Person(ssn);
Student student1 = new Student(person);
}
이전의 사례에서는 Student 클래스가 Person 클래스와 강하게 coupling이 되어 있다. Person 클래스를 생성할 때 따라서 Person 객체를 주입함으로써 Student 클래스와 Person 클래스의 의존성을 decoupling 시킬 수 있다.
하지만 이제 main 함수에서 Person과 Student 클래스 둘다 생성해서 관리해야하기 때문에 Person에 대한 의존성이 Student 클래스에서 main 함수로 옮겨진 것이지 없어진 것이 아니다.
위의 사례처럼 의존성을 옮기는 대신 여러 의존성들을 하나의 Class로 모아주면 의존성을 쉽게 관리할 수 있다. 의존성을 관리해주는 Class를 DI Container이라고 한다.
DI Container는 이 의존성 관리를 쉽게 구현할 수 있도록 구성되어 있다. 다음과 같이 DI Container를 정의할 수 있다.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
public Person person() {
return new person();
}
@Bean
public Student student() {
return new Student(person());
}
}
@Configuration annotation을 가지고 있는 AppConfig 클래스에서 우리는 모든 의존성을 관리할 수 있다. AppConfig 내부에서는 각 객체의 instance를 반환하는 함수들을 구현한다.
각 함수에 @Bean이라는 annotation을 달아준다. 각 Bean은 Singleton이 유지되며 이 경우 Student 객체를 여러번 호출하더라도 같은 Student 객체가 반환되며 Student 객체에 주입된 의존성인 Person도 매번 동일한 Person 객체가 반환되게 된다.
위의 Dependency Injection은 Servlet에서 다음과 같이 사용할 수 있다.
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
// Servlet 선언 생략
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
Student student = applicationContext.getBean(Student.class);
student.study();
}
AnnotationConfigApplicationContext을 통해 ApplicationConfig 파일을 가져오고 getBean()을 통해 해당 config 내부에 선언되어있는 Bean을 가져올 수 있다.
하지만 우리의 Spring은 이보다도 더 간단하게 DI Container를 구현할 수 있도록 해준다. 이제
AnnotationConfigApplicationContext와AppConfig또한 필요가 없어진다.
@Autowired annotation을 사용함으로써 우리는 간단하게 Bean을 생성하고 사용할 수 있다
이전의 Student 예제를 @Autowired를 사용하여 바꿔보자.
먼저 AppConfig class는 더 이상 필요가 없다.
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
// Servlet 선언 생략
private Student student;
@Autowired
public Student(Student student) {
this.student = student;
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
student.study();
}
AnnotationConfigApplicationContext를 더 이상 호출하지 않고 Servlet Class에서 @Autowired annotation을 달아준 Student constructor를 선언함으로써 쉽게 Bean을 선언할 수 있다. 아래에서 student 객체를 일반 객체를 사용하는 것처럼 불러주기만 해도 자동적으로 Bean을 사용하게 된다.
정보 감사합니다.