의존성을 주입할 수 있는 대상은 다른 Spring 빈뿐만이 아니다
의존성을 주입할 수 있는 대상은 아래와 같다
- 다른 Spring 빈 참조
- 단순 값
- 컬렉션
- 널(null)
- SpEL 표현식
다른 의존성 주입 대상들에 대해 사용하는 방법
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 31 32 33 34 35 | public class CustomerRepositoryImpl implements CustomerRepository { private String driverClassName; private String url; private String username; private String password; public String getDriverClassName() { return driverClassName; } public void setDriverClassName(String driverClassName) { this.driverClassName = driverClassName; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } } | cs |
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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="hello" class="springHello.Hello"/> <bean id="customerService" class="service.CustomerServiceImpl"> <constructor-arg ref="customerRepository"/> </bean> <bean id="customerRepository" class="repository.CustomerRepositoryImpl"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/order_system"/> <property name="username" value="root"/> <property name="password" value="root"/> </bean> </beans> | cs |
아래 xml 코드의 customerRepository 부분의 property 값들과 같이 스프링 빈이 아니어도 의존성 주입을 할수 있다
* 예제용으로 보여주었을 뿐 데이터 베이스를 구현하기 위한 더좋은 방법이 있으므로 이방법으로 할필요없는 없다
단일 필드 값만이 아니라 컬렉션 타입의 필드에도 값을 주입할 수 있다.
필드 타입 |
요소 |
설명 |
Collection/List |
<list> |
중복 허용 값 목록 |
Collection/Set |
<set> |
중복되지 않는 값 목록 |
Map |
<map> |
어떤 타입이든 허용되는 이름 값 컬렉션 |
Properties |
<props> |
Sring 타입의 이름-값 컬렉션 |
앞의 데이터베이스 연결 정보를 컬렉션 타입으로 정의할 때 가장 적당한 타입은 Properties 타입니다. 우리는 다음과 같이 Properties 타입의 컬렉션 필드를 정의할 수 있다.
| public class CustomerRepositoryImpl implements CustomerRepository { private Properties properties; public void setProperties(Properties properties){ this.properties = properties; } | cs |
| <bean id="customerRepository" class="repository.CustomerRepositoryImpl"> <property name="properties"> <props> <prop key="driverClassName">com.mysql.jdbc.Driver</prop> <prop key="url">jdbc:mysql://localhost:3306/order_system</prop> <prop key="username">root</prop> <prop key="password"></prop> </props> </property> </bean> | cs |
Properties 값을 이용할 경우 위와 같이의존성 주입을 할수 있다.
키값을 불러오는 형식으로 아래와 같이 사용가능하다.
| private String driverClassName = properties.getProperty("driverClassName"); private String url = properties.getProperty("url"); private String username = properties.getProperty("username"); private String password = properties.getProperty("password"); | cs |
이외에도
Map, List 를 이용하는 방법들이 있으니 교재를 참조 (p119 - p 121)
필드에 null값을 주입해야 하는 경우에는 다음과 같이 <null/> 요소를 사용한다.
1 | <property name="nullableProparty"><null/></property> | cs
|
또한 Spring 표현식 언어인 SpEL(Sproing Expression Language)의 #{} 표현식을 사용하여 필드값을 주입할 수 있다.
| <bean> <property name="property" value="#{5}" /> </bean> | cs |
Spring 표현식을 이용할수 있는 값들에 대해서는 교제 p122 에 있는 표를 참조하면 된다.
3.5 어노테이션
XML 설정 최소화
XML 설정 파일을 사용할 때 순수하가 POJO로 Spring 빈을 수현할 수 있으며, 앞에서 살펴본 바와 같이 소스 코드를 변경시키지 않고도 설정을 변경시키는 것만으로도 유지 보수를 쉽게 할수 있게 한다는 이점을 갖게된다
그러나 Java 코드와 설정이 분리되어 프로그램의 이해를 어렵게 하고 Spring 빈 클래스가 많아지면 XML 설정도 많아져서 개발자들이 어플리케이션을 개발하는데 어려움을 겪게되는것도 사실이다.
이런 문제를 해결하기 위해 아래와 같은 두가지 해결책이 있다.
자동와이어링은 XML설정 파일은 그대로 사용하면 Spring 빈 설정을 최소한으로 할 수 있ㄷ도록 하는 기능
어노테이션 와이어링은 XML 설정 파일을 아예 사용하거지 않거나또는, 가능한 사용을 억제하고 어노테이션을 사용하여 Spring 빈을 설정할 수 있도록 하는 기능을 제공
* 여기서 와이어링이란 의존성 주입을 통해 Spring 빈을 연결하는 것을 말한다.
Spring 프레임워크는 다음과 같은 4가지 자동 와이어링 방식을 제공
방식 |
autowire 애트리뷰트 |
설명 |
이름 |
byName |
필드와 같은 이름 (또는ID)를 가지는 빈과 자동 와이어링 |
타입 |
byType |
필드와 같은 타입의 빈과 자동 와이어링 |
생성자 |
contructor |
생성자 매개 변수의 타입과 일치하는 빈을 자동 와이어링1 |
자동탐색 |
autodetect |
먼저 생성자 자동 와이어링이 수행되고 실패하면 타입 와이어링이 수행됨 |
다음과 같이 Bean 클래스가 정의되어 있다고 하자
| public class Bean1 {} public class Bean2 { private Bean1 bean1; public void setBean1(Bean1 bean){ this.bean1 = bean1 } } public class Bean3 { private Bean1 bean1; public Bean3(Bean1 bean1){ this.bean1 = bean1; } } <bean id="bean1" class="Bean1"/> | cs |
byName 이 지정되면 필드명과 같은 이름을 가지는 빈을 찾아 자동으로 와이어링 시킨다
-> 이름 와이어링
아래는 Bean2 크래스의 필드명이 bean1이므로 빈 이름이 bean1인 빈을 찾아서 필드에 의존성을 주입한다.
1 | <bean id="bean2" class="Bean2" autowire="byName"/> | cs |
byType 이 지정되면 필드와 타입의을 가지는 빈을 찾아 자동으로 와이어링 시킨다
-> 타입 와이어링
아래는 Bean2 클래스의 bean1필드의 타입이 Bean1 클래스이므로 class 애트리뷰트가 Bean1인 bean1 빈을 찾아서 필드에 의존성을 주입시킨다.
1 | <bean id="bean2" class="Bean2" autowire="byType"/> | cs |
1 | <bean id="bean3" class="Bean3" autowire="constructor"/> | cs |
어노태이션 와이어링
XML 설정을 최소하 하기 위해 Spring 프레임 워크는 빈 와이어링 즉, 의존성 주입을 지원하는 어노테이션을 제공한다. 이러한 기능을 어노테이션 와이어링이라고 한다. 어노테이션 와이어링을 사용하기 위해서즌 먼저 XML 설정 파일에 context 네임스페이스를 추가해야 한다. 다음과 같이 <beans> 태그 안에 context 네임스페이스를 추가한다.
| <?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 http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd"> <context:annotation-config/> </beans> | cs |
추가로 <context:annotation-config/>도 설정해 어노테이션 와이어링 사용할수 있게 한다.
어노테이션을 사용한 의존성 주입에 사용할 수 있는 어노테이션은 다음과 같다.
어노테이션 |
제공자 |
@Autowired |
Spring |
@Inject |
JSR-330 |
@Resource |
JSR-250 |
@Autowired 어노테이션은 Spring 프레임워크에서 제공하는 기본적인 어노테이션이다. 이 어노테이션은 필드 또는 생성자, setter 메서드에 적용할 수 있으며, 먼저 타입 와이어링을 시도한 후에 실패하면 이름 와이어링으로 후보 빈을 찾는다.
보통 아래와 같이 오토와이
| public class CustomerServiceImpl implements CustomerService { @Autowired private CustomerRepository repository; } | cs |
필드외에도 생성자와 setter 메서드에 @Autowired 애트리뷰트를 지정할 수도 있다.
이제 XML 설정 파일에 의존성 주입을 하기 위한 설정을 생략해도 된다.
만약 와이어링할 빈이 없는 경우 NoSuchBeanDefinitionException이 발생
이떄 우리는 다음과 같은 두가지 방법을 사용할 수 있다.
방안 |
설정 |
선택적 자동 와이어링 지정(null값 허용) |
@Autowired(required=false) |
와이어링할 빈 지정(범위 한정) |
@Qualifier("beanID") |
첫번째 방법은 와이어링을 반드시 해야 하는것은 아니라고 선택적 자동 와이어링을 지정하는것이다. 만약 자동 와이어링할 빈을 찾지 못한다면, 해당 필드에 저장되는 값은 null이 된다.
| import org.springframework.beans.factory.annotation.Autowired; @Autowired(required=false) private CustomerRepository repository; | cs |
또 다른 방법은 와이어링할 빈을 지정하는 것. 달리말하면, 찾을 수 있도록 범위를 한정하는 것.ㅣ @Qualifier 어노테이션의 괄호 안에 와이어링할 빈 이름을 지정한다.
| import org.springframework.beans.factory.annotation.Qualifier; @Qualifier("customerRepository") private CustomerRepository repository; | cs |
Spring 프레임워크가 제공하는 @Autowired 어노테이션 외에도 Java의 JSR-330사양에 있는 @Inject 어노테이션을 사용할 수 있다. JSR-330 사양은 Java 언어가 제공하는 의존성 주입을 표준 어노테이션이 정의되어 있다. 이들 어노테이션을 사용하려면 클래스 경로에 표준 어노테이션을 구현한 jar 파일이 있어야 한다 . 우리는 Maven을 사용하므로 pom.xml 파일에 종종석을 추가하면 된다 .
| <dependency> <groupId>javax.inject</groupId> <artifactId>javax.inject</artifactId> <version>1</version> </dependency> | cs |
자동 빈 발견
XML 설정을 사용하지 않용하지 않고도 오노테이션을 사용하여 Spring 빈을 설정 할수 있다.
어노테이션 |
설명 |
@Component |
클래스가 Spring 빈임을 표시하는 범용 어노테이션 |
@Service |
클래스가 서비스를 정의하고 있으ㅁ을 표시하는 @Componenet |
@Repository |
클래스가 데이터 레파지토리를 정의하고 있음을 표시하는 @Component |
@Controller |
클래스가 Spring MVC 컨트롤러를 정의하고 있음을 표시하는 @Component |
@Component 어노테이션은 가장 범용적인 Spring 빈 설정 어노테이션이다. 다음과 같이 Spring 빈 클래스에 지정하면 된다. 이때 디폴트 Spring 빈의 이름은 클래스명의 첫 문자를 소문자로 바꾼 이름이 된다. 아래 예의 Spring 빈은 customerRepositoryImpl 이된다
| @Component public class CustomerRepositoryImpl implements CustomerRepository { } | cs |
Spring 빈의 이름을 변경하고 싶다면 괄호안에 이름을 지정하면 된다
| @Component("customerService") public class CustomerRepositoryImpl implements CustomerRepository { } | cs |
@Component 어노테이션 대신에 Spring 빈의 성격에 따라 @Service, @Repository, @Controller 어노테이션을 사용할 수 있다. @Service 어노테이션은 Spring 빈이 업무 로직을 구현한 서비스임을 나타낸다.
| @Service("customerService") public class CustomerServiceImpl implements CustomerService { } | cs |
@Repository 어노테이션은 Spring 빈이 데이터 액세서 기능을 제공하는 레파지토리임을 나타낸다.
| @Repository("customerRepository") public class CustomerRepositoryImpl implements CustomerRepository { } | cs |
@Controller 어노테이션은 Spring MVC에서 컨트롤러임을 나타낸다.
이렇게 어노테이션으로 정의한 Spring 빈을 자동으로 발견할 수 있도록 XML 설정 파일에 설정해야만 한다. 이때 XML 설정 파일에는 <context:annotation-config/> 대신에 자동으로 Spring 빈을 발견하기 위한 설정만 추가하면 된다
1 | <context:component-scan base-package="com.ensoa.order"/> | cs |
base-package애트리뷰트에 지정된 패키지오 서브 패키지를 스캐닝 하여 Spring 빈을 찾아 인스턴스를 생성하고 IoC컨테이ㅅ너 즉, 어플리케이션 컨텍스트에 자동으로 등록된다. 편리하지만 POJO코드보다는 조금 복잡해진다. 그래도 직관적으로 이해할 수 있으므로 아주 유용한 기능이다.
** 중대형 프로젝트는 수십명의 작업자가 같이 작업을 하므로 자동 어노테이션보다는 기존 XML방식으로 의존성을 서술한 방식을 주로 이용한다. XML 방식이 전체적인 의존성 주입방식 파악에 훨씬 유용하기 때문이다