웹_프론트_백엔드/JAVA프레임윅기반_풀스택

2020.06.19

shine94 2020. 6. 19. 10:44

1. 의존 자동 주입(@Autowired 사용), 자동 주입(Autowired)
 : 컨테이너 안에 이미 생성된 빈(bean)객체와 이를 의존하는 다른 빈 객체들로 하여금
   굳이 <construtor-arg>나 <property> 등의 설정 없이도 자동적으로 참조(autowire)하여 주입될 수 있게 하는 것

 

 

2. Autowired를 구현하는 방법
1) 스프링 XML 설정 파일에 <context:annotation-config/> 설정 추가

 

2) 자동주입 대상에 @Autowired 애노테이션 사용(자동주입 대상 :  생성자, 멤버 변수, setter 메소드)

 

 

3. @Autowired는 타입이 일치하는 bean과 가능..!! 


4. @Qualifier
 : 동일한 타입의 복수 개 Bean 객체에 대한 @Autowired는 모호함(ambiguity)하다,

   모호함을 없애기 위해 사용,
   사용할 의존 객체를 선택할 수 있도록 해줌

 


5. @Qualifier 설정 방법
[step1] 설정에서 Bean의 Qualifier 이름을 설정
[step2] @Autowired이 적용된 주입 대상에 @Qualifier를 사용하여 step1에서 설정한 Qualifier 이름을 지정 

 

[주의!] @Qualifier는 @Autowired와 달리 멤버변수와 setter에만 적용 가능(생성자에는 적용 불가)


6. @Autowired 빈(bean) 객체 적용 순서 (정리)
 : @Autowired로 자동 주입되는 Bean 객체 matching 순서

1) 타입이 같은 bean 객체 검색 > 한 개면 해당 bean 객체 사용

2) 타입이 같은 bean 객체가 두 개 이상이면 > @Qualifier로 지정한 bean 객체를 찾음, 있으면 해당 객체 사용

3) 타입이 같은 bean 객체가 두 개 이상이고 @Qualifier가 없을 경우 > 변수이름이 같거나 유사한 bean 객체를 찾음

 

7. STS03_DI2_Autowired

** [src/main/java] com.lec.beans > DAO.java

package com.lec.beans;

public class DAO {
	String uid;	// DAO 객체 식별용 필드
	
	
	public DAO() {
		System.out.println("DAO() 생성");
	}

	public DAO(String uid) {
		super();
		System.out.printf("DAO(%s) 생성\n", uid);
		this.uid = uid;
	}

	
	@Override
	public String toString() {
		return String.format("[DAO : %s]", this.uid);
	}
}

// DAO 상속 받은 클래스
class DAOEx extends DAO {
	public DAOEx() {
		super();
		System.out.println("DAOEx() 생성");
	}
	
	public DAOEx(String uid) {
		super(uid);
		System.out.printf("DAOEx(%s) 생성\n", uid);
	}
	
	@Override
	public String toString() {
		return String.format("[DAOEx: %s]", this.uid);
	}
	
}

 

** [src/main/java] com.lec.beans

    > 인터페이스 : Service,

       클래스 : RegisterService, ReadService, updateService, deleteService, ListService, ViewService

package com.lec.beans;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

/*
 * 참고로,
 * 	일전에 JSP Model 2에서
 * 	Command 라고 배웠던 객체를 'Service 단' 이라고 한다.
 * 
 */

public interface Service {}

class RegisterService implements Service {
	DAO dao;
	
	// 기본생성자는 없다
	
	public RegisterService(DAO dao) {
		System.out.printf("RegisterService(%s) 생성\n", dao.toString());
		this.dao = dao;
	}
	
	@Override
	public String toString() {
		return String.format("[RegisterService : %s]", dao.toString());
	}
}

// 기본생성자가 없는 Service 객체 다시 생성..!!
class ReadService implements Service {
	DAO dao;
	
	// 기본생성자는 없다
	
	// 생성자에 @Autowired 자동 주입
	// 매개변수 '타입' 과 일치하는 bean 객체가 자동 주입된다.
	@Autowired
	public ReadService(DAO dao) {
		System.out.printf("ReadService(%s) 생성\n", dao.toString());
		this.dao = dao;
	}
	
	@Override
	public String toString() {
		return String.format("[ReadService : %s]", dao.toString());
	}
}

class UpdateService implements Service {
	// 멤버변수에 @Autowired 자동 주입
	// 멤버변수 '타입'과 일치하는 bean 객체가 자동 주입된다.
	@Autowired
	DAO dao;
	
	// 기본생성자는 있다!
	public UpdateService() {
		System.out.println("UpdateService() 생성");
		
	}
	
	@Override
	public String toString() {
		return String.format("[UpdateService : %s]", dao.toString());
	}
}

class DeleteService implements Service {
	DAO dao;
	
	public DeleteService() {
		System.out.println("DeleteService() 생성");
	}
	
	// setter에 @Autowired 자동 주입
	// setter의 매개변수 '타입'과 일치하는 bean 객체가 주입된다.
	// <property>가 없어도 setter가 호출 된다!
	@Autowired
	public void setDao(DAO dao) {
		System.out.printf("setDao(%s) 호출\n", dao.toString());
		this.dao = dao;
	}
	
	@Override
	public String toString() {
		return String.format("[DeleteService : %s]", dao.toString());
	}
}

