본문 바로가기

Backend/Spring & SpringBoot

[Spring Framework] 02_01. Setter을 이용한 의존성 주입 방법

728x90

앞선 글에서는 의존성 주입을 할때, 생성자를 통하여 의존성 주입하는 방법에 대해서 알아보았다. 

이번에는 setter을 이용해서 어떻게 의존성을 주입하는지 알아보겠다. 

 

1) 먼저, setter를 xml파일에서 의존성을 주입하지않고 만드는 방법에 대해서 살펴보겠다.

 

DatabaseInfo.java 는 데이터베이스의 url, id, pw를 가지고 있는 객체이고, 

MemberDAO.java 는 데이터베이스를 연동해주는 객체이다. 예시로 간단하게 만들었다. 

 

# DatabaseInfo.java

 

package com.spring.basic.ex02;

public class DatabaseInfo {
	private String url;
	private String uid;
	private String upw;
	
	public String getUrl() {
		return url;
	}
	public void setUrl(String url) {
		this.url = url;
	}
	public String getUid() {
		return uid;
	}
	public void setUid(String uid) {
		this.uid = uid;
	}
	public String getUpw() {
		return upw;
	}
	public void setUpw(String upw) {
		this.upw = upw;
	}
}

#MemberDAO.java

 

package com.spring.basic.ex02;

public class MemberDAO {
	// db 연동
	
	private DatabaseInfo dbInfo;
	
	public void setDbInfo(DatabaseInfo dbInfo) {
		this.dbInfo = dbInfo;
	}
	
	public void showDBInfo() {
		System.out.println("URL : " + dbInfo.getUrl());
		System.out.println("UID : " + dbInfo.getUid());
		System.out.println("UPW : " + dbInfo.getUpw());
	}
}

# MainClass.java

package com.spring.basic.ex02;

public class MainClass {

	public static void main(String[] args) {
		DatabaseInfo dbInfo = new DatabaseInfo();
		
		dbInfo.setUid("spring1");
		dbInfo.setUpw("sss1111");
		dbInfo.setUrl("jdbc:oracle:thin:localhost:1521@:xe");
        
        System.out.println("url : " + dbInfo.getUrl());
		System.out.println("uid : " + dbInfo.getUid());
		System.out.println("upw : " + dbInfo.getUpw());
	}

}

 

<setter 직접 부른 실행결과>

2) 다음으로 setter에 의존성을 주입하여 실행하는 방식에 대해서 살펴보겠다.

 

* setter로 의존성 주입을 할때는 값을 사용할때는 value, 객체를 사용할때는 ref를 사용한다. 

<property name="변수명"  value=""/>

<property name="변수명"  ref="객체"/>

 

xml파일에 이렇게 작성한다. 

# database-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 id="db1" class="com.spring.basic.ex02.DatabaseInfo">
		<!-- setter 주입 -->
		<property name="url" value="jdbc:oracle:this:@localhost:1521:xe"/>
		<property name="uid" value="spring1"/>
		<property name="upw" value="sss1111"/>
	</bean>
</beans>

앞에 사용된 DatabaseInfo와 MemberDAO 클래스는 그대로 사용하겠다. 

 

# MainClass.java

package com.spring.basic.ex02;

import org.springframework.context.support.GenericXmlApplicationContext;

public class MainClass {

	public static void main(String[] args) {
		
		/*
		 //직접 setter을 부르는 식
		DatabaseInfo dbInfo = new DatabaseInfo();
		
		dbInfo.setUid("spring1");
		dbInfo.setUpw("sss1111");
		dbInfo.setUrl("jdbc:oracle:thin:localhost:1521@:xe");
		*/
		
		GenericXmlApplicationContext ct = new GenericXmlApplicationContext("classpath:db-config.xml");
		MemberDAO dao = ct.getBean("dao",MemberDAO.class);
		dao.showDBInfo();
		
		ct.close();
	}

}

=> 앞에 사용된 것과 실행결과 같은 것을 볼 수 있다. 

 

3) 주의 해야될 점.

 setter을 사용하면서 주의할 점이 몇가지 있다.

 

 (1) xml 파일에서 <property name="~"  value=""/>

~ 부분은 관례를 지켜서 작성해야된다. 보기에는 멤버변수로 접근하면 된다고 생각 할 수 있지만, 

setter, getter가 생략되어 있다는 점. 

따라서 setter , getter 을 작성할때 자동 완성 된 모습은 변경 안하는 것이 바람직하다.  

 

* 오류가 나는 예시를 살펴보겠다. 

