resource > xml 파일 만들어주기
config.xml
<java />
<?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="car" class="com.fastcampus.ch3.Car"/>
<bean id="engine" class="com.fastcampus.ch3.Engine"/>
<bean id="door" class="com.fastcampus.ch3.Door"/>
</beans>
SpringDiTest.java
<java />
package com.fastcampus.ch3;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
class Car{}
class Engine{}
class Door{}
public class SpringDiTest {
public static void main(String[] args) {
ApplicationContext ac = new GenericXmlApplicationContext("config.xml");
Car car = (Car) ac.getBean("car");
Engine engine = (Engine)ac.getBean("engine");
Door door = (Door)ac.getBean("door");
System.out.println("car = " + car);
System.out.println("engine = " + engine);
System.out.println("door = " + door);
}
}
config.xml에 클래스 정보를 설정해주고
그것을 읽어와서 객체 저장소에 객체가 만들어진다.
getBean으로(byNamed으로) 객체들을 가져와 사용했다.
<java />
ApplicationContext ac = new GenericXmlApplicationContext("config.xml");
// Car car = (Car) ac.getBean("car"); //byName 아래와 같은 문장
Car car = ac.getBean("car",Car.class); //byName
Car car2 = (Car) ac.getBean(Car.class); //byType
byName 또는 byType으로 찾기
byName으로 찾을 때,
그냥 이름만 쓰고, 앞에 형변환을 하던지
뒤에 타입 정보를 주고 형변환을 생략하던지
어느 방법이든 상관없다!
<java />
public static void main(String[] args) {
ApplicationContext ac = new GenericXmlApplicationContext("config.xml");
// Car car = (Car) ac.getBean("car"); //byName 아래와 같은 문장
Car car = ac.getBean("car",Car.class); //byName
Car car2 = (Car) ac.getBean(Car.class); //byType
Engine engine = (Engine)ac.getBean("engine");
Door door = (Door)ac.getBean("door");
System.out.println("car = " + car);
System.out.println("engine = " + engine);
System.out.println("door = " + door);
System.out.println("car2 = " + car2);
}
}

car와 car2 해쉬코드 값이 같은데, 같은 객체라서 그렇다.
getBean을 할 때마다 같은 값을 반환한다.
getBean을 할 때마다 매번 같은 객체가 만들어지는 singleton이지만,
때로는 getBean을 할 때마다 매번 다른 객체를 생성하고 싶을 때는
<java />
<?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="car" class="com.fastcampus.ch3.Car" scope="prototype"/>
<bean id="engine" class="com.fastcampus.ch3.Engine" scope="singleton"/>
<bean id="door" class="com.fastcampus.ch3.Door" scope="singleton"/>
</beans>
기본이 singleton이지만
scope로 prototype을 지정해주면 된다.

클래스의 객체를 하나만 생성하는 것이 싱글톤이다.
Car에 iv를 몇개 추가한다.
<java />
class Car{
String color;
int oil;
Engine engine;
Door[] doors;
public void setColor(String color) {
this.color = color;
}
public void setOil(int oil) {
this.oil = oil;
}
public void setEngine(Engine engine) {
this.engine = engine;
}
public void setDoors(Door[] doors) {
this.doors = doors;
}
@Override
public String toString() {
return "Car{" +
"color='" + color + '\'' +
", oil=" + oil +
", engine=" + engine +
", doors=" + Arrays.toString(doors) +
'}';
}
}
Setter를 이용해서
자동차에 엔진과 도어를 주입한다.
<java />
car.setColor("red");
car.setOil(100);
car.setEngine(engine);
car.setDoors(new Door[]{ac.getBean("door",Door.class), (Door)ac.getBean("door")});
System.out.println("car = " + car);

Door가 2개인데 두 해쉬값이 같다..
그러므로
<java />
<?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="car" class="com.fastcampus.ch3.Car" />
<bean id="engine" class="com.fastcampus.ch3.Engine" />
<bean id="door" class="com.fastcampus.ch3.Door" scope="prototype"/>
</beans>

