Spring Framework7,8,9(의존성 주입:필드,setter,생성자,Qualifier,어노테이션)

유성훈·2023년 2월 10일
0

Spring Framework공부

목록 보기
4/7

📌전체적인 프로젝트 구조



📌의존성 주입(필드주입)

📍package com.ysh.studySpring.dependency;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import lombok.Data;
@Component
@Data
public class Coding {
	//Computer computer = new Computer을 하면 의존성이 강하기 때무에 아래처럼 사용
	@Autowired  //서버가 실행되면 코딩이라는 것을 쓰면 spring이 자동으로 computer도 주입해준다.
	//편하게 주입이 가능하나 순환참조(무한루프)시 오류가 발생하지 않기 때문에 stackoverflow발생
	private final Computer computer;  //ex. 코딩을 하기 위해서는 computer가 필요하다 -> 의존성 관례
	//private를 사용해서 외부에서 직접 사용하지 못 하고 getter, setter를 통해 수정하도록 하는 것이 좋다.
	//final은 외부에서 접근 해서 수정을 하지 멋 하도록 사용
}
📍package com.ysh.studySpring.dependency;
import org.springframework.stereotype.Component;
import lombok.Data;
@Component //해당 객체를 spring에서 관리하도록 설정
@Data
public class Computer {
}
📍src/main/webapp/WEB-INF/spring/root-context.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 https://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
	<!-- Root Context: defines shared resources visible to all other web components -->
	<!-- 해당 패키지에서 component 어노테이션 스캔이 가능해진다. -->
	<context:component-scan base-package="com.ysh.studySpring.dependency"></context:component-scan>
</beans>
<!--  하단 NameSpaces -> conxtext체크 -->
📍package dependency;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.ysh.studySpring.dependency.Coding;
import lombok.extern.log4j.Log4j;
//단위 테스트를 하는 파일로 서버(WAS)와 따로 생각한다.
//서버가 아니라 junit이라는 단위 테스트 프로그램을 돌려 콘솔만 찍는다. (WAS와 별개)
@RunWith(SpringJUnit4ClassRunner.class) // 어떤 프로그램으로 테스트를 돌릴지 알려줘야 한다.
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml") //rootContext 위치를 알려주어야 한다.
@Log4j //해당 객체를 통해 에러, 자동줄바꿈등 로그 객체를 출력하여 보기 위해 써주어야 한다.
public class dependencyTest {
	@Autowired
	private Coding coding; //Autowired를 통해 Coding이 어디있는지 자동으로 알려준다.
	@Test //사용하면 단위 테스트로 인식이 된다.
	public void checkDependencyInjection() {
		log.info("---------------------------");
		log.info("coding :" + coding);
		log.info("computer:" + coding.getComputer());
		log.info("---------------------------");
	}
}


📌의존성 주입(setter주입, 생성자 주입 개념)

📍package com.ysh.studySpring.dependency;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import lombok.Data;
import lombok.Getter;
@Component
@Getter
public class Coding {
	//Computer computer = new Computer을 하면 의존성이 강하기 때무에 아래처럼 사용
    //@Autowired  //서버가 실행되면 코딩이라는 것을 쓰면 spring이 자동으로 computer도 주입해준다.
	//편하게 주입이 가능하나 순환참조(무한루프)시 오류가 발생하지 않기 때문에 stackoverflow발생
    private Computer computer;  //ex. 코딩을 하기 위해서는 computer가 필요하다 -> 의존성 관례
	//private를 사용해서 외부에서 직접 사용하지 못 하고 getter, setter를 통해 수정하도록 하는 것이 좋다.
    //final을 붙이면 다른 곳에서 변형이 가능 @Data를 사용하지 않으면 오류(필드주입만 할 경우 -> 생성자 주입 까지 해야 오류X)
	//-> 상수이기 대문에 생성가 동시에 주입을 해주어야 한다.(생성자는 값이 없어도 주입 가능)
	//Setter주입
	//편하게 주입이 가능하나 순환참조(무한 루프)시 오류가 발생하지 않기 때문에 stackoverflow발생
	//final을 붙일 수 없기 때문에 다른 고셍서 변형 가능
	//외부에서 직접 주입 가능
	//setter주입은 잘 사용하지 않는다.
	@Autowired
	public void setComputer(Computer computer) {
		this.computer = computer;
	}
	//메모리에 필드를 올리고 주입을 받는 것 : setter, getter 주입 (올리고 나서 오류가 생기면 알 수없다.)
	//메모리에 올리면서 주입을 받는 것 : 생성자 주입
	//생성자 주입
	//순환 참조시 컴파일러가 인지 가능, 오류 발생
	//메모리에 할당하면서 초기값으로 주입되므로 final 키워드 사용 가능, 다른 곳 에서 변형 불가능 -> 안전하다
	//의존성 주입이 되지 않으면 객체가 생성되지 않으므로 (올리면서 주입을 받기 때문)
	@Autowired
	public Coding(Computer computer) {
		super();
		this.computer = computer;
	}  //@AllArgsConstructor 상단에 사용하면 생성자 코드를 작성 하지 않아도 자동으로 생성된다
	//위의 세가지 주입 중 가장 많이 사용되고 안전한 주입은 생성자 주입이다.
}