// 두 개의 DAO 멤버변수
class ListService implements Service {
	@Autowired
	@Qualifier("memberDAO")
	DAO memberDao;
	DAO boardDao;
	
	public ListService() {
		System.out.println("ListService() 생성");
	}

	@Autowired
	@Qualifier("boardDAO")
	public final void setBoardDao(DAO boardDao) {
		this.boardDao = boardDao;
	}
	
	@Override
	public String toString() {
		return String.format("[ListService : %s, %s]", 
				memberDao.toString(), boardDao.toString());
	}
}

class ViewService implements Service {
	@Autowired
	DAO myDao;	// @Autowired된 변수 이름 주목!
	
	
	public ViewService() {
		System.out.println("ViewService() 생성");
	}
	
	
	@Override
	public String toString() {
		return String.format("[ViewService: %s]", myDao.toString());
	}
}

 

** [src/main/resources] autowiredCtx1.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"
	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-3.2.xsd">

	<context:annotation-config/>

	<bean id="dao1" class="com.lec.beans.DAOEx">
		<constructor-arg value="DAO_Ex"/>
	</bean>
	
	<bean id="regService" class="com.lec.beans.RegisterService">
		<constructor-arg ref="dao1"/>
	</bean>
	
	<!-- 이건 에러다, 기본 생성자가 없기 때문에, RegisterService는 반드시 DAO가 필요하다! -->
	<!-- <bean id="regService" class="com.lec.beans.RegisterService"/> -->
	
	<bean id="readService" class="com.lec.beans.ReadService"/>

	<!-- 기본 생성자가 있기 때문에 에러가 날 일이 없음..!! -->
	<bean id="updateService" class="com.lec.beans.UpdateService"/>
	
	<bean id="delService" class="com.lec.beans.DeleteService"/>
	
</beans>

 

** [src/main/resources] autowiredCtx2.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"
	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-3.2.xsd">
	
	<!-- Namespaces 에서 context 사용하기 위해서는 아래의 코드는 반드시 선언해줘야함! -->
	<context:annotation-config/>
	
	<bean id="dao" class="com.lec.beans.DAO">
		<constructor-arg value="DAO_MEMBER"/>
		<qualifier value="memberDAO"/>
	</bean>
	
	<!-- 
		@Qualifier 는 @Autowired 와 달리  
		‘멤버변수’와 ‘setter’에만 적용 가능(생성자에는 적용 불가)
	 -->
	<bean id="dao2" class="com.lec.beans.DAO">
		<constructor-arg value="DAO_BOARD"/>
		<qualifier value="boardDAO"/>
	</bean>
	
	<bean id="listService" class="com.lec.beans.ListService"/>
	
	<!-- 
		동일 DAO 객체 여러 개인데 qualifier가 지정되어 있지 않으면
		이름이 같은 것을 찾는다 
	-->
	<bean id="myDao" class="com.lec.beans.DAO">
		<constructor-arg value="DAO_VOTE"/>
	</bean>
	
	<bean id="viewService" class="com.lec.beans.ViewService"/>

</beans>

 

** [src/main/java] com.lec.string.autowired1 > AutowiredMain01

package com.lec.string.autowired1;

import org.springframework.context.support.GenericXmlApplicationContext;

public class AutowireMain01 {

	public static void main(String[] args) {
		System.out.println("Autowired 자동 주입");
		
		GenericXmlApplicationContext ctx
			= new GenericXmlApplicationContext("classpath:autowiredCtx1.xml");
		System.out.println("-- 컨테이너 생성 --");
		
		System.out.println(ctx.getBean("regService"));		
		System.out.println(ctx.getBean("readService"));
		System.out.println(ctx.getBean("updateService"));
		System.out.println(ctx.getBean("delService"));
		
		ctx.close();
		System.out.println("종료");
	}

}

 

** [src/main/java] com.lec.string.autowired2 > AutowiredMain02

package com.lec.spring.autowired2;

import org.springframework.context.support.GenericXmlApplicationContext;

public class AutowiredMain02 {

	public static void main(String[] args) {
		System.out.println("Autowired 자동 주입2");
		
		GenericXmlApplicationContext ctx
			= new GenericXmlApplicationContext("classpath:autowiredCtx2.xml");
		System.out.println("-- 컨테이너 생성 --");
		
		System.out.println(ctx.getBean("listService"));
		System.out.println(ctx.getBean("viewService"));
		
		ctx.close();
		System.out.println("종료");
	}

}

 

 

8. 연습 문제

** [src/main/java] ex3_1 > OperatorBean 인터페이스

package ex3_1;

public interface OperatorBean {
	
	public abstract int doOperate();

}

 

** [src/main/java] ex3_1 > Operand.java

package ex3_1;

public class Operand {
	int value;
	
	
	public Operand() {
		System.out.println("Operand() 생성");
	}
	public Operand(int value) {
		super();
		this.value = value;
	}

	
	public final int getValue() {
		return value;
	}
	public final void setValue(int value) {
		this.value = value;
	}
	
	
	@Override
	public String toString() {
		return String.format("[Operand: %d]", value);
	}
	
}

 

** [src/main/java] ex3_1 > PlusOp.java

package ex3_1;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

public class PlusOp implements OperatorBean {
	@Autowired
	@Qualifier("operand1")
	Operand operand1;
	
