Spring DI 흉내내기

 

1 - 1) 변경에 유리한 코드

다형성을 이용하면 변경 Point가 적어져서 코드를 작성할 때 실수가 줄어들고, 코드의 활용과 수정이 편리해진다.

 

1 - 2) 변경에 유리한 코드

Map, 외부 파일 등을 활용하여 클래스의 정보를 저장하고

필요할 때 파일의 정보를 가져와서 객체를 생성할 수 있다.

만약 객체의 정보가 변해도 파일 안의 객체 정보만 가져오기 때문에, 객체를 생성하는 코드는 수정하지 않아도 된다.

 

2) 객체 컨테이너(ApplicationContext)

ApplicationContext라는 객체 저장소를 만든다.

외부파일에 저장된 클래스의 정보를 이용해서 객체를 생성하고

ApplicationContext에 Map의 형태로 저장할 수 있다.

 

3) 자동 객체 등록하기 - Component Scanning

ApplicationContext에 직접 객체를 만들어서 저장할 수도 있지만

Component 애너테이션(@Component)가 붙어있는 클래스의 객체를 자동으로 생성하여 저장할 수도 있다.

 

4) 객체 찾기 - by Name, by Type

기존의 방법은 Map에 저장된 key의 name으로 객체를 생성했다면, => getBean("car")  // (byName)

Class의 타입으로 객체를 생성할 수도 있다. (byType)

 

Class 타입을 입력하면 map에 저장된 모든 객체들을 하나씩 꺼내서

입력했던 Class와 같은 클래스 타입이면 그 객체를 반환한다.

 

5 - 1) 객체를 자동 연결하기 - @Autowired (by Type)

객체 저장소에 저장된 객체가 @Autowired 가 붙은 참조변수에 주입된다.

(@Autowired 를 사용하려면 config.xml 파일에 <context: annotation-config/> 를 입력해야 한다)

 

5 - 2) 객체를 자동 연결하기 - @Resource (by Name)

@Resource(name="engine") Engine engine; 는

@Resource Engine engine; 과 같다.

 

name을 생략하면 클래스의 첫 글자를 소문자로 바꿔서 engine에 해당하는 객체의 주소를 저장하게 된다

생략하지 않고 특정 Name에 해당하는 객체의 주소를 저장할 수도 있다

 

@Resource(name="engine2") Engine engine;

-> engine2라는 이름을 가진 Engine객체의 주소를 engine에 저장하게 된다.

 

 

Spring DI 활용하기 - 실습

 

config.xml 파일을 src/main/resources 에 만들고

클래스의 이름과 정보를 작성하여 bean으로 등록한다.

<bean id="car" class="com.fastcampus.ch3.Car" scope="prototype"/>

(scope를 prototype으로 하면 매번 객체를 생성할 때마다 새로운 객체를 생성하며, 기본값인 singleton으로 하면 똑같은 객체를 생성하게 된다)

 

<bean id="car2" class="com.fastcampus.firstSpring.Car2">
    <property name="color" value="red"/>
    <property name="oil" value="100"/>
    <property name="engine" ref="engine"/>
    <property name="doors">
        <array value-type="com.fastcampus.firstSpring.Door">
            <ref bean="door"/>
            <ref bean="door"/>			
        </array>
    </property>
</bean>

<bean id="engine" class="com.fastcampus.firstSpring.Engine"/>
<bean id="door" class="com.fastcampus.firstSpring.Door" scope="prototype"/>

beans 태그 안에 <property> 태그를 삽입하여 iv값을 넣어줄 수 있다.

(클래스 내부에 setter 메서드가 정의되어 있어야 property 태그를 사용 가능)

 

 

또는 <constructor-arg> 태그(생성자)를 이용해서 iv값을 초기화 할 수 있다(클래스 내부에 생성자 코드가 있어야 가능)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
	<bean id="car2" class="com.fastcampus.firstSpring.Car2">
		<constructor-arg name="color" value="red"/>
		<constructor-arg name="oil" value="100"/>
		<constructor-arg name="engine" ref="engine"/>
		<constructor-arg name="doors">
			<array value-type="com.fastcampus.firstSpring.Door">
				<ref bean="door"/>
				<ref bean="door"/>			
			</array>
		</constructor-arg>
	</bean>
		
	<bean id="engine" class="com.fastcampus.firstSpring.Engine"/>
	<bean id="door" class="com.fastcampus.firstSpring.Door" scope="prototype"/>
	

</beans>

(기본 생성자를 항상 만들어주자)

 

 

@Component 를 이용해서 bean으로 등록하려면 다음과 같은 코드를 config.xml 파일에 패키지를 지정하여 추가한다.

<context:component-scan base-package="com.fastcampus.ch3"/>

com.fastcampus.ch3 패키지에 있는 모든 클래스중에서

Component 애너테이션이 있는 클래스들의 객체를 bean으로 등록해준다.

 

 

@Autowired는 타입으로 먼저 검색하여 여러 후보가 나오면 타입의 첫 글자를 소문자로 하여,

참조변수의 이름과 일치하는 곳에 객체를 주입한다.

