우선 컨테이너란 무엇인지부터 간단하게 알고 넘어가자.
컨테이너는 우리가 생각하듯, 무언가가 담겨있는 넓은 공간이다.
IT에서는 딱히 이거다!라는 정확한 정의는 없지만,
"무언가를 모아놓고 여러 기능을 수행하는 논리적인 공간"이란 의미로 생각하면 된다.
때문에 컨테이너는 프레임워크만의 특징이 아니며, 다른 것들도 가지고 있는 개념이다.
그대로 번역하면 "제어의 역전"이라는 의미이며, 객체나 메소드의 생성주기를 컨테이너가 관리해주는 것을 말한다.
즉 프로그램의 흐름을 컨테이너가 관리해주는 것이다.
JAVA를 예시를 들어보자.
User에게 Team을 설정하는 코드를 짠다고 해보자.
class User {
private String name;
private String Team team;
/* getter/setter 메소드들 */
}
class Team {
private name;
/* getter/setter 메소드들 */
}
// 일일히 다 적어줘야 함
public static void main(String[] args) {
User user = new User();
Team team = new Team();
}
객체도 생성하고, setter로 설정도 하는 등 개발자가 모든 것을 다 해줘야 했다.
하지만 프레임워크를 쓰면 그럴 필요가 없어진다.
@Bean
class User {
private String name;
private String Team team;
/* getter/setter 메소드들 */
public setTeam(Team team) {
this.team = team;
}
@Bean
class Team {
private name;
/* getter/setter 메소드들 */
}
public static void main(String[] args) {
/* 아무것도 안해도 됨ㅇㅇ */
}
저 @Bean으로 객체가 컨테이너에 빈으로 등록된다.
빈으로 등록된 객체는 컨테이너가 알아서 처리해주므로, 우린 신경쓸 것이 없다.
객체를 생성하고, 관계를 맺는 등의 역할은 모두 프레임워크가 다 해준다. 개발자는 로직에만 집중하면 되는 것이다.
이것을 프로그램의 흐름 즉, 제어가 개발자->프레임워크로 넘어갔다고 하여, 제어의 역전이라고 부른다.
의존성 주입이란 뜻으로, IoC와 엮어서 IoC/DI라고 한다.
의존성 주입은 위에서 살펴본 Setter 메소드와 같다.
class User {
private String name;
// 의존성을 가짐
private String Team team;
/* getter/setter 메소드들 */
public void setTeam(Team team) {
this.team = team;
}
}
class Team {
private name;
/* getter/setter 메소드들 */
}
public static void main(String[] args) {
User user = new User();
Team team = new Team();
// 의존성 주입
user.setTeam(team);
}
User가 Team을 속성으로 가지고 있는 것을 "의존성을 지닌다"라고 하고,
user의 setTeam으로 Team 속성을 정의해주는 것을 "의존성 주입"이라고 한다.
스프링 프레임워크는 위와 같은 DI를 지원해준다.
public static void main(String[] args) {
User user = new User();
Team teamA = new Team();
// teamB로 바꾸고 싶음
user.setTeam(teamA);
}
지금은 팀A를 DI하고 있지만, 팀A가 아닌 팀B를 DI하고 싶을 수도 있다.
그렇다면 teamA를 지우고 teamB라는 객체를 생성해야 할 것이고, 소스코드를 수정해야 한다.
위의 코드는 짧아서 그렇지, 만약에 몇백~천줄이 되는 코드라면 답도 없을 것이다.
스프링은 위와 같은 비효율적 DI를 알아서 해준다.
@Bean
class User {
// 자동 DI
@Autowired
private String Team team;
// 알아서 Team 빈을 찾아서 주입해 줌
public void setTeam(Team team) {
this.team = team;
}
}
@Bean
class Team {
/* getter/setter 메소드들 */
}
public static void main(String[] args) {
/* Setter 메소드 안써도 됨
}
@Autowired로 인해, 빈으로 등록된 Team을 찾아서 Setter에 자동으로 넣어진다.
이렇게 자동으로 이뤄지면서 코드는 훨씬 간결해지고,
복잡한 의존 관계를 개발자가 작성할 필요가 없어졌다.
이번 편에서는 컨테이너와 IoC/DI에 대해 간략히 알아보았다.
다음 편에선 Spring 관점으로 지원하는 컨테이너의 종류와
DI 종류에 대해 자세히 알아보도록 하겠다.
이어서>>