	@Autowired
	@Qualifier("operand2")
	Operand operand2;
	
	
	public PlusOp() {
		System.out.println("PlusOp() 생성");
	}
	public PlusOp(Operand operand1, Operand operand2) {
		super();
		System.out.printf("PlusOp(%d, %d) 생성\n",
				operand1.getValue(), operand2.getValue());
		this.operand1 = operand1;
		this.operand2 = operand2;
	}


	public final Operand getOperand1() {
		return operand1;
	}
	public final void setOperand1(Operand operand1) {
		this.operand1 = operand1;
	}
	
	public final Operand getOperand2() {
		return operand2;
	}
	public final void setOperand2(Operand operand2) {
		this.operand2 = operand2;
	}
	
	
	@Override
	public int doOperate() {
		return operand1.getValue() + operand2.getValue();
	}
	
	
	@Override
	public String toString() {
		return String.format("PlusOp %s, %s", operand1, operand2);
	}

}

 

** [src/main/resources] applicationContext.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"
	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-3.2.xsd">

	<context:annotation-config/>
	
	<!-- 
		2개의 Operand 빈 생성. (값은 자유)
		PlusOp 에서 자동 주입받아서 doOperate 구현하기 
	-->
	
	<bean id="operand1" class="ex3_1.Operand">
		<constructor-arg value="10"/>
		<qualifier value="operand1"/>
	</bean>
	
	<bean id="operand2" class="ex3_1.Operand">
		<constructor-arg value="4"/>
		<qualifier value="operand2"/>
	</bean>
	
	<bean id="op1" class="ex3_1.PlusOp"/>
	


</beans>

 

** [src/main/java] ex3_1 > DIApp.java

package ex3_1;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

public class DIApp {

	public static void main(String[] args) {
		
		System.out.println("Main 시작");
		
		AbstractApplicationContext ctx 
			= new GenericXmlApplicationContext("classpath:applicationContext.xml");
		
		OperatorBean operator = null;
		operator = ctx.getBean("op1", OperatorBean.class);
		
		int value = operator.doOperate();
		System.out.println("결과:" + value);


		ctx.close();
		System.out.println("Main 종료");
	}

}

 

 

9. Bean Configuration

 : Java 혹은 XML로 설정 가능

 


10. Bean 객체를 설정 하는 방법
1) XML을 이용한 DI설정 방법

2) JAVA를 이용한 DI설정 방법(@Configuration, @Bean ... )

3) XML에서 JAVA를 같이 DI설정
 
4) Java에서 XML 포함하여 설정(@ImportResource)   

 


11. Namespaces에서 context 설정하기

 : 파일은 Spring Config Editor로 열기

> Namespaces에서 context 체크

 

 

12. STS04_DI3_Config

** [src/main/java] com.lec.beans > Score.java

package com.lec.beans;

import java.util.Arrays;
import java.util.List;

public class Score {
	int kor;		// 국어 점수
	int eng;		// 영어 점수
	int math;		// 수학 점수
	String comment;	// 평가 코멘트
	
	// 기본 생성자
	public Score() {
		System.out.println("Score() 생성");
	}

	// 매개변수 생성자
	public Score(int kor, int eng, int math, String comment) {
		super();
		System.out.printf("Score(%d, %d, %d, %s) 생성\n", kor, eng, math, comment);
		this.kor = kor;
		this.eng = eng;
		this.math = math;
		this.comment = comment;
	}
	
	// 매개변수 생성자, 순서 변경
	public Score(int kor, int eng, String comment, int math) {
		super();
		System.out.printf("Score(%d, %d, %s, %d) 생성\n", kor, eng, comment, math);
		this.kor = kor;
		this.eng = eng;
		this.math = math;
		this.comment = comment;
	}
	
	// 매개변수 생성자
	public Score(int[] arr) {
		System.out.printf("Score(%s) 생성\n", Arrays.toString(arr));
		this.kor = arr[0];
		this.eng = arr[1];
		this.math = arr[2];
	}
	
	// getter, setter
	public int getKor() {
		return kor;
	}
	public void setKor(int kor) {
		this.kor = kor;
	}

	public int getEng() {
		return eng;
	}
	public void setEng(int eng) {
		this.eng = eng;
	}

	public int getMath() {
		return math;
	}
	public void setMath(int math) {
		this.math = math;
	}

	public String getComment() {
		return comment;
	}
	public void setComment(String comment) {
		this.comment = comment;
	}
	
	public void setScore(List<Integer> scores) {
		this.kor = scores.get(0);
		this.eng = scores.get(1);
		this.math = scores.get(2);
	}
	
	// 출력할때 이쁘게 나올려고..!!
	@Override
	public String toString() {
		return String.format("[Score 국어:%d 영어:%d 수학:%d 평가:%s]", 
				kor, eng, math, comment);
	}

}

 

** [src/main/java] com.lec.beans > Student.java

package com.lec.beans;

public class Student {
	String name;
	int age;
	Score score;	// reference 타입
	
	// 기본생성자
	public Student() {
		System.out.println("Student() 생성자");
	}

