@ 어노테이션 설정
.xml에 어노테이션을 사용하고 싶어서 컴파일 전 @ 어노테이션 있는지 확인해 달라는 설정이 필요하다.
(파일 위에 달려있는 어노테이션은 컴파일 전(메모리에 옮기기 전)에 본다)
스키마 추가가 필요함!
<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.2.xsd">
위 내용을 그대로 사용하면 된다.
(하나라도 틀리면 동작하지 않음!)
추가로 beans 안쪽에 아래의 코드도 필요하다.
<context:component-scan base-package="test" />
위 코드는 스캔하는 범위를 지정하는 코드이다.
(test 패키지만 스캔함)
이를 실행했을 때 나오는 순서는 test 패키지의 파일 순서대로!
// applicationContext.xml
<?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.2.xsd">
<!-- 스캔할 범위를 설정해준다. -->
<context:component-scan base-package="test" />
</beans>
Iphone.java에 어노테이션 설정을 추가한다.
package test;
import org.springframework.stereotype.Component;
@Component("apple") //어노테이션 설정 추가
public class Iphone implements Phone {
private Watch watch;
public Iphone() {
System.out.println("아이폰 객체 생성 01");
}
@Override
public void powerOn() {
this.watch.powerOn();
}
@Override
public void powerOff() {
this.watch.powerOff();
}
public Watch getWatch() {
return watch;
}
public void setWatch(Watch watch) {
this.watch = watch;
}
}
@Component("apple")는
new의 역할 == <bean>의 역할을 한다.
("apple") 는 <bean>에서 id이다.
Iphone apple = new Iphone();
== <bean class="Iphone" id="apple" />
== @Component("apple")
컴포넌트 == Bean == 모듈 == 패키지 == 위젯
== 리팩토링 결과물
== 함수화 == 메서드화 << 얘네는 좁은 의미의 리팩토링
// Client.java
package test;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
public class Client {
public static void main(String[] args) {
// 스프링 컨테이너 factory = new 스프링컨테이너();
AbstractApplicationContext factory = new GenericXmlApplicationContext("applicationContext.xml"); //GenericXmlApplicationContext == 아무 의미 없는 실습용 메서드임
Phone phone = (Phone)factory.getBean("apple"); // 다운캐스팅
// Bean == 자바객체 == 객체 == POJO
// 객체를 요청하다 == look up
phone.powerOn();
phone.powerOff();
factory.close();
}
}
Client에서 위처럼 powerOn / powerOff를 하려고 한다.
코드를 따라가보면 Watch로 power 동작을 한다.
하지만 현재 watch가 new 되어있지 않다.
따라서 watch 클래스 파일에도 new를 해주는 @Component 어노테이션을 달아줘야 한다.
하지만 private Watch watch; 에게 AppleWatch가 필요하다는 사실을 컨테이너는 모른다.
-> 이전에는 그래서 Setter 주입이나 생성자 주입을 했다.
이 의미는? 의존 주입이 필요하다는 의미! ( == DI 대상이다)
그래서 멤버변수 위에 @ 어노테이션을 달아준다.
@Autowired
@Qualifier("aw")
private Watch watch;
@Autowired를 달면 메모리의 자료형(타입)을 인지해서 주입을 한다.
만약 의존성이 여러개라면? (워치도 있고, 아이패드도 있고..)
하나하나 @Autowired를 달아줘야 한다.
어노테이션 하나당, 멤버변수 하나!!
그런데 @Autowired는 메모리의 타입을 인지해서 주입하는데, 현재 무슨 자료형인지 알 수 없다.
그래서 @Qualifier("aw")를 같이 달아야 한다.
🍀정리
1. <bean> 대신에 @Component로 객체 new
2. DI(의존주입) 기존에는 Setter 주입, 생성자 주입을 사용했는데 지금은 @Autowired로 주입
3. @Autowired는 메모리의 자료형만 참고하기 때문에 DI 모호성 에러 발생하기 쉬움
4. @Qualifier 객체명 참고하는 어노테이션을 달아줘야 한다.
여기서 TIP!
@Qualifier는 잘 쓰이지 않음.
-> 동일한 타입의 객체를 메모리에 여러 개 생성했다는 뜻이라서 성능에 좋지 않다.
따라서 성능에 예민한 프로그램들은 이걸 사용하지 않는다.
대신!
.xml에서
<bean class="test.AppleWatch" id="aw" />
를 사용하고, @Qualifier는 지워준다.
(섞어서 사용한다!)
이를 사용할 때,
<bean class="test.AppleWatch" id="aw" />
<bean class="test.GalaxyWatch" id="gw" />
이렇게 두 개 다 사용하게 되면 DI 모호성 에러 발생하기 때문에, 객체 생성이 필요한 bean만 작성한다.
'Spring' 카테고리의 다른 글
[Spring] DispatcherServlet (0) | 2024.10.07 |
---|---|
[Spring] Spring의 구조와 Service (0) | 2024.10.06 |
[Spring] Spring 내용 정리 (0) | 2024.10.06 |
[Spring] 의존성 주입 (0) | 2024.10.06 |
[Spring] 결합도가 높은 프로젝트의 형태 (1) | 2024.10.03 |