필드로Pokemon 타입의 객체를 의존성 주입 받는 PokemonService 클래스를 선언한다. @Resource 어노테이션의 name속성에 주입할 빈 객체의 이름을 지정한다.
@Service("pokemonServiceResource")
public class PokemonService {
/* pikachu 이름의 빈 지정 */
@Resource(name = "pikachu")
private Pokemon pokemon;
public void pokemonAttack() {
pokemon.attack();
}
}
Charmander, Pikachu, Squirtle, PokemonService 를 빈 스캐닝 할 수 있는 basePackages를 설정하여 스프링 컨테이너를 생성한다.
@Autowired어노테이션은 가장 보편적으로 사용 되는 의존성 주입 Annotation이다.@Autowired와 함께 사용하거나 또는 대체해서 사용할 수 있는 어노테이션을 학습한다.
아래 코드는 테스트에 공통적으로 사용 할Pokemon,Charmander,Pikachu,Squirtle클래스이다.
Pokemon
public interface Pokemon {
/* 공격하다 */
void attack();
}
Charmander
@Component
public class Charmander implements Pokemon {
@Override
public void attack() {
System.out.println("파이리 불꽃 공격🔥");
}
}
Pikachu
@Component
public class Pikachu implements Pokemon {
@Override
public void attack() {
System.out.println("피카츄 백만볼트⚡");
}
}
Squirtle
@Component
public class Squirtle implements Pokemon {
@Override
public void attack() {
System.out.println("꼬부기 물대포 발사🌊");
}
}
1. @Primary
@Primary 어노테이션은 여러 개의 빈 객체 중에서 우선순위가 가장 높은 빈 객체를 지정하는 어노테이션이다.
생성자로 Pokemon 타입의 객체를 의존성 주입 받는 PokemonService클래스를 선언한다.
@Service("pokemonServicePrimary")
public class PokemonService {
private Pokemon pokemon;
@Autowired
public PokemonService(Pokemon pokemon) {
this.pokemon = pokemon;
}
public void pokemonAttack() {
pokemon.attack();
}
}
Charmander, Pikachu, Squirtle, PokemonService 를 빈 스캐닝 할 수 있는 basePackages를 설정하여 스프링 컨테이너를 생성한다.
ApplicationContext context = new AnnotationConfigApplicationContext("project");
PokemonService pokemonService = context.getBean("pokemonServicePrimary", PokemonService.class);
pokemonService.pokemonAttack();
/*
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'pokemonServicePrimary' defined in file 파일 경로 :
Unsatisfied dependency expressed through constructor parameter 0;
nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type 'project.common.Pokemon' available:
expected single matching bean but found 3: charmander,pikachu,squirtle
...생략
*/
스프링 컨테이너 내부에 Pokemon 타입의 빈 객체가 charmander,pikachu,squirtle 3개가 있어 1개의 객체를 PokemonService의 생성자로 전달할 수 없어 오류가 발생했음을 확인할 수 있다.
@Component
@Primary
public class Charmander implements Pokemon {
@Override
public void attack() {
System.out.println("파이리 불꽃 공격🔥");
}
}
/*
파이리 불꽃 공격🔥
*/
@Primary어노테이션을 설정하면@Autowired로 동일한 타입의 여러 빈을 찾게 되는 경우 자동으로 연결 우선 시 할 타입으로 설정 된다.
동일한 타입의 클래스 중 한 개만@Primary어노테이션을 사용할 수 있다.
Charmander빈 객체에@Primary어노테이션이 설정되어 있으므로,PokemonService의 생성자로Pokemon객체를 주입받으면Charmander빈 객체가 우선적으로 주입된다.
2. @Qualifier
@Qualifierb어노테이션은 여러 개의 빈 객체 중에서 특정 빈 객체를 이름으로 지정하는 어노테이션이다.
1. 필드 주입
필드로Pokemon 타입의 객체를 의존성 주입 받는 PokemonService 클래스를 선언한다. @Autowired 어노테이션과 함께 @Qualifier 어노테이션을 사용하여 빈 이름을 통해 주입할 빈 객체를 지정한다.
@Service("pokemonServiceQualifier")
public class PokemonService {
/* @Qualifier 어노테이션을 사용하여 pikachu 빈 객체를 지정한다. */
@Autowired
@Qualifier("pikachu")
private Pokemon pokemon;
public void pokemonAttack() {
pokemon.attack();
}
Charmander, Pikachu, Squirtle, PokemonService 를 빈 스캐닝 할 수 있는 basePackages를 설정하여 스프링 컨테이너를 생성한다.
base package로 설정 된 하위 경로에 특정 어노테이션을 가지고 있는 클래스를 bean으로 등록하는 기능이다.
@Component어노테이션이 작성 된 클래스를 인식하여 bean으로 등록한다.
특수 목적에 따라 세부 기능을 제공하는@Controller,@Service,@Repository,@Configuration등을 사용한다.
어노테이션
설명
@Component
객체를 나타내는 일반적인 타입으로<bean> 태그와 동일한 역할
@Controller
프리젠테이션 레이어. 웹 어플리케이션에서 View에서 전달된 웹 요청과 응답을 처리하는 클래스 EX) Controller Class
@Service
서비스 레이어, 비즈니스 로직을 가진 클래스 EX) Service Class
@Repository
퍼시스턴스(persistence) 레이어, 영속성을 가지는 속성(파일, 데이터베이스)을 가진 클래스 EX) Data Access Object Class
@Configuration
빈을 등록하는 설정 클래스
2. @Component 어노테이션으로 자동 빈 등록하기
@Component
public class MemberDAO {
private final Map<Integer, MemberDTO> memberMap;
public MemberDAO() {
memberMap = new HashMap<>();
memberMap.put(1, new MemberDTO(1, "user01", "pass01", "홍길동"));
memberMap.put(2, new MemberDTO(2, "user02", "pass02", "유관순"));
}
/* 매개변수로 전달 받은 회원 번호를 map에서 조회 후 회원 정보를 리턴하는 메소드 */
public MemberDTO selectMember(int sequence) {
return memberMap.get(sequence);
}
/* 매개변수를 전달 받은 회원 정보를 map에 추가하고 성공 실패 여부를 boolean으로 리턴하는 메소드 */
public boolean insertMember(MemberDTO newMember) {
int before = memberMap.size();
memberMap.put(newMember.getSequence(), newMember);
int after = memberMap.size();
return after > before;
}
}
bean으로 등록하고자 하는 클래스 위에@Component어노테이션을 기재하면 스프링 컨테이너 구동 시 빈으로 자동 등록된다.
이름을 별도로 지정하지 않으면 클래스명의 첫 문자를 소문자로 변경하여 bean의 id로 자동 인식한다.
@Component("myName")또는@Component(value="myName")의 형식으로 bean의 id를 설정할 수 있다.
3. @ComponentScan 어노테이션으로 base packages 설정하기
@ComponentScan(basePackages="project")
public class ContextConfiguration {}
@ComponentScan어노테이션의 basePackagese 속성에 입력한 패키지가 빈 스캐닝의 범위가 된다.
@ComponentScan 의 excludeFilters속성을 이용해서 일부 컴포넌트를 빈 스캐닝에서 제외할 수 있다.
Type으로 설정하는 방법
@ComponentScan(basePackages="project",
excludeFilters={
@ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE,
classes={MemberDAO.class})
})
public class ContextConfiguration {}
Annotation 종류로 설정하는 방법
@ComponentScan(basePackages="project",
excludeFilters={
@ComponentScan.Filter(type=FilterType.ANNOTATION,
classes={org.springframework.stereotype.Component.class})
})
public class ContextConfiguration {}
표현식으로 설정하는 방법
@ComponentScan(basePackages="project",
excludeFilters={
@ComponentScan.Filter(type=FilterType.REGEX,
pattern={"annotationconfig.java.*"})
})
public class ContextConfiguration {}
빈 스캐닝에서MemberDAO클래스가 제외되어 아래 코드를 실행하면 해당 이름을 가진 빈이 없다는 오류가 발생한다.
ApplicationContext context = new AnnotationConfigApplicationContext(ContextConfiguration.class);
String[] beanNames = context.getBeanDefinitionNames();
for(String beanName : beanNames) {
System.out.println("beanName : " + beanName);
}
MemberDAO memberDAO = context.getBean("memberDAO", MemberDAO.class);
/*
...생략
beanName : contextConfiguration
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException:
No bean named 'memberDAO' available
*/
5. includeFilters
@ComponentScan 의 includeFilters속성을 이용해서 일부 컴포넌트를 빈 스캐닝에 포함 시킬 수 있다.
@ComponentScan(basePackages="project",
useDefaultFilters=false,
includeFilters={@ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE,
classes= {MemberDAO.class})
})
public class ContextConfiguration {}
useDefaultFilters속성의 기본 값은 true로 @Component 종류의 어노테이션을 자동으로 등록 처리 해준다. 해당 속성을 false로 변경하면 컴포넌트 스캔이 일어나지 않게 된다.
별도로includeFilters속성을 정의해 컴포넌트 스캔이 발생하도록 한다.
excludeFilters에서 설정하는 방식과 동일하므로 종류별 예시는 생략한다.
아래 코드를 실행하면 빈 스캐닝에서MemberDAO클래스가 포함되어 해당 이름을 가진 빈을 확인할 수 있다.