	// 매개변수 생성자
	public Student(String name, int age, Score score) {
		super();
		System.out.printf("Student(%s, %d, %s) 생성\n",
								name, age, score.toString());
		this.name = name;
		this.age = age;
		this.score = score;
	}

	
	// getter, setter
	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;
	}

	public Score getScore() {
		return score;
	}
	public void setScore(Score score) {	 // 매개변수가 reference 타입!
		this.score = score;
	}
	
	
	@Override
	public String toString() {
		return String.format("[Student 이름:%s, 나이:%d, 성적:%s]", 
				name, age, score.toString());
	}
	
}

 

** [src/main/resources] appCtx01_A.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"
	xmlns:c="http://www.springframework.org/schema/c"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="score1" class="com.lec.beans.Score"
		c:kor="100" c:eng="80" c:math="75" c:comment="좋아요"></bean>

</beans>

 

** [src/main/resources] appCtx01_B.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"
	xmlns:c="http://www.springframework.org/schema/c"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
	
	<bean id="score2" class="com.lec.beans.Score"
		c:kor="55" c:eng="66" c:math="23" c:comment="이것도 점수냐"/>
		
	<!--
		복수 개의 설정파일로부터 생성하는 컨텍스트의 경우
		중복되는 id가 있을 경우, 나중에 생성되는 bean이 덮어쓰기 한다.
		 
	-->
	<bean id="score1" class="com.lec.beans.Score"
		c:kor="4" c:eng="8" c:math="1" c:comment="꽝이요~"/>	


</beans>

 

** [src/main/java] com.lec.beans.Score > configMain01.java

package com.lec.spring.config01;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

import com.lec.beans.Score;

public class ConfigMain01 {

	public static void main(String[] args) {
		AbstractApplicationContext ctxA
			= new GenericXmlApplicationContext("classpath:appCtx01_A.xml");
		System.out.println("-- ctxA 생성 --");
		
		Score score1 = (Score)ctxA.getBean("score1");
		System.out.println(score1);
		
		// 컨텍스트 객체는 여러 개 만들 수 있다.
		
		AbstractApplicationContext ctxB
			= new GenericXmlApplicationContext("classpath:appCtx01_B.xml");
		System.out.println("-- ctxB 생성 --");
		
		Score score2 = (Score)ctxB.getBean("score2");
		System.out.println(score2);
	
		// 심지어 여러 개의 설정 파일로부터 컨텍스트 생성 가능!
		AbstractApplicationContext ctxAB =
				new GenericXmlApplicationContext(
						"classpath:appCtx01_A.xml","classpath:appCtx01_B.xml"
						);
		System.out.println("-- ctxAB 생성 --");
		
		Score score1_2 = ctxAB.getBean("score1", Score.class);
		Score score2_2 = ctxAB.getBean("score2", Score.class);
		
		// 다음 두개는 같다? 다르다? -> 주소 비교
		// 다르다 출력
		if(score1 == score1_2) {
			System.out.println("같다");
		} else {
			System.out.println("다르다");
		}
		// 결국 다른 컨테이너에 생성된 별개의 객체!!
		
		ctxA.close();
		ctxB.close();
		ctxAB.close();
	}

}

 

** [src/main/java] com.lec.spring.config02 > configMain02.java

package com.lec.spring.config02;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.lec.beans.Score;
import com.lec.beans.Student;

/*
 * JAVA 클래스를 이용한 설정
 * 클래스 이름 앞에 반드시 어노테이션 명시 필요
 * @Configuration --> 이 클래스는 '스프링 설정'에 사용되는 클래스 입니다.
 * 
 * 결국 컨테이너 역활을 함.
 * 
 */

@Configuration
public class AppConfig02 {

	@Bean
	public Score score1() {	// 메소드 이름 score1이 bean의 name값(id값)이 된다.
		return new Score(100, 85, 75, "좋아요");
	}
	
	@Bean
	public Student stu1() {
		return new Student("훈지예지", 34, score1());
	}
}

 

** [src/main/java] com.lec.spring.config02 > configMain02.java

package com.lec.spring.config02;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.lec.beans.Score;

public class ConfigMain02 {

	public static void main(String[] args) {
		// 'Java 설정파일' 사용한 컨텍스트 생성
		AnnotationConfigApplicationContext ctxA
			= new AnnotationConfigApplicationContext(AppConfig02.class);
		
		System.out.println("-- ctxA 생성 --");
		
		Score score1 = null;
		
		score1 = ctxA.getBean("score1", Score.class);
		System.out.println(score1);
		
		System.out.println(ctxA.getBean("stu1"));

		ctxA.close();
	}

}

 

** [src/main/java] com.lec.spring.config03 > AppConfig03.java

package com.lec.spring.config03;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.lec.beans.Score;

@Configuration
public class AppConfig03 {
	@Bean
	public Score score1() {	// id "score1"의 Score 빈 생성
		return new Score(60, 30, 45, "나빠요~");
	}
}

 

** [src/main.resources] appCtx03.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"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:c="http://www.springframework.org/schema/c"
	xmlns:p="http://www.springframework.org/schema/p"
	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-3.2.xsd">

	<context:annotation-config/>
	
	<!-- XML 파일에서 JAVA의 설정을 가져오기, score1 빈이 생성됨 -->
	<bean class="com.lec.spring.config03.AppConfig03"/>
	
	<bean id="score2" class="com.lec.beans.Score"
		c:kor="100" c:eng="80" c:math="75" c:comment="좋아요"/>
	
</beans>

 

** [src/main/java] com.lec.spring.config03 > ConfigMain03.java

package com.lec.spring.config03;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

