728x90

https://hahagogo.tistory.com/157

 

Spring DI

1. 다형성 Car car = (Car) getObject("car"); Engine engine = (Engine) getObject("engine"); static Object getObject(String key) throws Exception { Properties p = new Properties(); p.load( new FileRead..

hahagogo.tistory.com

 

config.txt 를 대신해서 resources > config.xml 가 역할을 대신한다.

 

빈의 기본 scope 는 싱글톤 이다. 

싱글톤 scope이란 어플리케이션 전반에 걸쳐 해당 빈의 인스턴스를 오직 하나만 생성해서 사용하는 것이다.

prototype  scope으로 설정하려면 @Scope("prototype")과 같이 문자열로 지정해주며, 실행할때마다 객체를 생성한다.

 

싱글톤의 경우 해시값이 같은것을 볼 수있다.

 

prototype 타입으로 적용시 해시값이 다른것을 볼 수 있다.

 

직접  Setter 를 이용하여 값을 할당

config.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- Bean 으로 사용할 클래스 등록 -->
    <bean id="car" class="com.test.ch3.Car" />
    <bean id="engine" class="com.test.ch3.Engine" />
    <bean id="door" class="com.test.ch3.Door" scope="prototype" />
</beans>
class Car{
    String color;
    int oil;
    Engine engine;
    Door[] doors;

    public void setColor(String clolr) {
        this.color = clolr;
    }
    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) +
                '}';
    }
}

class Engine{}
class Door{}

public class SpringDiTest {
    public static void main(String[] args) {
        ApplicationContext ac = new GenericXmlApplicationContext("config.xml");
        Car car = ac.getBean("car", Car.class);         // by name :: 타입정보 주면 형변환 필요 없다.
        Engine engine = (Engine) ac.getBean("engine"); // by name

        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);
    }
}

 

 

config.xml 이 setter를 이용하여 자동으로 값을 할당 <property ~~

<?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 으로 사용할 클래스 등록 -->
    <bean id="car" class="com.test.ch3.Car" >
        <property name="color" value="red" />  <!-- 기본형이나 String 일때만 value -->
        <property name="oil" value="100" />
        <property name="engine" ref="engine" /><!-- 참조형 인경우 ref -->
        <property name="doors">                <!-- 배열인 경우 -->
            <array value-type="com.test.ch3.Door" >
                <ref bean="door" />
                <ref bean="door" />
            </array>
        </property>
    </bean>
    <bean id="engine" class="com.test.ch3.Engine" />
    <bean id="door" class="com.test.ch3.Door" scope="prototype" />
</beans>
class Car{
    String color;
    int oil;
    Engine engine;
    Door[] doors;

    public void setColor(String clolr) {
        this.color = clolr;
    }
    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) +
                '}';
    }
}

class Engine{}
class Door{}

public class SpringDiTest {
    public static void main(String[] args) {
        ApplicationContext ac = new GenericXmlApplicationContext("config.xml");
        Car car = ac.getBean("car", Car.class);         // by name :: 타입정보 주면 형변환 필요 없다.
 
        System.out.println("car = " + car);
    }
}

 

 

config.xml 이 생성자 를 이용하여 자동으로 값을 초기화/할당

1. 기본 생성자 이용

<?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 으로 사용할 클래스 등록 -->
    <bean id="car" class="com.test.ch3.Car" />
    <bean id="engine" class="com.test.ch3.Engine" />
    <bean id="door" class="com.test.ch3.Door" scope="prototype" />
</beans>
class Car{
    String color;
    int oil;
    Engine engine;
    Door[] doors;   

    public Car(){}

    @Override
    public String toString() {
        return "Car{" +
                " color ='" + color + '\'' +
                ", oil =" + oil +
                ", engine =" + engine +
                ", doors =" + Arrays.toString(doors) +
                '}';
    }
}

class Engine{}
class Door{}

public class SpringDiTest {
    public static void main(String[] args) {
        ApplicationContext ac = new GenericXmlApplicationContext("config.xml");
        Car car = ac.getBean("car", Car.class);         // by name :: 타입정보 주면 형변환 필요 없다.
        System.out.println("car = " + car);
    }
}

 

2. 생성자 만들어서(기본 생성자 아님)  <constructor-arg ~

<?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 으로 사용할 클래스 등록 -->
    <bean id="car" class="com.test.ch3.Car" >
        <constructor-arg name="color" value="red" />  <!-- 기본형이나 String 일때만 value -->
        <constructor-arg name="oil" value="100" />
        <constructor-arg name="engine" ref="engine" /><!-- 참조형 인경우 ref -->
        <constructor-arg name="doors">                <!-- 배열인 경우 -->
            <array value-type="com.test.ch3.Door" >
                <ref bean="door" />
                <ref bean="door" />
            </array>
        </constructor-arg>
    </bean>
    <bean id="engine" class="com.test.ch3.Engine" />
    <bean id="door" class="com.test.ch3.Door" scope="prototype" />
