Spring Ioc @Component
포스트
취소

Spring Ioc @Component

우리는 앞에서 xml 방식이 아닌 어노테이션 방식으로 설정 파일을 만들어 IoC 컨테이너에 Bean 을 주입하는 방식에 대해서 기술을 했습니다 이제는 IoC 컨테이너에 직접 넣지도 않고 기동 시 알아서 읽는 방법에 대해서 기술하겠습니다

ApplicationContext 는 없어도 된다

1
2
3
4
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfig.class);
ClassRoomA roomA = applicationContext.getBean(ClassRoomA.class);

사실 bean 을 생성하고 불러올 때부터 ApplicationContext 코드는 처음부터 필요 없었습니다 단지 이 코드를 쓴 이유는 우리가 만들어진 Bean 들이 IoC 컨테이너에 들어간다는 것을 보여주기 위함이었습니다 실제로 @Bean 태그를 쓴 이후부터는 아래와 같이 작성할 수 있습니다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@SpringBootApplication
public class SpringRestart2Application implements ApplicationRunner{
	
	@Autowired
	private ClassRoomA classRoomA;

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

	@Override
	public void run(ApplicationArguments args) throws Exception {
		

		classRoomA.classRoomAInStudent();
				
	}
}

사실 이렇게만 쓰더라도 우리가 원하는 bean 객체를 계속해서 불러올 수 있습니다 SpringBoot 환경이라서 좀 그렇게 보일 수 있지만 실제로는

1
2
3
4
@Autowired
private ClassRoomA classRoomA;

이 코드만 있으면 IoC 컨테이너에서 ClassRoomA라는 객체를 가져와서 주입을 받게 됩니다 그러한 역할을 하는 어노테이션은 @Autowired 즉 앞에서 @Configuration이라는 어노테이션 단 클래스 파일을 만들고 그 아래 @Bean이라는 정의서를 만들게 되면 이들은 애플리케이션이 기동이 될 때 자동으로 IoC 컨테이너로 들어가서 bean 이 됩니다 그리고 외부에서 필요한 곳에 주입을 해줄 때에는 @Autowired를 통해서 주입을 하게 되면 IoC 컨테이너가 적절한 bean 객체를 찾아서 주입을 하게 되고 우리는 그 주입된 bean 객체를 사용할 수 있게 됩니다 이와 더불어서 사용할 수 있는 어노테이션은 바로 @Component입니다 이것도 @Bean 태그와 마찬가지로 Bean 객체를 만들 때 사용하지만 사용하는 위치가 조금 다릅니다

@Component

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@Component
public class Student {
	
	private String name;
	
	private int age;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + "]";
	}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Component
public class ClassRoomA {
	
	private Student student;
	
	@Autowired
	public ClassRoomA(Student student) {
		
		student.setName("Time");
		student.setAge(20);
		
		
		this.student = student;
		
	}
	
	public void classRoomAInStudent() {
		
		System.out.print(student.toString());
	}
}

자 우리는 다른 방법으로 Bean 을 만들었다 앞에서는 메서드 위에 @Bean 붙이면서 이 메서드는 객체를 반환하니 이를 bean 객체로 만들어주세요 했다면 이제는 Class 상단에 @Component를 붙여서 이 Class는 bean 객체로 만들어주세요 하고 있습니다 그리고 이때 ClassRoomA는 외부에서 Student 객체를 주입을 받아야 하므로 @Autowired 사용했습니다

우리는 점점 bean 객체를 생성하는 코드가 추상화되는 것을 보고 있습니다 IoC의 단점 중 하나가 학습곡선이 높다는 것과 추상화가 너무 크다는 게 단점입니다 처음에는 bean.xml로 bean 을 정의해서 읽게 시키면서 bean 이 어떻게 생기는 것을 보았지만 어노테이션을 활용함으로써 점점 bean 정의 파일은 없어지고 간단한 어노테이션 몇 가지로 bean 을 정의하고 있는 모습을 볼 수 있습니다

자 그럼 여기서 궁금한 점은 우리가 앞에서 IoC 컨테이너를 직접 불러서 사용할 때에는 어떤 bean 을 가지고 와야 하는지 정확히 표현을 했습니다 ClassRoomA roomA = applicationContext.getBean("classRoomA" , ClassRoomA.class); 이렇게 getBean이라는 메서드를 사용할 때 ClassRoomA.class의 bean 타입을 가져오라고 했습니다 다만 지금 보면 @Autowired 가 적혀만 있지 위에처럼 명시하는 것도 찾는 걸까 사실 여기엔 이미 IoC 메커니즘이 동작을 하고 있습니다 기본적으로 @Autowired는 타입을 보고 찾습니다 그것이 무슨 말이냐

우리는 앞에서 ClassRoomA , Student 타입의 bean 을 정의했습니다 이때 Bean 을 만드는 전략 중 하나인 동일한 이름의 Bean 은 만들 수 없다는 것입니다 예를 들어서 우리가 위치가 다른 곳에 동일한 Student 파일을 만든 뒤 그것을 Bean으로 해서 기동하는 순간

1
2
Annotation-specified bean name 'student' for bean class [com.cybb.main.main1.Student] conflicts with existing, non-compatible bean definition of same name and class [com.cybb.main.Student]

이렇게 이미 존재하는 Studen 이름의 bean 이 존재하기 때문에 이 bean 은 생성할 수 없습니다 그래서 기동하다가 시스템이 멈추게 됩니다 그래서 이름이 동일한 bean 은 만들 수가 없게 됩니다 이 정책을 근거로 IoC 이는 이름은 유일하고 이제 타입만 살펴보면 되기 때문에 주입하려는 대상의 이름 그리고 타입을 분석해서 가장 적절한 bean 을 주입해 주게 됩니다