public class ConfigMain03 {

	public static void main(String[] args) {
		// XML 설정으로부터 생성(XML 안에 Java 설정 포함)
		AbstractApplicationContext ctx
			= new GenericXmlApplicationContext("classpath:appCtx03.xml");
		System.out.println("-- ctx 생성 --");

		// Java에서 설정
		System.out.println(ctx.getBean("score1"));
		
		// XML에서 설정
		System.out.println(ctx.getBean("score2"));
		
		ctx.close();
	}

}

 

** [src/main/java] com.lec.spring.config04 > Appconfig04.java

package com.lec.spring.config04;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;

import com.lec.beans.Score;

@Configuration
@ImportResource("classpath:appCtx04.xml")	// XML 설정을 Java 설정 안에 가져오기
public class Appconfig04 {
	@Bean
	public Score score2() {
		return new Score(60, 30, 45, "나빠요");
	}
	
	@Bean
	public Score score1() {
		return new Score(100, 100, 100, "만점입니다~~!!");
	}
}

 

** [src/main.resources] appCtx04.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"
	xmlns:c="http://www.springframework.org/schema/c"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="score1" class="com.lec.beans.Score"
		c:kor="100" c:eng="80" c:math="75" c:comment="XML score1"/>
		
	<bean id="score2" class="com.lec.beans.Score"
		c:kor="100" c:eng="80" c:math="75" c:comment="XML score2"/>

</beans>

 

[src/main/java] com.lec.spring.config04 > ConfigMain04.java

package com.lec.spring.config04;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class ConfigMain04 {

	public static void main(String[] args) {
		AnnotationConfigApplicationContext ctx
			= new AnnotationConfigApplicationContext(Appconfig04.class);
		System.out.println("-- ctx 생성 --");
		
		// 중복된 값 -> XML에 적용된 값이 나중에...!!
		
		
		// XML에서 설정
		System.out.println(ctx.getBean("score1"));
		
		// Java에서 설정
		System.out.println(ctx.getBean("score2"));

		ctx.close();
	}

}



13. 빈(bean)의 스코프(scope)
1) singleton : 컨테이너에 딱 한 개의 인스턴스만 생김


2) prototype : getBean 등을 할 때 마다 새로운 인스턴스 생성

 

 

14. STS05_LifeCycle
** [src/main/java] com.lec.beans > Score.java

package com.lec.beans;

import java.util.Arrays;
import java.util.List;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

public class Score implements InitializingBean, DisposableBean {
	int kor;		// 국어 점수
	int eng;		// 영어 점수
	int math;		// 수학 점수
	String comment;	// 평가 코멘트
	
	// 기본 생성자
	public Score() {
		System.out.println("Score() 생성");
	}

	// 매개변수 생성자
	public Score(int kor, int eng, int math, String comment) {
		super();
		System.out.printf("Score(%d, %d, %d, %s) 생성\n", kor, eng, math, comment);
		this.kor = kor;
		this.eng = eng;
		this.math = math;
		this.comment = comment;
	}
	
	// 매개변수 생성자, 순서 변경
	public Score(int kor, int eng, String comment, int math) {
		super();
		System.out.printf("Score(%d, %d, %s, %d) 생성\n", kor, eng, comment, math);
		this.kor = kor;
		this.eng = eng;
		this.math = math;
		this.comment = comment;
	}
	
	// 매개변수 생성자
	public Score(int[] arr) {
		System.out.printf("Score(%s) 생성\n", Arrays.toString(arr));
		this.kor = arr[0];
		this.eng = arr[1];
		this.math = arr[2];
	}
	
	// getter, setter
	public int getKor() {
		return kor;
	}
	public void setKor(int kor) {
		this.kor = kor;
	}

	public int getEng() {
		return eng;
	}
	public void setEng(int eng) {
		this.eng = eng;
	}

	public int getMath() {
		return math;
	}
	public void setMath(int math) {
		this.math = math;
	}

	public String getComment() {
		return comment;
	}
	public void setComment(String comment) {
		this.comment = comment;
	}
	
	public void setScore(List<Integer> scores) {
		this.kor = scores.get(0);
		this.eng = scores.get(1);
		this.math = scores.get(2);
	}
	
	// 출력할때 이쁘게 나올려고..!!
	@Override
	public String toString() {
		return String.format("[Score 국어:%d 영어:%d 수학:%d 평가:%s]", 
				kor, eng, math, comment);
	}
	
	
	@Override
	public void afterPropertiesSet() throws Exception {
		// 빈 초기화 하는 과정에서 호출
		System.out.println("빈 초기화 afterPropertiesSet() 호출");
	}

	
	@Override
	public void destroy() throws Exception {
		// 빈 소멸 과정에서 호출
		System.out.println("빈 소멸 destroy() 호출");
	}

}


** [src/main/java] com.lec.beans > Student.java

package com.lec.beans;

public class Student {
	String name;
	int age;
	Score score;	// reference 타입
	
	// 기본생성자
	public Student() {
		System.out.println("Student() 생성자");
	}

	// 매개변수 생성자
	public Student(String name, int age, Score score) {
		super();
		System.out.printf("Student(%s, %d, %s) 생성\n",
								name, age, score.toString());
		this.name = name;
		this.age = age;
		this.score = score;
	}

	
	// getter, setter
	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;
	}

	public Score getScore() {
		return score;
	}
	public void setScore(Score score) {	 // 매개변수가 reference 타입!
		this.score = score;
	}
	
	
	@Override
	public String toString() {
		return String.format("[Student 이름:%s, 나이:%d, 성적:%s]", 
				name, age, score.toString());
	}
	
}

 

