잼's Tech

[SPRING] DI 본문

FRAME WORK/SPRING

[SPRING] DI

차잼 2021. 8. 16. 18:46

[SPRING] DI

DI

DI(의존성 주입: Dependency Injection)

Spring에서의 Di란 클래스 사이의 의존관계를 컨테이너가 자동으로 맵핑해주는 것이다.

예를 들면

Dependency 1

이런식으로 개발자가 직접 의존성을 만든다.

하지만, Spring에서는

Dependency 2

이런 식으로 config.xml을 읽어 컨테이너에 bean으로 생성 후 필요할 때마다 bean 객체를 꺼낸 후 자동적으로 의존성 주입을 컨테이너가 해준다.

 

Spring에서의 다양한 Di 설정 방법에 대하여 배워보자

크게 XML, Annotation 방식 2가지로 나뉘어진다.


이해를 돕기 위해 이런 클래스와 인터페이스를 만들어 놓았다.

Dependency 3

 

<코드>

더보기
// Car interface 
public interface Car { void take(String s); }


// Person Class
import com.my.di.ui.Car;
public class Person {
	private Car car;
    int age;

	public Person() {};
	public Person(Car car, int age) { this.car = car; this.age = age; }
	public Car getCar() { return car; }
	public void setCar(Car car) { this.car = car; }
	public void take(String name) { car.take(name); }
	@Override
	public String toString() { return "Person [car=" + car + " / age=" + age + "]"; }
}


// Taxi Class
public class Taxi implements Car{
	@Override
	public void take(String s) { System.out.println(s+" take a Taxi"); }
}


// Bus Class
public class Bus implements Car{
	@Override
	public void take(String s) { System.out.println(s+" take a Bus"); }
}

※ 보다시피 Taxi와 Bus는 Car 인터페이스를 구현한 것이다. 그렇기에 사용 시 Bus를 넣어줄 것인지 Taxi를 넣어줄 것인지 명시를 해줘야한다. 만약 그렇지 못한다면 java.lang.IllegalStateException가 발생하게 된다.


1) XML 방식

- Constructor -Arg

더보기
//config.xml

<bean id = "bus" class = "com.my.di.ui.Bus"></bean>
<bean id = "taxi" class = "com.my.di.ui.Taxi"></bean>

<bean id = "Person" class = "com.my.di.entity.Person">
	<constructor-arg index="0" ref="bus" />
	<constructor-arg index="1" value="20" />
</bean>

객체는 기본적으로 ref를 사용하여 주입하고

기본형은 value를 사용한다.(string, int 등등)

위 방식은 생성자가 필요하다. ex) public Person(Car car, int age)

 

- Property

더보기
//config.xml

<bean id="bus" class="com.my.di.ui.Bus"></bean>
<bean id="taxi" class="com.my.di.ui.Taxi"></bean>

<bean id="Person" class="com.my.di.entity.Person">
	<property name="car" ref="taxi" />
</bean>

 

- p 태그

더보기

p 태그 사용시 xml에 p 태그 DTD가 필요하다.

<beans xmlns=> 안에 넣어주자

xmlns:p="http://www.springframework.org/schema/p
//config.xml

<bean id="bus" class="com.my.di.ui.Bus"></bean>
<bean id="taxi" class="com.my.di.ui.Taxi"></bean>
<bean id="Person" class="com.my.di.entity.Person" p:car-ref="bus" />

p 태그와 Property는 set 메서드를 사용하니 set 메서드가 필요하다.

 

- Untitled Text File 사용

더보기

Untitled Text File 사용시 당연히 File이 필요하고 그 파일의 경로가 필요하다.

파일의 경로는 context로 잡아주는게 편하다.

이를 위해 context DTD가 필요하다

xmlns:context="http://www.springframework.org/schema/context
//config.xml

<context:property-placeholder location="classpath:com/my/di/test/personlist.properties" />
	
<bean id="bus" class="com.my.di.ui.Bus"></bean>
<bean id="taxi" class="com.my.di.ui.Taxi"></bean>

<bean id="Person" class="com.my.di.entity.Person">
	<property name="car" ref="taxi" />
	<property name="age" value="${person1.age}" />
</bean>


