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 |