📌의존성 주입(Qualifier 실습)

📍package com.ysh.studySpring.qulifier;
//해상도를 갖고 오는 경우
public interface Computer {
	public int getScreenWidth();
}
📍package com.ysh.studySpring.qulifier;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component
@Qualifier("deskTop")
public class Desktop implements Computer{
	@Override
	public int getScreenWidth() {
		return 1920;
	}
}
📍package com.ysh.studySpring.qulifier;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component
@Qualifier("lapTop")
public class Laptop implements Computer {
	@Override
	public int getScreenWidth() {
		// TODO Auto-generated method stub
		return 1280;
	}
}
📍package dependency;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Primary;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.ysh.studySpring.qulifier.Computer;
import lombok.extern.log4j.Log4j;
@RunWith(SpringJUnit4ClassRunner.class) // 어떤 프로그램으로 테스트를 돌릴지 알려줘야 한다.
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml") // rootContext 위치를 알려주어야 한다.
@Log4j // 해당 객체를 통해 에러, 자동줄바꿈등 로그 객체를 출력하여 보기 위해 써주어야 한다.
public class QualifierTests {
	@Autowired
	@Qualifier("lapTop") 
	private Computer lapTop; // 단위 테스트는 필드 주입
	@Test
	public void testQualifier() {
		log.info("=================");
		log.info("computer : " + lapTop);
		log.info("screen width : " + lapTop.getScreenWidth());
		log.info("=================");
	}
}


✏️Qualifier 예시

  • Qualifier
    @Autowired를 통해 객체를 주입할 때 같은 타입의 객체가 여러개 있다면 구분할 수 없다. (ex. 망치가 100개 있을때 망치를 달라고 하면 어떤 망치를 말하는지 알수 없다.), 이때 @Qulifier를 통해 식별자를 부여하면 원하는 객체를 주입받을 수 있다.
    예시
    [1]
    public class 클래스A implements 인터페이스{
    }
    public class 클래스B implements 인터페이스{
    }
    [2]
    @Autowired
    private 인터페이스 객체; -> 이때 인터페이스 파일이 열러개 있을 경우 어떤 인터페이스 타입을 원하는가? (classA or clasB ??)
    ==>따라서 해결 방법
    [1]
    @Qulifier("식별자A")
    public class 클래스A implements 인터페이스{
    }
    @Qulifier("식별자B")
    public class 클래스B implements 인터페이스{
    }
    [2]
    @Autowired
    @Qulifier("식별자A") -> 원하는 객체를 선택해서 주입 받는다.
    private 인터페이스 객체;



📌어노테이션 정리

  • @Compoent어노테이션 사용
    ➡️ spring에게 대신 관리를 해달라는 의미(해당 객체를 spring에서 관리)
  • @Data어노테이션 사용
    ➡️ loombok기능을 사용하기 위해서(getter, setter, 생성자.. )
  • @RunWith(어떠한 프로그램으로 테스트를 돌릴 것인가)
  • @ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
    ➡️ rootContext 위치를 알려주어야 한다.
  • @Log4j
    ➡️ 해당 객체를 통해 에러, 자동줄바꿈등 로그 객체를 출력하여 보기 위해 써주어야 한다.
  • @Autowired
    ➡️ 서버가 실행되면 코딩이라는 것을 쓰면 spring이 자동으로 computer도 주입해준다.
    ➡️편하게 주입이 가능하나 순환참조(무한루프)시 오류가 발생하지 않기 때문에 stackoverflow발생
    ➡️외부 에서 해당 클래스 필드에 접근 하기 위해서 객체화를 하는 과정을 유연하게 하기 위해 사용
  • @AllArgsConstructor
    ➡️ 안에 있는 모든 필드를 초기화 할 수 있는 생성자를 만들어 준다.
  • @RequiredArgsConstructor
    ➡️ 여러개 필드 중 특정 필드에 대해서만 주입을 받고 싶을 경우 (해당 필드에 final이 붙어 있거나 @NonNull어노테이션이 붙어 있는경우만 해당)
  • @Qualifier
    ➡️ 여러개의 타입을 갖고 있을 경우 어떤 타입을 줘야할지 문제를 해결하기 위한 어노테이션
  • @Primary
    ➡️ 여러개 중 주입 받은 객체를 default로 설정, 이 때에는 식별자 없이 주입 시
  • @Primary가 사용된 객체가 주입 된다.


