Spring Ioc @Bean
포스트
취소

Spring Ioc @Bean

우리는 앞에서 xml 을 통한 bean 정의서를 만들고 그것을 IoC 컨테이너에 주입하는 방식으로 진행을 했다 이때 xml bean 정의서의 가장 큰 단점 중 한 가지는 바로 오타 또는 기타 오류 검증이 안된다는 단점이 있다 다시 앞의 bean.xml 파일을 보자

bean.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8"?>
  <beans xmlns="http://www.springframework.org/schema/beans"
	  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	  xmlns:context="http://www.springframework.org/schema/context"
	  xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
		
	  	<bean id = "student" class="com.cybb.main.Student">
	  		<property name="name" value="time"/>
	  		<property name="age" value="20"/>
	  	</bean>
	  	
	  	<bean id = "classRoomA" class="com.cybb.main.ClassRoomA">
	  		<constructor-arg ref = "student"/>
	  	</bean>
    </beans>

이때 이 이 태그에서 오류를 한 가지라도 발생하면 xml 파일을 읽지 못하거나 bean 을 생성하지 못합니다 단적인 예로 <bean id = "student" class="com.cybb.main.Student">에서 class를 오타를 내어서 <bean id = "student" class="cOm.cybb.main.Student"> 이렇게 bean 생성될 위치를 올바르게 명시하지 못하면 오류가 발생하게 됩니다

그래서 나온 게 java 어노테이션 기반의 bean 정의가 등장을 하게 됩니다

어노테이션 기반

어노테이션은 기본적으로 @로 시작하는 java 명령어입니다 이 어노테이션은 소스 안에 이 어노테이션을 붙였을 시 어떤 행동을 하라는 정의가 이미 소스 안에 다 만들어져 있기 때문에 그냥 바로 가져다 쓰면 됩니다

애노테이션 기반 bean 생성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Configuration
public class BeanConfig {
	
	@Bean
	public Student student() {
		
		Student student = new Student();
		student.setName("time");
		student.setAge(20);
		
		return student;	
	}
	
	@Bean
	public ClassRoomA classRoomA() {
		
		ClassRoomA classRoomA = new ClassRoomA(student());
		
		return classRoomA;
	}

}


이렇게 java 기반으로 bean 객체 정의서를 만들 수 있습니다 이때 @Configuration 이 클래스 파일은 bean 설정 파일이라는 것을 명시해 줍니다 그리고 각 bean 이 될 애들에 대해서는 @bean 어노테이션을 붙여서 이를 Ioc 가 관리하는 bean 객체가 되는 것입니다 자 그럼 이들을 불러오는 방법은 아래와 같다

어노테이션 기반 bean 을 Ioc 컨테이너에 담는 방법

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

우리는 앞에서 ClassPathXmlApplicationContext 로 bean.xml 파일을 읽었다면 이제는 다른 구현체 AnnotationConfigApplicationContext를 사용해서 Ioc 컨테이너에 bean 을 담게 됩니다 이 이후는 앞의 내용과 동일함으로 생략을 할 텐데 여기서 궁금증이 생길 것입니다

@Bean 태그가 있는것과 없는것의 차이점

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Bean
public Student student() {
	
	Student student = new Student();
	student.setName("time");
	student.setAge(20);
	
	return student;
	
}


public Student student() {
	
	Student student = new Student();
	student.setName("time");
	student.setAge(20);
	
	return student;
	
}

이 두 개의 소스는 어찌 보면 위에 @Bean 어노테이션 차이 말고는 하는 역할은 똑같습니다 하지만 이 객체가 어디로 들어가냐에 따라서 그 이후 상황은 완전히 달라지게 됩니다 @Bean 태그가 붙은 객체는 Ioc 컨테이너에서 관리가 되고 그게 없는 객체는 그냥 GC(Garbage Collection)에서 관리가 될 것입니다 그리고 당장 눈에 볼 수 있는 차이점은 @Bean 이 붙은 객체는 여러 번 호출해도 단 하나의 객체가 계속해서 반환이 되고 (Bean 생성 전략) 그렇지 않은 객체는 계속해서 새로운 객체를 생성할 것입니다 그를 비교할 수 있는 코드는 아래와 같습니다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfig.class);
ClassRoomA roomA = applicationContext.getBean(ClassRoomA.class);

Student student1 = applicationContext.getBean(Student.class);
Student student2 = applicationContext.getBean(Student.class);
Student student3 = applicationContext.getBean(Student.class);

BeanConfig beanConfig = new BeanConfig();

Student student4 = beanConfig.student();
Student student5 = beanConfig.student();
Student student6 = beanConfig.student();

System.out.println(student1.hashCode());
System.out.println(student2.hashCode());
System.out.println(student3.hashCode());

System.out.println(student4.hashCode());
System.out.println(student5.hashCode());
System.out.println(student6.hashCode());

hashCode는 객체를 구별할 때 유용하게 쓰일 수 있으며 같은 값을 반환하는 객체는 동일한 객체임을 알려줍니다 즉 Ioc 컨테이너에서 꺼내는 모든 객체는 동일한 객체를 나타냅니다 단 student 직접 호출한 4 5 6 객체는 전부 새로운 객체를 생성하기에 이들을 서로 다른 객체입니다