** [src/main/resources] appCtx01_A.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"
	xmlns:c="http://www.springframework.org/schema/c"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="score1" class="com.lec.beans.Score"
		c:kor="100" c:eng="80" c:math="75" c:comment="좋아요"></bean>

</beans>

 

** [src/main/resources] appCtx01_B.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"
	xmlns:c="http://www.springframework.org/schema/c"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
	
	<bean id="score2" class="com.lec.beans.Score"
		c:kor="55" c:eng="66" c:math="23" c:comment="이것도 점수냐"/>
		
	<!--
		복수 개의 설정파일로부터 생성하는 컨텍스트의 경우
		중복되는 id가 있을 경우, 나중에 생성되는 bean이 덮어쓰기 한다.
		 
	-->
	<bean id="score1" class="com.lec.beans.Score"
		c:kor="4" c:eng="8" c:math="1" c:comment="꽝이요~"/>	


</beans>

 

** [src/main/resources] appCtx2.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"
	xmlns:c="http://www.springframework.org/schema/c"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

	<!-- singleton scope(디폴트) : 컨테이너 생성 시점에서 생성됨
		  컨테이너 안에 하나의 인스턴스만 생성 : 아무리 getBean()으로 여러 번 가져와도 동일 객체 -->
	<bean id="score1" class="com.lec.beans.Score"
	 	c:kor="55" c:eng="66" c:math="23" c:comment="점수 구려요"
		scope="singleton"/>
	
	
	<!-- prototype scope
		  컨테이너 생성시점에서는 생성되지 않음
		 getBean()할 때마다 새로운 인스턴스로 생성 -->
	<bean id="score2" class="com.lec.beans.Score"
	  	c:kor="100" c:eng="80" c:math="90" c:comment="잘했어요"
		scope="prototype"/>

</beans>

 

** [src/main/java] com.lec.spring.lifecycle01 > LifeCycleMain01.java

package com.lec.spring.lifecycle01;

import org.springframework.context.support.GenericXmlApplicationContext;

import com.lec.beans.Score;

public class LifeCycleMain01 {

	public static void main(String[] args) {
		System.out.println("Main 시작");
		// new GenericXmlApplicationContext(설정 파일);		// 컨테이너 생성 + 컨테이너 설정
		
		// 먼저 컨테이너 '생성'
		GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();	// 컨테이너 생성
		System.out.println("컨테이너 생성 완료");
		
		// 나중에 설정을 load 할 수 있다.
		ctx.load("classpath:appCtx01_A.xml");	// 설정
												// 설정 파일을 로딩한 것이지 빈을 생성한 것이 아님...!!
		System.out.println("설정 load 완료");
		
		ctx.refresh();	// <-- refresh() 해야 제대로 설정(빈 생성) 완료 된다!
		System.out.println("컨테이너 refresh 완료");
		
		Score score1 = ctx.getBean("score1", Score.class);	// 사용
		System.out.println(score1);
		
		ctx.close();	// 종료
		
		System.out.println("Main 종료");
	}

}

 

** [src/main/java] com.lec.spring.scope > ScopeMain.java

package com.lec.spring.scope;

import org.springframework.context.support.GenericXmlApplicationContext;

import com.lec.beans.Score;

public class ScopeMain {

	public static void main(String[] args) {
		GenericXmlApplicationContext ctx =
				new GenericXmlApplicationContext("classpath:appCtx2.xml");
		System.out.println("-- ctx 생성 --");
		
		// scope="singleton" 
		Score score11 = ctx.getBean("score1", Score.class);
		Score score12 = ctx.getBean("score1", Score.class);
		System.out.println(score11);
		System.out.println(score12);
		
		if(score11 == score12) {
			System.out.println("동일 인스턴스");
		} else {
			System.out.println("다른 인스턴스");
		}
		
		score12.setComment("절망이야");
		System.out.println(score11);
		System.out.println(score12);
		
		// scope = "prototype"
		// getBean()할 때마다 bean 인스턴스 새롭게 생성
		Score score21 = ctx.getBean("score2", Score.class);
		Score score22 = ctx.getBean("score2", Score.class);
		
		score21.setComment("21입니다");
		score22.setComment("22입니다");
		System.out.println(score21);
		System.out.println(score22);
		
		if(score21 == score22) {
			System.out.println("score21 == score22");
		} else {
			System.out.println("score21 != score22");
		}
		
		ctx.close();
		System.out.println("종료");
	}

}

 

 

15. 다양한 빈 설정 방법들

1) Environment 객체 + Property 파일 이용한 스프링 빈 설정


2) Property 파일 이용한 설정(XML에 명시)


3) Property 파일 이용한 설정(Java에 명시) 


4) profile 속성 이용한 설정(XML에 명시) 

 

5) profile 속성 이용한 설정(Java에 명시)

 


16. Environment 객체
 : 설정 정보를 Java 코드가 아닌 외부에서 관리해서 프로그램에서 끌고 들어와서 이용, 
   설정 정보가 바뀌면 그 외부 파일(설정 파일)만 바꾸어도 동작  

 