//personlist.properties file
person1.age=22

 


2) Injection + XML 방식

Injection의 종류는 총 4가지가 있다.

더보기
//config.xml

<bean id="car" class="com.my.di.ui.Bus" />
<bean id="Person" class="com.my.di.entity.Person" />

 

우선 xml에 위와 같이 작성하고

Person Class에서

더보기

- Property Injection

//Person.java

@Autowired
private Car car;

 

- Setter Injection

//Person.java

@Autowired
public void setCar(Car car) {
	this.car = car;
}

 

- 특정 메소드 Injection

//Person.java
//메소드를 직접 만들어주는 것

@Autowired
public void matchCar(Car car) {
	this.car = car;
}

 

- 생성자 Injection

//Person.java

@Autowired
public Person(Car car){
	this.car = car;
}

 

※ Autowired의 경우 넣을 수 있는 타입이 bean에 있다면 자동으로 넣어준다.

이때, 만약 Bus와 Taxi가 같이 있다면?

//config.xml

<bean id="bus" class="com.my.di.ui.Bus" />
<bean id="taxi" class="com.my.di.ui.Taxi" />
<bean id="person" class="com.my.di.entity.Person" />

java.lang.IllegalStateException가 뜰 것이다.

이때, 사용하는 것이 

@Qualifier("bus"), @Resource(name="taxi") Annotation이다.

@Autowired
@Qualifier("bus")
public void setCar(Car car) {
	this.car = car;
}

또는

@Autowired
@Resource(name="bus")
public void setCar(Car car) {
	this.car = car;
}

※ 주의할 것은 생성자 Injection은 @Qualifier, @Resource가 사용이 안된다.

우선은 빈 값을 가지더라도 객체를 만들고 싶다면 @Autowired(required=false)를 사용하면 된다.

 

- Component-scan 방식

더보기
  • bean을 일일이 등록해주지 않아도 된다.
  • 역시 context DTD가 필요하다.
//config.xml

<context:component-scan base-package="com.my.di.ui, com.my.di.entity" />

 자동적으로 패키지들을 읽으며 component가 붙은 클래스들을 bean으로 생성한다.

그렇기에 bean으로 올릴 객체들만 component Annotation을 붙여주면 된다.

이때 이름을 따로 안 준다면 클래스의 맨 앞글자를 소문자로 바꾸어 id 값으로 등록한다

ex) Class Person -> id: person

@Component
클래스

또는

@Component("줄 이름")
클래스

 

※ 알아두면 좋을 Value Annotation과 EL 태그

더보기

이것은 의존 객체 생성 시 변수에 값을 넣어주는 것이다.

@Value("#{'SPRINGkk' +' EL '}")
private String name = "";

 


3) Annotation 방식

- @Bean 사용

더보기

config.xml을 사용하지 않고 클래스와 Annotation을 이용하는 방식이다.

// di_config.java

@Configuration
public class di_config {
	@Bean
	public Person person() {
		return new Person(taxi());
	}
	
	@Bean
	public Taxi taxi() {
		return new Taxi();
	}
	
	@Bean
	public Bus bus() {
		return new bus();
	}
}

 

- ComponetScan 사용

더보기
// di_config.java

@ComponentScan({"com.my.di.ui, com.my.di.entity"})
@Configuration
public class di_config {}

// bean으로 올릴 클래스 위에 component를 올려줘야한다.
@Component("bus")
@Component()

 

- 사용 시

더보기
@ContextConfiguration(classes= {di_config.class})
public class 사용할 클래스 {
	@Autowired
	ApplicationContext context;
	
	@Test
	public void bean1() {
		
		Person person = (Person)context.getBean("person");
		person.take("jaem");
		System.out.println(person.toString());
		
	}

}

 


다양한 사용 방식

더보기

컨테이너가 의존 객체를 생성할 때 타입이 어떻게 되는지 알려줘야하는데

이때, 다양한 방법으로 알려줄 수 있다.

@ContextConfiguration(locations = "classpath:com/my/di/test/config.xml")
public class 사용할 클래스 {
	@Autowired
	ApplicationContext ctx;
	