# DatabaseInfo.java 에서 setUrl () 메서드를  setURL로 변경할경우.

 

8월 12, 2020 4:55:34 오후 org.springframework.context.support.AbstractApplicationContext refresh
경고: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'db1' defined in class path resource [db-config.xml]: Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'url' of bean class [com.spring.basic.ex02.DatabaseInfo]: Bean property 'url' is not writable or has an invalid setter method. Did you mean 'uid', or 'upw'?
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'db1' defined in class path resource [db-config.xml]: Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'url' of bean class [com.spring.basic.ex02.DatabaseInfo]: Bean property 'url' is not writable or has an invalid setter method. Did you mean 'uid', or 'upw'?
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1702)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1417)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:592)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:849)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:877)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549)
	at org.springframework.context.support.GenericXmlApplicationContext.<init>(GenericXmlApplicationContext.java:71)
	at com.spring.basic.ex02.MainClass.main(MainClass.java:18)
Caused by: org.springframework.beans.NotWritablePropertyException: Invalid property 'url' of bean class [com.spring.basic.ex02.DatabaseInfo]: Bean property 'url' is not writable or has an invalid setter method. Did you mean 'uid', or 'upw'?
	at org.springframework.beans.BeanWrapperImpl.createNotWritablePropertyException(BeanWrapperImpl.java:243)
	at org.springframework.beans.AbstractNestablePropertyAccessor.processLocalProperty(AbstractNestablePropertyAccessor.java:426)
	at org.springframework.beans.AbstractNestablePropertyAccessor.setPropertyValue(AbstractNestablePropertyAccessor.java:278)
	at org.springframework.beans.AbstractNestablePropertyAccessor.setPropertyValue(AbstractNestablePropertyAccessor.java:266)
	at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:97)
	at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:77)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1698)
	... 12 more

 이런 오류가 뜨게된다. 

오류를 살펴보면,

" Bean property 'url' is not writable or has an invalid setter method. Did you mean 'uid', or 'upw'? " 이라고 뜨는데, 

xml파일에서 url을 읽지 못하고 있다. 따라서 오류를 발생시키지 않기 위해 기본 형식을 유지해줘야 한다. 

 

(2) 빈(bean)의 기본 범위가 싱글톤 패턴이라는 것.

 

스프링 컨테이너에서 생성된 빈(Bean)객체의 경우 동일한 타입에 대해서는 적으로한 개만 생성이 되며,

getBean() 메소드로 호출될 동일한 객체가 반환 된다.

 

예시를 한번 살펴보겠다. 

#prototype-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 id ="person" class="com.spring.basic.ex03.Person">
		<property name="name" value="홍길동"/>
		<property name="age" value="20"/>
	</bean>
</beans>

 

#Person.java

package com.spring.basic.ex03;

public class Person {
	private String name;
	private int age;
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	
}

# MainClass.java

package com.spring.basic.ex03;

import org.springframework.context.support.GenericXmlApplicationContext;

public class MainClass {

	public static void main(String[] args) {
		GenericXmlApplicationContext ct = new GenericXmlApplicationContext("classpath:prototype-config.xml");
		Person hong = ct.getBean("person", Person.class);
		Person kim = ct.getBean("person", Person.class);
		
		//주소값 찍어보기
		
		System.out.println("hong의 주소 : " + hong);
		System.out.println("kim의 주소 : " + kim);
		System.out.println("hong과 kim은 같은 객체인가 ?  : " + (hong == kim));
		 
		System.out.println("====================================");
		
		kim.setName("김철수");  // kim 과 hong이 같다! -> 같은 객체를 쳐다보고있음. 주소값을 찍어보면?
		kim.setAge(30);
		
		System.out.println("hong의 이름 : " + hong.getName());
		System.out.println("hong의 나이 : " + hong.getAge());
		System.out.println("kim의 이름 : " + kim.getName());
		System.out.println("kim의 나이 : " + kim.getAge());
		
		ct.close();
	} 

}

<실행결과>

getBean을 통해서 반환된 객체 hong과 kim의 주소값이 같다. 즉 같은 객체를 바라보고있다는 뜻이다. 이렇게 스프링 컨테이너의 bean 기본적으로 싱글톤 패턴으로 만들어져 있다.

 

그렇다면 다른 객체로 만들려면 어떻게 해야될까?

간단하게 범위를 프로토타입으로 지정해주면된다. 

 

이런식으로 scope="prototype" 을 설정해주면 결과는 다음과 같이 나오게 된다. 

<실행결과>

 

결과 : getBean을 할때 마다 다른 주소값이 튀어나오게 된다. 

728x90