[Spring] 스프링 정리2 - 생성자 주입(Constructor Injection), setter 주입(setter injection)
[목차]
2. 생성자 주입(Constructor Injection)
① meta.xml
② 생성자 호출
③ MVC 패턴 및 다형성 활용한 프로그래밍
④ 생성자 주입(construnctor injection)
⑤생성자 주입방법 2
3. setter 주입(setter injection)
4. new를 이용한 객체생성과 Spring 객체 생성의 차이
[내용]
2. 생성자 주입(Constructor Injection)
public static void main(String[] args) {
// new로 객체 생성시 매번 생성된다.
MessageImpl m1 = new MessageImpl("김이상");
m1.sayHi();
MessageImpl m2 = new MessageImpl("김이상");
m2.sayHi();
System.out.println("주소 : "+m1);
System.out.println("주소 : "+m2);
}
=> new를 이용한 객체 생성
① meta.xml
<beans>
<bean id="moneyCalc" name="aa,bb,cc" class="pack.model.MoneyCalc"/>
<bean id="myProcess" class="pack.controller.MyProcess">
<constructor-arg>
<ref bean="moneyCalc"/>
</constructor-arg>
</bean>
</beans>
=> 매개변수가 있는 생성자일 경우 <contructor-arg>와 <ref> 태그를 사용하여 매개변수를 입력한다.
=> 매개변수도 생성자를 생성한다.
<beans>
<bean id="moneyCalc" name="aa,bb,cc" class="pack.model.MoneyCalc"/>
<bean id="myProcess" class="pack.controller.MyProcess">
<constructor-arg>
<ref bean="aa"/>
</constructor-arg>
</bean>
</beans>
=> id나 name 둘중 무엇을 사용해도 상관없으며, <ref bean="name">에서 name을 호출가능.
② 생성자 호출
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("money_init.xml");
MyInter inter = (MyInter)context.getBean("myProcess");
inter.inputMoney();
inter.showResult();
}
}
=> ApplicationContext 객체 생성시 xml에 연결된 모든 생성자가 호출되며, 각 객체가 생성된다.
=> context의 getBean()메소드로 객체를 get하여 메소드를 사용한다.
=> getBean() 메소드의 리턴값은 Object로 다형성을 사용하여 캐스팅하여 객체를 대입한다.
=> getBean() 리턴 객체도 다형성을 사용하여 interface 객체에 대입하여 사용하는 것을 지향한다.
③ MVC 패턴 및 다형성 활용한 프로그래밍
pakage | Controller(Servlet) | Model(Dto, Dao-sql) |
Interface | BusinessInterface | ModelInterface |
↑ | ↑ | |
Class | BusinessClass | ModelClass |
=> 다형성을 갖춘 MVC Pattern 작성을 지향하여 프로그래밍한다.
=> Controller의 Business Class에서 Model Interface를 호출하여 사용한다.
=> 각 모델은 다형성을 활용하여 테이블에 따른 Sql문을 호출하여 DB와 연결된다.
=> [src.main/java]에 작성한다.
- Business Interface
public interface MyInter {
void inputMoney();
void showResult();
}
- Business Class
public class MyProcess implements MyInter{
private MoneyInter inter;
private int result[];
public MyProcess(MoneyInter inter) {
this.inter = inter;
}
public void inputMoney() {
//키보드로 금액입력
try {
InputStreamReader reader = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(reader);
int myMoney=0;
System.out.println("금액입력");
String data = br.readLine();
myMoney = Integer.parseInt(data);
result = inter.calcMoney(myMoney);
} catch (Exception e) {
System.out.println("inputMoney err "+e);
}
}
public void showResult() {
//계산이 끝난 배열 자료 출력.
System.out.println("만원 : "+result[0]+"개");
System.out.println("천원 : "+result[1]+"개");
System.out.println("백원 : "+result[2]+"개");
System.out.println("십원 : "+result[3]+"개");
System.out.println("일원 : "+result[4]+"개");
}
}
=> 생성자에 모델의 interface 객체를 매개변수로 받아 사용.
- Model Interface
public interface MoneyInter {
int[] calcMoney(int money);
}
- Model Class
public class MoneyCalc implements MoneyInter{
public MoneyCalc() {
}
public int[] calcMoney(int money) {
//단위별 금액 건수 계산용
int result[] = new int[5];
int temp=0;
int len = result.length;
for(int i=0; i<len;i++) {
if(i == 0) {
result[i] = money/(int)Math.pow(10, (len-1-i));
temp=money%(int)Math.pow(10, (len-1-i));
continue;
}
result[i] = temp/(int)Math.pow(10, (len-1-i));
temp=temp%(int)Math.pow(10, (len-1-i));
}
return result;
}
}
③ 생성자 주입(construnctor injection)
- ShowData(Dao)
public class ShowData {
public String toAlias() {
return "홍길동";
}
public String toHobby() {
return "운동";
}
}
- MyProcess(Controller)
public class MyProcess { // 포함으로 약결합 진행
private int age;
private String name;
private ShowData showData; // Class Type
public MyProcess(int age, String name, ShowData showData) {
this.age = age;
this.name = name;
this.showData = showData;
}
public void printData() {
System.out.println(name+age+showData.toAlias()+showData.toHobby());
}
}
- xml
<beans>
<bean id="showData" class="pack.model.ShowData"/>
<bean id="myProcess" class="pack.controller.MyProcess">
<constructor-arg>
<value>13</value>
</constructor-arg>
<constructor-arg>
<value>홍길동</value>
</constructor-arg>
<constructor-arg>
<ref bean="showData"/>
</constructor-arg>
</bean>
</beans>
- main
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("init.xml");
MyProcess myProcess = (MyProcess)context.getBean("myProcess");
myProcess.printData();
}
④ 생성자 주입방법 2
- MessageInter
public interface MessageInter {
void sayHi();
}
- MessageImpl
public class MessageImpl implements MessageInter{
private String name1;
private String name2;
private int year;
private MyClass myclass;
private String spec;
// 생성자 주입
public MessageImpl(String name1, String name2, int year, MyClass myclass) {
this.name1=name1;
this.name2=name2;
this.year=year;
this.myclass = myclass;
}
//setter 주입
public void setSpec(String spec) {
this.spec = spec;
}
// 출력담당 메소드
public void sayHi() {
String msg="이름 : "+name1+" / "+name2+"\n";
msg+="직업 : "+(year+21)+"년 " + myclass.myData();
msg+="\n보유기술 : "+spec;
System.out.println(msg);
}
}
- arrange.xml
① 생성자 주입방법 1
<bean id="mbean" class="pack.MessageImpl" scope="singleton">
<constructor-arg value="홍길동">
<ref bean="name1"/>
</constructor-arg>
</bean>
<bean id="mbean" class="pack.MessageImpl" scope="singleton">
// <bean> scope의 default는 singleton.
// scope를 prototype 설정 시 getBean()호출시 매번 객체를 생성한다.
// request, session은 web에서 사용.
<constructor-arg index="1">
<value>홍길동</value>
</constructor-arg>
<constructor-arg index="0">
<value>도둑놈</value>
</constructor-arg>
<constructor-arg index="2" value="2000"/> // String -> int로 자동 변경된다.
<constructor-arg index="2" type="int" value="2000"/> // 매개변수가 int일 경우
<constructor-arg index="2" type="int" value="이천"/> // error
<constructor-arg index="3" type="pack2.MyClass" ref="myClass"/>
</bean>
<bean id="myClass" class="pack2.MyClass">
<property name="data" value="자바"/> // setter injection
</bean>
② 생성자 주입방법 2
: arrange.xml의 Namespace Tab에서 c, p check
<bean id="mbean" class="pack.MessageImpl"
c:name1="고길동"
c:name2="깡패"
c:year="2000"
c:myclass-ref="myClass"
p:spec="sqld">
</bean>
<bean id="myClass" class="pack2.MyClass">
<property name="data" value="자바"/><!-- setter injection -->
</bean>
=> contruct, setter injection 혼용가능
- main
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("arrange.xml");
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:pack/arrange.xml");
// src/main/java/pack에 있을경우
//다형성
MessageInter inter = (MessageInter)context.getBean("mbean"); // 캐스팅을 interface로 한다.
// MessageInter inter = (MessageImpl)context.getBean("mbean"); // 지양
inter.sayHi();
System.out.println("주소 : "+inter);
}
3. setter 주입(setter injection)
- MyProcess
public class MyProcess {
private int age;
private String name;
private ShowData showData;
// setter를 이용해서 private 멤버에 값을 입력
public void setAge(int age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public void setShowData(ShowData showData) {
this.showData = showData;
}
public void printData() {
System.out.println(name+age+showData.toAlias()+showData.toHobby());
}
}
- init.xml
① 방법 1
<bean id="myProcess" class="pack.MyProcess">
<property name="age" value="22"/> //MyProcess의 setAge()를 호출한다.
<property name="name" value="김이상"/> // setName() 호출
<property name="showData" ref="showData"/> //객체의 setter 호출시 ref를 사용한다.
</bean>
<bean id="showData" class="pack.ShowData"/> // 다른 <bean>태그에서도 호출 가능
② 방법 2 : 하위 element로 사용
<bean id="myProcess" class="pack.MyProcess">
<property name="age">
<value>23</value>
</property>
<property name="name">
<value>김이상</value>
</property>
<property name="showData">
<bean class="pack.ShowData"/> // 해당 <bean>태그에서만 사용가능
</property>
</bean>
- main
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("init.xml");
MyProcess myProcess = (MyProcess)context.getBean("myProcess");
myProcess.printData();
}
4. new를 이용한 객체생성과 Spring 객체 생성의 차이
- new
public static void main(String[] args) {
// new로 객체 생성시 매번 생성된다.
MessageImpl m1 = new MessageImpl("김이상");
m1.sayHi();
MessageImpl m2 = new MessageImpl("김이상");
m2.sayHi();
System.out.println("주소 : "+m1); // 주소 : pack.MessageImpl@74e28667
System.out.println("주소 : "+m2); // 주소 : pack.MessageImpl@1cf6d1be
}
- xml
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("arrange.xml");
// getBean사용시 singletone으로 객체 생성
MessageImpl impl1 = (MessageImpl)context.getBean("mbean");
impl1.sayHi();
MessageImpl impl2 = (MessageImpl)context.getBean("mbean");
impl2.sayHi();
System.out.println("주소 : "+impl1);
System.out.println("주소 : "+impl2);
}
. 어노테이션 : 객체생성시 xml에 의존적 -> @annotation으로 대체.
① @Require 어노테이션 : setter를 사용하도록 제약을 건다.
- Abc
public class Abc {
private int number;
@Required // setter를 사용하도록 제약을 건다.
public void setNumber(int number) {
this.number = number;
}
public void printData() {
System.out.println("number : "+number);
}
}
- anno1.xml
<beans>
<context:annotation-config/>
<bean id="abc" class="anno1.Abc">
<property name="number" value="100"></property>
</bean>
</beans>
- main
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("anno1.xml");
Abc abc = (Abc)context.getBean("abc");
abc.printData();
}
② @Component : 객체 생성
- SenderInter
public interface SenderInter{
void show();
}
- Sender
@Component // 객체 생성
public class Sender implements SenderInter{
public void show() {
System.out.println("show메소드 수행");
}
}
- Sender2
//@Component = @Component("Sender2")// 객체 생성
@Component("별명")
public class Sender2 implements SenderInter{
public void show() {
System.out.println("Sender2의 show메소드 수행");
}
}
③ @Service : @Component와 동일하나 Business 로직에서 사용한다.
④ @Autowired : setter가 내부적으로 정의되며, type에 의한 mapping 진행.
⑤ @Qualifier("아이디") : type에 대하여 mapping시 동일한 타입(같은 부모를 상속받는 자식) 객체가 복수인 경우
Qualifier의 아이디에 명시한 아이디로 mapping한다.
- SenderProcess
//@Component
//@Service
@Service("SenderProcess") //Component와 동일
public class SenderProcess { // 서비스를 하는 비지니스 로직
private String name = "tom";
@Autowired // xml의 type에 대한 mapping.
//@Qualifier("sender2") // 동일한 타입의 객체(상속받는 자식 객체)가 복수인 경우 id로 mapping
@Qualifier("별명")
private SenderInter senderInter;
//public void setSender(Sender sender) { // @Autowired사용시 삭제가능
// this.sender = sender;
//}
public void displayData() {
System.out.println("displayData의 name : " + name);
senderInter.show();
}
}
- xml
<context:annotation-config/> // @어노테이션을 사용가능하게 한다.
<bean id="senderProcess" class="anno2.SenderProcess"/>
<bean id="sender" class="anno2.Sender"/>
<bean id="sender2" class="anno2.Sender2"/>
// SenderInter를 상속하는 class가 복수가 되면 type으로 mapping하기 때문에 식별자가 필요하다.
<bean class="anno2.Sender"/>
// type에 대한 mapping으로 id가 없어도 mapping된다.
<context:annotation-config/> // 생략 가능
<context:component-scan base-package="anno2"/> // pakage의 @Component, @Service가 작성된 class의 Bean을 생성.
- main
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("anno2.xml");
SenderProcess senderProcess = (SenderProcess)context.getBean("senderProcess");
senderProcess.displayData();
}