	@Test
	public void bean1() {
		
        // 타입에 맞추어 데이터 가져오기 1
        Person person = (Person)ctx.getBean("person");
        
        // 타입에 맞추어 데이터 가져오기 2
        Person person = ctx.getBean(Person.class);
        
        // 타입에 맞추어 데이터 가져오기 3
        Person person = ctx.getBean("person",Person.class);
        
        person.take("jaem");
        System.out.println(person.toString());
		

	}

}

 


컬렉션이 포함된 bean 객체

컬렉션에 대해 잘 모른다면

https://jaem-tech.tistory.com/18

 

[JAVA] 컬렉션(Collection) 프레임워크

컬렉션? 여러 자료를 효율적으로 보관 및 처리하기 위한 자료구조 배열의 단점을 보완 사이즈가 동적 어떤 자료형이라도 상관 없음 컬렉션 프레임워크? 여러 자료를 효율적으로 관리하기 위한

jaem-tech.tistory.com

을 참고하자.

 

- List

더보기
//Person.java
private List<String> names;

//config.xml
<bean id="person" class="com.my.di.entity.Person">
	<property name="names">
		<list>
			<value>Spring</value>
			<value>AOP</value>
			<value>DI</value>
		</list>
	</property>
</bean>

 

// Person.java
private List<Human> humans;

// Human.java
int age;
String name;

// config.xml
<bean id="person" class="com.my.di.entity.Person">
  <property name="humans">
      <list>
          <bean class="com.my.di.humans">
              <property name="age" value="30" />
              <property name="name" value="jaem" />
          </bean>
          <bean class="iaccess.di.entity.Person">
              <property name="age" value="50" />
              <property name="name" value="hong" />
          </bean>
      </list>
  </property>
</bean>

 

사용 시

Person person = context.getBean(Person.class);
List<String> list = person.getNames();

// 1) forEach + lamda
	list.forEach(s->System.out.println(s));
    
// 2) enhencede for
	for(String value : list) {
		System.out.println(value);
	}
    
// 3) Iterator
	Iterator<String> lst = list.iterator();
	while(lst.hasNext()) {
		System.out.println(lst.next());
	}

 

- Map

더보기
//Person.java
private Map<String, Integer> ages;

//config.xml
<bean id="person" class="com.my.di.entity.Person">
	<property name="ages">
		<map>
			<entry key="Kim" value="10" />
			<entry key="Lee" value="20" />
			<entry key="Ahn" value="30" />
		</map>
	</property>
</bean>

 

사용 시

Person person = context.getBean(Person.class);
Map<String, Integer> ages = person.getAges();

// 1) enhencede for
	for(Map.Entry<String,Integer> entry : ages.entrySet()) {
		System.out.println("KEY : " + entry.getKey() + ", VALUE : " + entry.getValue());
	}

// 2) Iterator set(keyset)
	Iterator<String> keys = ages.keySet().iterator();
	while(keys.hasNext()) {
		String key = keys.next();
		System.out.println("key : " + key + ", value : " + ages.get(key));
	}

// 3) lamda
	ages.forEach((key,value) -> System.out.println("key: " + key + "  | value: " + value));
	ages.entrySet().forEach(entry -> System.out.println("key: " + entry.getKey() + " | value: " + entry.getValue()));
	ages.keySet().forEach(key -> System.out.println("key: " + key));
	ages.values().forEach(value -> System.out.println("value : " + value));

 

- Set

더보기
//Person.java
private Set<String> emails;

//config.xml
<bean id="person" class="com.my.di.entity.Person">
	<property name="emails">
		<set>
			<value>kor@naver.com</value>
            <value>eng@naver.com</value>
			<value>eng@naver.com</value>
		</set>
	</property>
</bean>

 

사용 시

Person person = context.getBean(Person.class);
Set<String> set = person.getEmails();
Iterator<String> it = hs.iterator();

// 1) enhencede for
	for(String s : set) {
		System.out.println(s);
	}

// 2) Iterator
	while(it.hasNext()) {
		System.out.println(it.next());
	}

// 3) lamda
	set.forEach(s-> System.out.println(s));

 

'FRAME WORK > SPRING' 카테고리의 다른 글

[SPRING] AOP 적용  (0) 2021.08.18
[SPRING] AOP 이론  (0) 2021.08.13
Comments