</beans>
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;
    }

    @Override
    public String toString() {
        return "Car{" +
                " color ='" + color + '\'' +
                ", oil =" + oil +
                ", engine =" + engine +
                ", doors =" + Arrays.toString(doors) +
                '}';
    }
}

class Engine{}
class Door{}

public class SpringDiTest {
    public static void main(String[] args) {
        ApplicationContext ac = new GenericXmlApplicationContext("config.xml");
        Car car = ac.getBean("car", Car.class);         // by name :: 타입정보 주면 형변환 필요 없다.
        System.out.println("car = " + car);
    }
}

 

 

config.xml 에 패키지 지정하고 @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 http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

        <!-- @Autowired 사용하려면 필수 -->
        <!-- 단 여기에서는 component-scan 이 빈을 등록 해주기 때문에 없어도 된다 -->
        <context:annotation-config />

        <!-- com ( component-scan ) -->
        <!-- 패키지 안에 있는 클래스 중에서 @Component 붙은것을 찾아서 Bean 으로 등록 -->
        <context:component-scan base-package="com.test.ch3" >
                <!-- ex 입력시 빠른 입력 가능 -->
                <!-- 제외 할 것들 -->
                <context:exclude-filter type="regex" expression="com.test.ch3.dpCopy*.*"/>
        </context:component-scan>
</beans>
@Component("engine") class Engine{} // <bean id="engine" class="com.test.ch3.Engine" /  >
@Component class SuperEngine extends Engine{}
@Component class TurboEngine extends Engine{}
@Component class Door{}
@Component
class Car{
    @Value("red") String color;
    @Value("100") int oil;
    @Autowired Engine engine;  // 타입으로 먼저 검색 , 여러개인 경우 이름으로 찾음..
    @Autowired Door[] doors;

    public Car(){}
    public Car(String color, int oil, Engine engine, Door[] doors) {
        this.color = color;
        this.oil = oil;
        this.engine = engine;
        this.doors = 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) +
                '}';
    }
}

public class SpringDiTest {
    public static void main(String[] args) {
        ApplicationContext ac = new GenericXmlApplicationContext("config.xml");
        Car car = ac.getBean("car", Car.class);         // by name :: 타입정보 주면 형변환 필요 없다.
        System.out.println("car = " + car);

        //Engine engine = ac.getBean(Engine.class); // 엔진 타입이 3개라 에러가 난다.
        Engine engine = ac.getBean("superEngine" , Engine.class);
        System.out.println("engine = " + engine);
    }
}

 

 

하나만 나와야 되는데 두개 이상 검색되어 뭐를 선택해야 하는지 모를경우 나오는 에러

Exception in thread "main" org.springframework.beans.factory.
UnsatisfiedDependencyException: Error creating bean with name 'car':
Unsatisfied dependency expressed through field 'engine'; nested exception is org.
springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type 'com.test.ch3.Engine' available:
expected single matching bean but found 2: superEngine,turboEngine
	 
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: 
No qualifying bean of type 'com.test.ch3.Engine' available: expected 
single matching bean but found 2: superEngine,turboEngine

 

class Engine{} 에 @Component (빈 등록) 이 되어 있지 않은 상태에서

@Autowired Engine engine;  여기서 타입 검색을 먼저 하는데 빈으로 등록된 superEngine , turboEngine 둘중에 

무엇을 선택해야 될지 모르겠고 이름으로 조회해도 engine이 빈에 등록되어 있지 않아서 에러를 발생함.

 

이런 경우 @Autowired 아래에 @Qualifier("superEngine") 를 이용하여

빈으로 등록된 후보 중에서 하나를 지정해 주어야 한다.

 

아니면 주입받을 의존객체가 필수적이지 않을 경우 @Autowired(required = false)로 설정해서 

의존객체를 주입받지 못하더라도 빈을 생성하도록 할 수 있다.

 

또는  @Resource(name="superEngine") 이렇게 이름검색을 이용해도 된다.

class Engine{} // <bean id="engine" class="com.test.ch3.Engine" /  >
@Component class SuperEngine extends Engine{}
@Component class TurboEngine extends Engine{}
@Component class Door{}
@Component
class Car{
    @Value("red") String color;
    @Value("100") int oil;
    
//    @Autowired
//    @Qualifier("superEngine")
    @Resource(name="superEngine")
    Engine engine;  // engine , superEngine , TurboEngine
    
    @Autowired Door[] doors;

    public Car(){}
    public Car(String color, int oil, Engine engine, Door[] doors) {
        this.color = color;
        this.oil = oil;
        this.engine = engine;
        this.doors = 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) +
                '}';
    }
}

public class SpringDiTest {
    public static void main(String[] args) {
        ApplicationContext ac = new GenericXmlApplicationContext("config.xml");
        Car car = ac.getBean("car", Car.class);         // by name :: 타입정보 주면 형변환 필요 없다.
        System.out.println("car = " + car);
    }
}
728x90

+ Recent posts