또는 @Qualifier에 특정 Name을 넣어서, 타입으로 검색하여 여러 후보가 나왔을 때 특정 Name을 가진 참조변수에게

객체를 주입해줄 수 있다.

 

 

객체를 주입해주는 애너테이션 중, 

@Autowired는 Type으로 찾아서 객체를 넣어주고

@Resource는 Name으로 찾아서 객체를 넣어주는데

 

일반적으로 @Autowired를 많이 사용한다.

클래스의 Type은 잘 변하지 않고, 상대적으로 Name은 바뀌기 쉬우며 오타 실수가 생기기도 쉬움.

 

 

Spring DI 활용하기 - 이론

 

- 빈(Bean)

 

JavaBeans - 재사용 가능한 컴포넌트, 상태(iv), getter&setter, no-args constructor

JavaBeans가 현재의 Spring Bean으로 발전함

Spring Bean - 단순하고 독립적이며, Spring container가 관리하는 객체이다.

Spring container - Bean 저장소이다. Bean을 저장, 관리(생성, 소멸, 연결) 한다.

 

BeanFactory는 Bean 생성, 연결 등의 기본기능을 정의해놓은 인터페이스인데,

ApplicationContext는 BeanFactory를 확장해서 여러 기능을 추가 정의한 것이다.

ApplicationContext의 일부가 Spring container이다.

 

ApplicationContext의 종류로는 XML과 Java Config(자바 코드)가 있는데,

XML은 text로, Java Config는 애너테이션으로 bean을 관리함.

 

 

- Root AC와 Servlet AC

 

web.xml 파일을 보면 

ContextLoaderListener에 의해 Root AC와 Servlet AC가 생성된다는 것을 확인할 수 있다.

Root AC(부모 AC)에는 공통으로 사용하는 Bean(web과 상관없는 빈, DB같은)을 등록하고

Servlet AC(자식 AC)에는 각 모듈에서 사용하는 Bean을 등록한다.

 

자식 XmlWebApplicationContext(AC)은 부모를 참조하고 있음.

자식 XmlWebApplicationContext(AC)에서 Beans를 먼저 찾고,

없으면 부모 XmlWebApplicationContext에서 Beans를 찾게됨.

 

- IoC와 DI

Inversion of Control(제어의 역전) : 제어의 흐름이 전통적인 방식(내가 만든 코드에서 다른 사람이 만든 코드를 호출)

에서 그 반대로 뒤바뀌는 것(다른 사람이 만든 코드에서 내가 만든 코드를 호출)

이 경우에 DI가 일어남.

 

Dependency Injection(의존성 주입) : 사용할 객체를 외부에서 주입받는 것을 의미.

즉, 다른 사람이 만든 코드에서 내가 만든 객체를 사용하게 됨.

 

 

- @Autowired (byType)

인스턴스 변수(iv), setter, 참조형 매개변수를 가진 생성자, 메서드에 적용이 가능하다.

생성자가 클래스에 단 하나일 경우 @Autowired는 생략이 가능함.

(iv에 직접 주입하는 것 보다 생성자를 통해 주입하는 것을 권장함)

 

Autowired는 원래 단 하나의 객체가 주입이 되어야 하지만(주입이 되지 않으면 에러 발생)

required=false를 주면 객체가 주입이 되지 않아도 에러가 발생하지 않으며

배열에 Autowired로 객체를 주입하는 경우엔 2개 이상의 객체도 주입이 가능하다.

 

 

- @Resource (byName)

 

Spring Container에서 이름으로 빈을 검색해서 참조 변수에 자동 주입(DI)

일치하는 이름의 빈이 없으면, 예외 발생

 

name을 따로 주지 않으면 참조변수의 이름을 name으로 사용함.

 

 

 - @Component

 

<component-scan>으로 @Component가 클래스를 자동 검색해서 빈으로 등록함.

@Component는 @Controller, @Service, @Repository, @ControllerAdvice의 메타 애너테이션이다.

 

<context:component-scan base-package="com.fastcampus.ch3"/> 로 하위 패키지까지 전부 컴포넌트를 찾아서 빈으로 등록함.

 

 

- @Value & @PropertySource

 

@Value 애너테이션으로 기본형 값을 직접 설정해 줄 수 있고

환경변수의 값을 불러와서 사용할 수도 있다.

@PropertySource와 같이 활용하여 properties 파일에서 값을 불러올 수도 있음.

 

 

- <property>, <constructor-arg>를 이용한 빈 초기화

 

<property>를 이용한 빈 초기화는 setter를 이용한다.

코드에서 직접 값을 세팅하는 대신에 xml 파일에서 <property> 태그를 이용해서 초기화 해준다.

setter 메서드가 정의되어 있어야 가능함.

 

<constructor-arg>를 이용한 빈 초기화. 생성자가 정의되어 있어야 함.

코드에서 직접 값을 세팅하는 대신에 xml 파일에서 <constructor-arg> 태그를 이용해서 초기화 해준다.

 


출처 : 스프링의 정석 - 남궁성과 끝까지 간다

+ Recent posts