스프링 DI pattern 다루기
📖생성자가 있는 객체를 DI pattern을 활용하여 생성하기
MessageBean 인터페이스를 구현하는 클래스를 하나 만들고, DI 패턴으로 구현을 하려고 한다. 이때 생성자가 있는 경우의 예제이다.
MessageBean.java
public interface MessageBean {
public void sayHello();
}
MessageBeanImpl.java
public class MessageBeanImpl implements MessageBean{
private String name;
private int age;
private String greeting;
public MessageBeanImpl() {}
public MessageBeanImpl(String name, int age, String greeting) {
this.name = name;
this.age = age;
this.greeting = greeting;
}
@Override
public void sayHello() {
String msg = greeting + "!~~" + name + "님, 당신의 나이는 " + age + "살입니다.";
System.out.println(msg);
}
}
App.java
public class App {
private static ApplicationContext ctx;
public static void main( String[] args ){
ctx = new ClassPathXmlApplicationContext("config/basic05_config.xml");
MessageBean bean = ctx.getBean("bean", MessageBeanImpl.class);
bean.sayHello();
//안녕하세요!~~홍길동님, 당신의 나이는 20살입니다. or
//안녕하세요!~~임꺽정님, 당신의 나이는 30살입니다.
}
}
App.java와 같이 외부에서 의존성을 주입 받아 최종적으로 동작하는 클래스를 consumer 클래스라고 한다.
여기까지가 예제를 위한 코드들이고, 의존성을 주입하기 위해서 두 가지 방법을 사용할 수 있다.
📝Constructor-based DI
basic05_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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bean" class="basic05.MessageBeanImpl">
<constructor-arg index="0" value="홍길동" />
<constructor-arg index="1" value="20" />
<constructor-arg index="2" value="안녕하세요" />
</bean>
</beans>
constructor-arg
태그를 활용하여 생성자에 인자를 넘겨줄 수 있다. 이렇게 메인 함수에서 객체를 생성하지 않고 외부에서 생성자를 호출하여 객체를 생성하는 방식이 Constructor-based DI이다.
인덱스가 아니라 타입으로 매칭해줄 수도 있다.
📝Setter-based DI
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bean" class="basic05.MessageBeanImpl">
<constructor-arg index="0" value="홍길동" />
<constructor-arg index="1" value="20" />
<constructor-arg index="2" value="안녕하세요" />
<!-- 추가된 코드 -->
<property name="name" value="임꺽정" />
<property name="age" value="30" />
</bean>
</beans>
property
태그를 활용하여 setter 메서드를 호출할 수 있다. setter 메서드는 규약에 따라 set+”프로퍼티이름(첫글자 대문자)”로 이름이 정해져 있는데, name
속성에 프로퍼티 이름만 넣어주면 알아서 호출을 해준다.
📖 ref 속성으로 클래스 간 DI 패턴 적용하기
이번에는 위의 코드에 인사말을 다양한 방법으로 출력할 수 있게 하는 코드를 추가하고자 한다.
Outputter.java
public interface Outputter {
void output(String msg) throws Exception;
}
FileOutputter.java
import java.io.FileWriter;
public class FileOutputter implements Outputter{
private String filePath;
public void setFilePath(String path) {
filePath = path;
}
@Override
public void output(String msg) throws Exception {
FileWriter writer = new FileWriter(filePath);
writer.write(msg);
writer.close();
}
}
파일 입출력을 하는 클래스를 생성해 Outputter 인터페이스를 구현한다.
MessageBeanImpl.java
인사말을 파일로 출력하기 위해서 오버라이딩한 sayHello() 메서드 내에서 FileOutputter 객체를 가져오려고 하는데, consumer 클래스가 아닌 곳에서 getBean()함수로 객체를 가져오는 것은 적절해보이지 않는다. 따라서 Outputter 프로퍼티를 추가하고, setter-based DI pattern을 적용해보고자 한다.
public class MessageBeanImpl implements MessageBean{
private String name;
private int age;
private String greeting;
private Outputter outputter;
public MessageBeanImpl() {}
public MessageBeanImpl(String name, int age, String greeting) {
this.name = name;
this.age = age;
this.greeting = greeting;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setGreeting(String greeting) {
this.greeting = greeting;
}
public void setOutputter(FileOutputter outputter) {
this.outputter = outputter;
}
@Override
public void sayHello() {
String msg = greeting + "!~~" + name + "님, 당신의 나이는 " + age + "살입니다.";
System.out.println(msg);
try {
outputter.output(msg);
}
catch(Exception e) {
e.printStackTrace();
}
}
}
basic05_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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bean" class="basic05.MessageBeanImpl">
<constructor-arg index="0" value="홍길동" />
<constructor-arg index="1" value="20" />
<constructor-arg index="2" value="안녕하세요" />
<property name="outputter" ref="writer" />
</bean>
<bean id="writer" class="basic05.FileOutputter">
<property name="filePath" value="src/main/java/basic05/result.txt" />
</bean>
</beans>
정해진 값을 가져오는 게 아니라, 어떤 값의 주소를 받아와야 하는 경우 value 대신 ref 속성을 활용할 수 있다.
댓글남기기