context 네임스페이스 설정

어노테이션 설정을 하려면 스프링 설정파일의 루트 엘리먼트인 <beans>에 Context 관련 네임스페이스와 스키마 문서의 위치를 등록해야 한다.

 

xmlns:context="http://www.springframework.org/schema/context" 

http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd"

<?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:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context" 
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
			http://www.springframework.org/schema/context
			http://www.springframework.org/schema/context/spring-context-4.2.xsd">
	
</beans>

 

컴포넌트 스캔(component-scan) 설정

스프링 설정파일에 사용할 객체들을 <bean> 등록하지 않고 자동으로 생성하려면 <context:component-scan/> 엘리먼트를 사용해야 한다.

이 설정을 추가하면 스프링 컨테이너는 클래스 path에 있는 클래스들을 스캔하여 @Component가 설정된 클래스들을 자동으로 객체 생성한다.

<?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:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context" 
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
			http://www.springframework.org/schema/context
			http://www.springframework.org/schema/context/spring-context-4.2.xsd">
	
	<!-- Context nameSpace 추가, 해당 Package class에 @Component 선언해야함! -->
	<context:component-scan base-package="polymorphism"></context:component-scan>
</bean>

 

@Component

스프링 설정파일에 <context:component-scan> 설정을 했다면. 사용할 객체의 클래스 선언부 위에 @Component 를 설정하면 된다.

package polymorphism;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
public class LgTV implements TV {
	public LgTV() {
		System.out.println("===> LgTV 객체 생성");
	}
}

 

그러나 위에 코드는 클라이언트 프로그램에서 LgTV 객체를 요청할 수는 없다.

클라이언트가 스프링 컨테이너가 생성한 객체를 요청하려면, 요청할 때 사용할 아이디나 이름이 반드시 설정되야함!

→ @Component("tv")

public class TVUser {

	public static void main(String[] args) {
		// 1. Spring 컨테이너를 구동한다.
		AbstractApplicationContext factory = new GenericXmlApplicationContext("root-context.xml");

		// 2. Spring 컨테이너로부터 필요한 객체를 요청(Lookup)한다.
		TV tv = (TV) factory.getBean("tv");
    }
}
package polymorphism;

import javax.annotation.Resource;
import org.springframework.stereotype.Component;

@Component("tv")
public class LgTV implements TV {
	public LgTV() {
		System.out.println("===> LgTV 객체 생성");
	}
}

 

@Autowired

@Autowired 는 생성자나 메소드, 멤버변수 위에 모두 사용할 수 있음

주로 멤버변수 위에 선언하여 사용함

스프링 컨테이너는 멤버 변수 위에 붙은 @Autowired 를 확인하는 순간 해당 변수의 타입을 체크한다. 그리고 그 타입의 객체가 메모리에 존재하는지를 확인한 후에, 그 객체를 변수에 주입한다.

 

만약 @Autowired 가 붙은 객체가 메모리에 없다면 스프링 컨테이너는 NoSuchBeanDefinitionException을 발생시킨다.

package polymorphism;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component("tv")
public class LgTV implements TV {
	@Autowired
	private Speaker speaker;
	
	public LgTV() {
		System.out.println("===> LgTV 객체 생성");
	}

	public void powerOn() {
		System.out.println("LgTV---전원 켠다.");
	}

	public void powerOff() {
		System.out.println("LgTV---전원 끈다.");
	}
	
	public void volumeUp() {
		speaker.volumeUp();
	}

	public void volumeDown() {
		speaker.volumeDown();
	}
}
package polymorphism;

public interface Speaker {
	void volumeUp();
	void volumeDown();
}
package polymorphism;

import org.springframework.stereotype.Component;

@Component("sony")
public class SonySpeaker implements Speaker{
	public SonySpeaker() {
		System.out.println("===> SonySpeaker 객체 생성");
	}

	public void volumeUp() {
		System.out.println("SonySpeaker---소리 올린다.");
	}