prototype으로 바꾸어주면
Door가 서로 다른 값이 나온다
Setter를 호출하는 것이 아닌
xml에서 property 태그로 해결할 수 있다.
property태그를 이용해 iv를 초기화했다.
<java />
<?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="car" class="com.fastcampus.ch3.Car">
<property name="color" value="red"/>
<property name="oil" value="100"/>
<property name="engine" ref="engine"/>
<property name="doors">
<array value-type="com.fastcampus.ch3.Door">
<ref bean="door"/>
<ref bean="door"/>
</array>
</property>
</bean>
<bean id="engine" class="com.fastcampus.ch3.Engine" />
<bean id="door" class="com.fastcampus.ch3.Door" scope="prototype"/>
</beans>
만약 변경 사항이 생기면
config.xml파일만 고쳐주면 되기 때문에
고칠 코드가 줄어든다.
<java />
public class SpringDiTest {
public static void main(String[] args) {
ApplicationContext ac = new GenericXmlApplicationContext("config.xml");
// Car car = (Car) ac.getBean("car"); //byName 아래와 같은 문장
Car car = ac.getBean("car",Car.class); //byName
Car car2 = (Car) ac.getBean(Car.class); //byType
Engine engine = (Engine)ac.getBean("engine");
Door door = (Door)ac.getBean("door");
// car.setColor("red");
// car.setOil(100);
// car.setEngine(engine);
// car.setDoors(new Door[]{ac.getBean("door",Door.class), (Door)ac.getBean("door")});
System.out.println("car = " + car);
}
}