17. Environment와 PropertySources
 : Environment의 PropertySources 객체는 여러 개의 PropertySource들을 가질수 있다.
   각 PropertySource에는 key:value 값들을 가지고 있다.

 

 

18. STS06_PropertySource

** [src/main/resources] admin.auth

admin.id=system
admin.pw=123456789

 

** [src/main/java] com.lec.spring.environment > AdminConnection.java

package com.lec.spring.environment;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;

public class AdminConnection implements EnvironmentAware, InitializingBean, DisposableBean {
	
	private Environment env;
	private String adminId;
	private String adminPw;

	// 빈 생성될때 호출
	// afterPropertiesSet() 이전에 호출, 즉 InitializingBean 보다 먼저 호출 됨에 주목
	@Override
	public void setEnvironment(Environment environment) {
		System.out.println("setEnvironment() 호출");
		setEnv(environment);
	}
	
	@Override
	public void afterPropertiesSet() throws Exception {
		System.out.println("afterPropertiesSet() 호출");
		// 설정 파일의 property 들.
		setAdminId(env.getProperty("admin.id"));
		setAdminPw(env.getProperty("admin.pw"));
	}
	
	@Override
	public void destroy() throws Exception {
		
	}

	
	// getter, setter
	public final Environment getEnv() {
		return env;
	}
	public final void setEnv(Environment env) {
		this.env = env;
	}

	public final String getAdminId() {
		return adminId;
	}
	public final void setAdminId(String adminId) {
		this.adminId = adminId;
	}

	public final String getAdminPw() {
		return adminPw;
	}
	public final void setAdminPw(String adminPw) {
		this.adminPw = adminPw;
	}
	
}

 

** [src/main/resources] appCtx1.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">

	<!-- 기본 생성자로 생성!!
		 constructor-arg 나 property 사용 안했음을 주목! -->
	<bean id="adminConnection" class="com.lec.spring.environment.AdminConnection"/>

</beans>

 

** [src/main/java] com.lec.spring.environment > EnvMain.java

package com.lec.spring.environment;

import java.io.IOException;

import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.io.support.ResourcePropertySource;

public class EnvMain {

	public static void main(String[] args) {
		System.out.println("Main 시작");

		// Context -> Environment -> PropertySources
		ConfigurableApplicationContext ctx = new GenericXmlApplicationContext();
		ConfigurableEnvironment env = ctx.getEnvironment();	// <- ConfigurableApplicationContext 소속 메소드다!
		MutablePropertySources propertySources = env.getPropertySources();
		
		// propertySources에 propertySource 추가
		try {
			// PropertySource 하나를 생성하여 PropertySources에 추가 : addLast() <-- 끝에 추가
			propertySources.addLast(new ResourcePropertySource("classpath:admin.auth"));	// IOException
			
			// 이제, Environment를 통해 원하는 property에 접근 가능
			// 굳이 '어느 PropertySource'의 '어느 property'를 지정할 필요 없다.
			// '어느 property'에 대한 것만 요청하면
			// PropertySources에 소속된 모든 PropertySource 들을 다 스캔해서 찾아낸다!
			System.out.println(env.getProperty("admin.id"));
			System.out.println(env.getProperty("admin.pw"));
			
		} catch (IOException e) {
			e.printStackTrace();
		} // end try
		
		// ctx.load() <-- 안된다 아래와 같이 변환 후 사용해야 사용 가능
		GenericXmlApplicationContext gCtx = (GenericXmlApplicationContext)ctx;
		gCtx.load("classpath:appCtx1.xml");	// 설정 로딩
		gCtx.refresh();	// 빈 생성
		
		AdminConnection adminConnection = gCtx.getBean("adminConnection", AdminConnection.class);
		
		System.out.println("admin ID : " + adminConnection.getAdminId());
		System.out.println("admin PW : " + adminConnection.getAdminPw());
		
		gCtx.close();
		System.out.println("Main 종료");
	}

}

 

** [src/main/resources] db.info

db.url=db.news.net
db.port=3309

 

** [src/main/java] com.lec.spring.property2.xml > DBConn.java

package com.lec.spring.property2.xml;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

public class DBConn implements InitializingBean, DisposableBean {
	private String id;
	private String pw;
	private String url;
	private String port;
	
	
	// getter / setter 
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getPw() {
		return pw;
	}
	public void setPw(String pw) {
		this.pw = pw;
	}
	public String getUrl() {
		return url;
	}
	public void setUrl(String url) {
		this.url = url;
	}
	public String getPort() {
		return port;
	}
	public void setPort(String port) {
		this.port = port;
	}
	
	@Override
	public void destroy() throws Exception {
		System.out.println("destroy()");	
	}
	
	@Override
	public void afterPropertiesSet() throws Exception {
		System.out.println("afterPropertiesSet()");
		
	}
	
}

 

** [src/main/resources] appCtx2.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"
	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-3.2.xsd">
		
	<!-- ↑ context namespace 우선 추가 -->
	
	<context:property-placeholder
		location="classpath:admin.auth, classpath:db.info"/>
		
	<bean id="dbConnection" class="com.lec.spring.property2.xml.DBConn">
	
		<!-- property로 값 세팅해주지 않는다면 비록 파일은 읽었으나 데이터를 꽂아주는 것이 아니기 때문에
			 Null 값이 출력됨 -->
			 
		<property name="id">
			<!-- EL 사용 -->
			<value>${admin.id}</value>
		</property>
		
		<property name="pw">
			<!-- EL 사용 -->
			<value>${admin.pw}</value>
		</property>
		
		<property name="url">
			<!-- EL 사용 -->
			<value>${db.url}</value>
		</property>
		
		<property name="port">
			<!-- EL 사용 -->
			<value>${db.port}</value>
		</property>
	</bean>