	public void volumeDown() {
		System.out.println("SonySpeaker---소리 내린다.");
	}
}

 

@Qualifier

문제는 의존성 주입 대상이 되는 Speaker 타입의 객체가 두개 이상일 때 발생한다.

만약 SonySpeaker와 AppleSpeaker 객체가 모두 메로리에 생성되어 있는 상황이라면, 스프링 컨테이너는 어떤 객체를 할당할지 스스로 판단할 수 없어서 에러를 발생시킨다.

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: (생략~)
expected single matching bean but found 2 : apple, sony

위와 같은 상황일 때, @Qualifier 어노테이션을 이용하면 의존성 주입될 객체의 아이디나 이름을 지정할 수 있는데, 이때 Speaker 객체의 이름(sony, apple) 중 사용할 하나를 지정한다.

 

package polymorphism;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component("tv")
public class LgTV implements TV {
    @Autowired
    @Qualifier("sony")
    private Speaker speaker;
	
	public LgTV() {
		System.out.println("===> LgTV 객체 생성");
	}

	public void powerOn() {
		System.out.println("LgTV---전원 켠다.");
	}

	public void powerOff() {
		System.out.println("LgTV---전원 끈다.");
	}
	
	public void volumeUp() {
		speaker.volumeUp();
	}

	public void volumeDown() {
		speaker.volumeDown();
	}
}

 

어노테이션과 XML 설정 병행하여 사용하기

변경되지 않는 객체는 어노테이션으로 설정하고, 변경될 가능성이 있는 객체는 XML 설정으로 사용한다.

 - 변경되지 않는 객체 : LgTv.java

 - 변경될 가능성이 있는 객체 : SonySpeaker.java, AppleSpeaker.java

package polymorphism;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component("tv")
public class LgTV implements TV {
    @Autowired
    private Speaker speaker;
	
	public LgTV() {
		System.out.println("===> LgTV 객체 생성");
	}

	public void powerOn() {
		System.out.println("LgTV---전원 켠다.");
	}

	public void powerOff() {
		System.out.println("LgTV---전원 끈다.");
	}
	
	public void volumeUp() {
		speaker.volumeUp();
	}

	public void volumeDown() {
		speaker.volumeDown();
	}
}
package polymorphism;

public class SonySpeaker implements Speaker{
	public SonySpeaker() {
		System.out.println("===> SonySpeaker 객체 생성");
	}

	public void volumeUp() {
		System.out.println("SonySpeaker---소리 올린다.");
	}

	public void volumeDown() {
		System.out.println("SonySpeaker---소리 내린다.");
	}
}
package polymorphism;

public class AppleSpeaker implements Speaker {
	public AppleSpeaker() {
		System.out.println("===> AppleSpeaker 객체 생성");
	}

	public void volumeUp() {
		System.out.println("AppleSpeaker---소리 올린다.");
	}

	public void volumeDown() {
		System.out.println("AppleSpeaker---소리 내린다.");
	}
}
<?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:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context" 
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
					    http://www.springframework.org/schema/context
					    http://www.springframework.org/schema/context/spring-context-4.2.xsd">
	
	<!-- LgTv는 어노테이션으로, Speaker는 <bean> xml 설정으로 SonySpeaker 주입 -->
	<context:component-scan base-package="polymorphism"></context:component-scan>
	<bean id="sony" class="polymorphism.SonySpeaker"></bean>
 </beans>

 

어노테이션, <bean>설정 주의사항

직접 개발한 클래스는 어노테이션을 사용할 수도 있고, <bean>를 등록하여 XML 설정을 할 수도 있다.

하지만 라이브러리 형태로 제공되는 클래스는 반드시 XML 설정을 통해서만 사용할 수 있음!

 

예를들어 commons-dbcp-1.4.jar 라이브러리를 이용하여 DB연결을 할 때 XML 설정을 통해 사용해야 한다.

 

+ Recent posts