XML Configure 파일에 <bean> 등록하지 않고 자동으로 생성하려면 <context:component-scan /> 엘리먼트를 정의해주어야 한다. 이 엘리먼트를 추가하면 스프링 컨테이너는 classpath에 있는 클래스들을 스캔하면서 @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: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-3.1.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->
<context:component-scan base-package="com.spring.example" />
</beans>
위의 소스를 보면 <context:component-scan>엘리먼트의 base-package속성을 "com.spring.example"으로 지정해주었는데 이 의미는 "com.spring.example"로 패키지로 시작하는 모든 패키지를 스캔하라는 의미이다.
@Component("pet")
public class Pet {
public Pet() {
/* default construct */
}
}
Pet클래스의 기본생성자를 생성해야 스프링컨테이너가 Pet클래스를 메모리에 생성을 할 수 있고 스프링컨테이너가 생성한 Pet객체를 요청하기 위해 "pet"이라는 식별자도 등록해주어야 한다. 만약 식별자를 등록하지 않는다면 클래스이름의 첫글자를 소문자로 바꿔서 사용하면 된다.
[Pet.class]
package com.spring.example;
import org.springframework.stereotype.Component;
@Component("pet")
public class Pet {
public Pet() {
System.out.println("Pet 객체가 생성되었습니다.");
}
/* 중략 */
}
[MainExample.class]
package com.spring.example;
import org.springframework.context.support.GenericXmlApplicationContext;
public class MainExample {
public static void main(String[] args) {
GenericXmlApplicationContext context = new GenericXmlApplicationContext("classpath:META-INF/spring/root-context.xml");
Pet pet = (Pet)context.getBean("pet");
context.close();
}
}
스프링에서는 어노테이션(@)방식으로 의존성 주입을 지원하고 있다.
@Autowired
@Inject
@Qualifer
@Resource
이렇게 네 가지가 있다.
1. @Autowired
@Autowired는 생성자, 메서드, 멤버변수에 모두 사용할 수 있다. 어디에 사용하든 상관없지만 보통은 멤버변수에 선언하여 사용한다.
스프링 컨테이너는 멤버변수 위에 붙은 @Autowired를 확인하는 순간 해당 변수의 타입을 체크한다. 그리고 그 객체가 메모리에 존재하는지 확인한 다음 그 객체를 주입하게 된다.
1-1. 필드(멤버변수)주입 예제
package com.spring.example;
public interface PetService {
public List<PetVO> getPetList() throws Exception;
}
package com.spring.example;
@Service
public class PetServiceImpl implements PetService {
@Autowired
private PetDAO petDAO;
@Override
public List<PetVO> getPetList() throws Exception {
/* section of implementation of getting list of pets */
}
}
1-2 메서드 주입 예제
package com.spring.example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class PetServiceImpl implements PetService {
private PetVO petVO;
@Autowired
public void getPetList(PetVO petVO) {
this.petVO = petVO;
}
}
1-3 생성자 주입 예제
package com.spring.example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class PetServiceImpl {
private PetVO petVO;
@Autowired
public PetServiceImpl(PetVO petVO) {
this.petVO = petVO;
}
}
2. @Qualifier
스프링에서 Bean을 생성할때 <context:annotation-config/>을 설정해주면 굳이 <bean>태그 안에 <property>나 <construct-arg>를 추가하지 않아도 @Autowired가 적용된 필드,메서드,생성자에 대해서 자동으로 주입을 한다.
그런데 만약 동일한 타입을 가진 bean객체가 두 개 이상이라면 문제가 발생한다.
같은 타입의 두 bean객체가 모두 메모리에 생성되어 있는 상황이면 스프링컨테이너는 어떤 객체를 할당할지 판단할 수 없기 때문에 에러가 발생하게 된다.
[AppleSpeaker.class]
package com.spring.example;
import org.springframework.stereotype.Component;
@Component("apple")
public class AppleSpeaker implements Speaker {
public AppleSpeaker() {
System.out.println("AppleSpeaker객체 생성됨");
}
}
[SonySpeaker.class]
package com.spring.example;
import org.springframework.stereotype.Component;
@Component("sony")
public class SonySpeaker implements Speaker {
public SonySpeaker() {
System.out.println("SonySpeaker객체 생성됨");
}
}
[SamsungTV.class]
package com.spring.example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component("tv")
public class SamsungTV {
@Autowired
private Speaker speaker;
public SamsungTV() {
System.out.println("SamsungTV 객체 생성됨");
}
}
[에러발생]
SamsungTV클래스에서 Speaker 타입의 변수를 @Autowired설정했는데 SonySpeaker와 AppleSpeaker객체 모두 Speake타입이기 때문에 스프링컨테이너가 어떤 객체를 주입해주어야 할지 모르기 때문에 에러가 나는 것이다.
[ @Qualifier("apple") 추가 ]
package com.spring.example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component("tv")
public class SamsungTV {
@Autowired
@Qualifier("apple")
private Speaker speaker;
public SamsungTV() {
System.out.println("SamsungTV 객체 생성됨");
}
}
해결방법 : @Autowired설정한 멤버변수에 @Qualifier("식별자")를 설정해주면 해당 식별자를 가지고 있는 객체를 주입해주게 된다.
3. @Resource
@Autowired는 변수의 타입을 기준으로 객체를 검색하여 의존성 주입을 처리하지만 @Resource는 객체의 이름을 이용하여 의존성 주입을 처리한다.
@Resource(name=" ... ")
name 속성을 이용하여 스프링 컨테이너가 해당 이름으로 생성된 객체를 검색하여 의존성 주입을 처리한다.
package com.spring.example;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component("tv")
public class SamsungTV {
@Autowired
@Resource(name="apple")
private Speaker speaker;
public SamsungTV() {
System.out.println("SamsungTV 객체 생성됨");
}
}
'개발하자 > Spring' 카테고리의 다른 글
DI(Dependency Injection)이란? (0) | 2020.03.26 |
---|---|
SPRING bean life cycle (0) | 2020.03.25 |
Controller에서 json으로 객체 변환 불가 에러. (0) | 2020.03.19 |
댓글