클래스 내에 Setter들이 있어야
property 태그를 사용할 수 있다.
(property가 Setter를 사용하는 것이다.)
Setter를 사용하는 대신에 생성자를 사용할 수도 있는데,
property를 constructor-arg로 바꿔주고
클래스에 생성자를 추가한다.
<java />
<?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="car" class="com.fastcampus.ch3.Car">
<constructor-arg name="color" value="red"/>
<constructor-arg name="oil" value="100"/>
<constructor-arg name="engine" ref="engine"/>
<constructor-arg name="doors">
<array value-type="com.fastcampus.ch3.Door">
<ref bean="door"/>
<ref bean="door"/>
</array>
</constructor-arg>
</bean>
<bean id="engine" class="com.fastcampus.ch3.Engine" />
<bean id="door" class="com.fastcampus.ch3.Door" scope="prototype"/>
</beans>
<java />
class Car{
String color;
int oil;
Engine engine;
Door[] doors;
public Car(String color, int oil, Engine engine, Door[] doors) {
this.color = color;
this.oil = oil;
this.engine = engine;
this.doors = doors;
}

패키지 안의 Componet 애노테이션이 붙은 클래스를 찾아서 bean으로 등록
<java />
<?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.xsd">
<context:component-scan base-package="com.fastcampus.ch3"/>
</beans>
패키지 하위에 있는 것들까지 다 찾아버려서(Car 클래스가 diCopy3에도 있으므로) 에러가 나기 때문에
코드를 추가해줘서
SpringDiTest.java 클래스 내에만 있는 Component를 스캔하는 것으로 설정한다.
<java />
<?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.xsd">
<context:component-scan base-package="com.fastcampus.ch3">
<context:exclude-filter type="regex" expression="com.fastcampus.ch3.diCopy*.*"/>
</context:component-scan>
</beans>

Setter를 주석으로 해서 다 null값이 나온다
Setter 주석 해제~
<java />
public class SpringDiTest {
public static void main(String[] args) {
ApplicationContext ac = new GenericXmlApplicationContext("config.xml");
// Car car = (Car) ac.getBean("car"); //byName 아래와 같은 문장
Car car = ac.getBean("car",Car.class); //byName
Car car2 = (Car) ac.getBean(Car.class); //byType
Engine engine = (Engine)ac.getBean("engine");
Door door = (Door)ac.getBean("door");
car.setColor("red");
car.setOil(100);
car.setEngine(engine);
car.setDoors(new Door[]{ac.getBean("door",Door.class), (Door)ac.getBean("door")});
System.out.println("car = " + car);
}
}

getBean이 잘 되었다는 뜻
다시 Setter를 주석처리한다
@Autowired를 통해 Setter 대신 주입을 해본다
객체들 간의 관계를 맺어주는 것이다.
<java />
@Component
class Car{
String color;
int oil;
@Autowired
Engine engine;
@Autowired
Door[] doors;
<code />
public class SpringDiTest {
public static void main(String[] args) {
ApplicationContext ac = new GenericXmlApplicationContext("config.xml");
// Car car = (Car) ac.getBean("car"); //byName 아래와 같은 문장
Car car = ac.getBean("car",Car.class); //byName
Car car2 = (Car) ac.getBean(Car.class); //byType
Engine engine = (Engine)ac.getBean("engine");
Door door = (Door)ac.getBean("door");
// car.setColor("red");
// car.setOil(100);
// car.setEngine(engine);
// car.setDoors(new Door[]{ac.getBean("door",Door.class), (Door)ac.getBean("door")});
System.out.println("car = " + car);
}
}

color와 oil에는 null값이 나온다
@Value 어노테이션을 사용해준다
<java />
@Component
class Car{
@Value("red")
String color;
@Value("100")
int oil;

door는 하나만 주입이 되었는데,
Autowired는 타입이 맞는 bean 하나만 넣기 때문에..
Engine을 추가한다
<code />
@Component("engine") //<bean id="engine"
class Engine{}
@Component
class SuperEngine extends Engine{}
@Component
class TurboEngine extends Engine{}
<code />
public class SpringDiTest {
public static void main(String[] args) {
ApplicationContext ac = new GenericXmlApplicationContext("config.xml");
// Car car = (Car) ac.getBean("car"); //byName 아래와 같은 문장
Car car = ac.getBean("car",Car.class); //byName
Car car2 = (Car) ac.getBean(Car.class); //byType
// Engine engine = (Engine)ac.getBean("engine"); //ByName
Engine engine = (Engine)ac.getBean(Engine.class); //ByType
Door door = (Door)ac.getBean("door");

매칭되는 bean 1개를 예상했는데 3개가 발견되어 에러가 난 것이다.
타입이 여러 개일때는 타입이 아닌 이름으로 찾는다.
<code />
Engine engine = (Engine)ac.getBean("superEngine"); //ByType
Door door = (Door)ac.getBean("door");
// car.setColor("red");
// car.setOil(100);
// car.setEngine(engine);
// car.setDoors(new Door[]{ac.getBean("door",Door.class), (Door)ac.getBean("door")});
System.out.println("car = " + car);
System.out.println("engine = " + engine);

같은 타입이 여러 개 있을 때 byType으로 찾으면 에러가 난다.
그럴 때에는 이름으로(key) 찾아야한다.
<code />
@Autowired //byType - 타입으로 먼저 검색, 여러개면 이름으로 검색. - engine, superEngine, turboEngine
Engine engine;
<java />
public class SpringDiTest {
public static void main(String[] args) {
ApplicationContext ac = new GenericXmlApplicationContext("config.xml");
// Car car = (Car) ac.getBean("car"); //byName 아래와 같은 문장
Car car = ac.getBean("car",Car.class); //byName
// Car car2 = (Car) ac.getBean(Car.class); //byType
// Engine engine = (Engine)ac.getBean("engine"); //ByName
// Engine engine = (Engine)ac.getBean("superEngine"); //ByType
// Door door = (Door)ac.getBean("door");
// car.setColor("red");
// car.setOil(100);
// car.setEngine(engine);
// car.setDoors(new Door[]{ac.getBean("door",Door.class), (Door)ac.getBean("door")});
System.out.println("car = " + car);
}
}
@Autowired는 byType인데 왜 에러가 나지 않을까?
그 이유는 타입으로 먼저 검색한 뒤, 후보가 여러 개라면 타입의 앞글자가 소문자인 것으로 이름을 검색한다.
<java />
//@Component("engine") //<bean id="engine" class="com.fastcampus.ch3.Engine"/>
class Engine{}
Engine이 Component에 있어서 일치하는 것이 있었는데,
빼고 나면
Autowired로 이름을 찾아야한다.
타입이 일치하는 SuperEngine과 TurboEngine 2개가 있는데 이름으로 비교해보니 판단이 서지않아 에러가 난다.
그럴때는
@Qualifier로 판단을 해주어야한다.
<code />
@Autowired //byType - 타입으로 먼저 검색, 여러개면 이름으로 검색. - engine, superEngine, turboEngine
@Qualifier("superEngine")
Engine engine;

Autowired는 type으로 bean을 찾아서 주입을 하는데
만약에 같은 타입이 여러개라면,
@Qualifier를 사용한다.
Autowired가 아닌
Resource를 사용해도 제대로 결과가 나온다!
<code />
@Resource(name="superEngine")
Engine engine;
'패캠 챌린지' 카테고리의 다른 글
스프링 IOC와 DI (0) | 2023.03.24 |
---|---|
스프링 DI 활용하기 - 이론 (0) | 2023.03.23 |
스프링 DI 흉내내기 - 객체 찾는 법 (by type/by name) (0) | 2023.03.22 |
패스트캠퍼스 챌린지 - 30일차 [스프링의 정석:남궁성과 끝까지 간다] (0) | 2023.03.21 |
패스트캠퍼스 챌린지 - 29일차 [스프링의 정석:남궁성과 끝까지 간다] (0) | 2023.03.20 |