</beans>

 

** [src/main/java] com.lec.spring.property2.xml > PropertyMain2.java

package com.lec.spring.property2.xml;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

public class PropertyMain2 {

	public static void main(String[] args) {
		
		AbstractApplicationContext ctx = 
				new GenericXmlApplicationContext("classpath:appCtx2.xml");
		System.out.println("-- ctx 생성 --");
		
		
		DBConn conn = ctx.getBean("dbConnection", DBConn.class);
		System.out.println("admin.id : " + conn.getId());
		System.out.println("admin.pw : " + conn.getPw());
		System.out.println("db.url : " + conn.getUrl());
		System.out.println("db.port : " + conn.getPort());
		
		ctx.close();
	}

}

 

** [src/main/java] com.lec.spring.property3.java > DBConfig.java

package com.lec.spring.property3.java;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

import com.lec.spring.property2.xml.DBConn;

@Configuration
public class DBConfig {
	@Value("${admin.id}")
	private String id;
	@Value("${admin.pw}")
	private String pw;
	@Value("${db.url}")
	private String url;
	@Value("${db.port}")
	private String port;
	
	
	@Bean
	public static PropertySourcesPlaceholderConfigurer Properties() {
		System.out.println("Properties() 호출");
		PropertySourcesPlaceholderConfigurer configurer =
				new PropertySourcesPlaceholderConfigurer();
		
		Resource[] loResources = new Resource[2];
		Resource[] locations = new Resource[2];
		locations[0] = new ClassPathResource("admin.auth");
		locations[1] = new ClassPathResource("db.info");
		configurer.setLocations(locations);
		
		return configurer;
	}
	
	@Bean
	public DBConn dbConfig() {
		DBConn conn = new DBConn();
		
		conn.setId(id);
		conn.setPw(pw);
		conn.setUrl(url);
		conn.setPort(port);
		
		return conn;
	}

}


** [src/main/java] com.lec.spring.property3.java > PropertyMain3.java

package com.lec.spring.property3.java;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.lec.spring.property2.xml.DBConn;

public class PropertyMain3 {

	public static void main(String[] args) {
		AnnotationConfigApplicationContext ctx
			= new AnnotationConfigApplicationContext(DBConfig.class);
		System.out.println("-- ctx 생성 --");
		
		DBConn conn = ctx.getBean("dbConfig", DBConn.class);
		
		System.out.println("id : " + conn.getId());
		System.out.println("pw : " + conn.getPw());
		System.out.println("url : " + conn.getUrl());
		System.out.println("port : " + conn.getPort());
		
		ctx.close();
	}

}

 

** [src/main/java] com.lec.spring.profile4.xml > ServiceInfo.java

package com.lec.spring.profile4.xml;

public class ServiceInfo {
	private String ipNum;
	private String portNum;
	
	public final String getIpNum() {
		return ipNum;
	}
	public final void setIpNum(String ipNum) {
		this.ipNum = ipNum;
	}
	
	public final String getPortNum() {
		return portNum;
	}
	public final void setPortNum(String portNum) {
		this.portNum = portNum;
	}
}

 

** [src/main/resources] appCtx4_dev.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"
	profile="dev">
	
	<bean id="serverInfo" class="com.lec.spring.profile4.xml.ServiceInfo">
		<property name="ipNum" value="localhost"/>
		<property name="portNum" value="8181"/>
	</bean>


</beans>


** [src/main/resources] appCtx4_run.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"
	profile="run">

	<bean id="serverInfo" class="com.lec.spring.profile4.xml.ServiceInfo">
		<property name="ipNum" value="213.186.229.29"/>
		<property name="portNum" value="80"/>
	</bean>

</beans>

 

** [src/main/java] com.lec.spring.profile4.xml > ProfileMain4.java

package com.lec.spring.profile4.xml;

import org.springframework.context.support.GenericXmlApplicationContext;

public class ProfileMain4 {

	public static void main(String[] args) {
		String config = "run";
		
		GenericXmlApplicationContext ctx =
				new GenericXmlApplicationContext();
		
		// 현재 활성화할 profile이 무엇인지 세팅
		ctx.getEnvironment().setActiveProfiles(config);
		
		// 해당 profile의 설정 파일만 설정 된다!
		ctx.load("appCtx4_dev.xml", "appCtx4_run.xml");
		ctx.refresh();

		ServiceInfo info = ctx.getBean("serverInfo", ServiceInfo.class);
		System.out.println("ip: " + info.getIpNum());
		System.out.println("port: " + info.getPortNum());
		ctx.close();
		
	}

}

'웹_프론트_백엔드 > JAVA프레임윅기반_풀스택' 카테고리의 다른 글

2020.06.23  (0) 2020.06.23
2020.06.22  (0) 2020.06.22
2020.06.18  (0) 2020.06.18
2020.06.17  (0) 2020.06.17
2020.06.16  (0) 2020.06.16