📌의존성 주입 예제

설명
dependency package
1.Restaurant 클래스 선언
2.Chef 클래스 선언
3.의존 관계를 확립하고 생성자 주입 진행
4.단위 테스트를 통해 객체 확인

📍package com.ysh.studySpring.dependency;
import org.springframework.stereotype.Component;
import lombok.Data;
import lombok.RequiredArgsConstructor;
@Component
@Data
public class Chef {
}
📍package com.ysh.studySpring.dependency;
import org.springframework.stereotype.Component;
import lombok.Data;
import lombok.RequiredArgsConstructor;
@Component //spring이 관리하는 파일
@Data //기본 생성자
@RequiredArgsConstructor
public class Restaurant {
	private final Chef chef;
}
📍package dependency;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.ysh.studySpring.dependency.Coding;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.ysh.studySpring.dependency.Coding;
import com.ysh.studySpring.dependency.Restaurant;
import lombok.extern.log4j.Log4j;
//단위 테스트를 하는 파일로 서버(WAS)와 따로 생각한다.
//서버가 아니라 junit이라는 단위 테스트 프로그램을 돌려 콘솔만 찍는다. (WAS와 별개)
@RunWith(SpringJUnit4ClassRunner.class) // 어떤 프로그램으로 테스트를 돌릴지 알려줘야 한다.
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml") //rootContext 위치를 알려주어야 한다.
@Log4j //해당 객체를 통해 에러, 자동줄바꿈등 로그 객체를 출력하여 보기 위해 써주어야 한다.
public class dependencyTest {
@Autowired
private Restaurant restarant;
	@Test //사용하면 단위 테스트로 인식이 된다.
	public void checkDependencyInjection() {
		log.info("---------------------------");
        	log.info("restarant :" + restarant);
		log.info("chef:" + restarant.getChef());
		log.info("---------------------------");
	}
}


📌qualifier 문제

문제
qualifier package
1.Restaurant인터페이스 선언
2.steak가격 80,000원 선언, saladbar 유무 여부 선언
3.outback 클래스 선언, restaurant 지정
4.vips 클래스 선언, restarant 지정
5.기본 주입 대상은 vips로 설정
6.단위 테스트를 통해 객체 확인

📍package com.ysh.studySpring.qulifier;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component
@Qualifier("outback")
public class OutBack implements Restarant {
	@Override
	public boolean hasSalad() {
		// TODO Auto-generated method stub
		return false;
	}
}
📍package com.ysh.studySpring.qulifier;
public interface Restarant {
	public int steak = 80000; //interface는 final, static자동으로 붙는ㄷ. --> 상수
	public boolean hasSalad();
}
📍package com.ysh.studySpring.qulifier;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
@Component
@Qualifier("vips") @Primary
public class Vips implements Restarant {
	@Override
	public boolean hasSalad() {
		// TODO Auto-generated method stub
		return true;
	}
}
📍package dependency;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.ysh.studySpring.dependency.Restaurant;
import com.ysh.studySpring.qulifier.OutBack;
import com.ysh.studySpring.qulifier.Restarant;
import com.ysh.studySpring.qulifier.Vips;
import lombok.extern.log4j.Log4j;
@RunWith(SpringJUnit4ClassRunner.class) // 어떤 프로그램으로 테스트를 돌릴지 알려줘야 한다.
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml") // rootContext 위치를 알려주어야 한다.
@Log4j // 해당 객체를 통해 에러, 자동줄바꿈등 로그 객체를 출력하여 보기 위해 써주어야 한다.
public class QualifierTests {
	@Autowired
@Qualifier("outback")
	private Restarant outback;
	@Qualifier("vips")
	@Autowired
	private Restarant vips;
	@Autowired
	private Restarant restaurant;
	@Test
	public void testQualifier() {
		log.info("=================");
        log.info("outback : " + outback);
		log.info("outback salad: " + outback.hasSalad());
		log.info("steak price: " + OutBack.steak);
		log.info("=================");
		log.info("=================");
		log.info("vips : " + vips);
		log.info("vips salad: " + vips.hashCode());
		log.info("steak price: " + Vips.steak);
		log.info("=================");
		log.info("=================");
		log.info("vips : " + restaurant);
		log.info("vips salad: " + restaurant.hashCode());
		log.info("steak price: " + Restarant.steak);
		log.info("=================");
	}
}
profile
프로그래밍 공부

0개의 댓글