생성자 주입, Setter메소드 주입, annotation 주입

brave_chicken·2024년 4월 27일

잇(IT)생 챌린지

목록 보기
37/90

2) DI(Dependency Injection)

  • 개발자가 스프링컨테이너로부터 직접 빈을 찾아와서 사용하는 DL과 다르게 Spring IoC 컨테이너 내부에서 설정파일에 등록된 빈을 직접 생성하고 내부에서 의존하고 있는 빈도 생성해서 연결시켜주는 작업
  • 스프링컨테이너에 의해서 자동으로 객체의 관계가 설정되도록 하려면 빈이 사용하는 의존모듈으로 어떤 방법으로 주입받을 것인지 미리 설정파일에 등록해야한다. 또한 주입받을 방법에 맞는 메소드를 미리 준비해놓아야 한다.

[Constructor Injection]
=> 생성자를 통해서 주입받기(주로 사용하는 방법)
(1) 주입받을 클래스에서 객체를 주입받을 수 있도록 생성자를 미리 정의해놓아야한다.
(2) 설정파일에도 매개변수가 있는 생성자를 호출할 수 있도록 즉, 객체를 주입받을수있도록 엘리먼트(태그)를 정의해야한다.

[Setter Injection(Property Injection)]

  • Setter 메소드를 통해서 주입받기
  • 컨테이너로부터 주입받는 방식이 생성자가 아니라 setter메소드를 통해 전달받도록 설정
  • 기본생성자와 setter메소드를 준비해야 한다.
  • < property > 엘리먼트를 정의하고 작업해야한다.
  • constuctor-args없어서 기본생성자로 작업해야함 => 기본생성자 있는지 확인

< constructor-args >가 있는 경우 매개변수가 있는 생성자를 찾습니다. 기본생성자는 setter injection만 사용하는 경우 와 어노테이션을 하는 경우 내부에서 어떤 생성자를 사용해야 할 지 모르므로 기본생성자를 찾습니다.

5. 어노테이션으로 객체주입

  • 컨테이너가 어노테이션 기호를 보고 객체를 생성해서 자동으로 연결시켜준다.
  • 설정파일에 어떤 패키지의 클래스들을 생성할 것인지 등록해야 한다.
    (IoC컨테이너에게 어느 위치의 클래스를 빈으로 관리해야하는지 알려줌)
    <context:component-scan base-package=""/>의 base-package에 IoC컨테이너가 스캔하며 객체를 생성할 수 있도록 패키지를 등록
  • 스프링컨테이너가 생성될때 설정파일에 등록된 패키지를 스캐닝해서 생성해야할 빈을 생성하고 주입해야할 빈은 주입하면서 모든 빈을 생성한다.
    => 클래스에 어노테이션이 추가된 빈만 생성
  • 생성자, 필드, setter메소드를 통해서 주입받을 수 있다.

1) 빈으로 생성하기 위해서 추가할 어노테이션

스프링 컨테이너가 관리할 수 있도록 빈으로 등록하기 위해서 아래의 조건에 맞게 어노테이션을 추가
@Component : 일반적인 빈으로 등록하는 경우 -> 일반적
(오브젝트 느낌, 상속의개념으로 봐도됨, 얘가 상위개념 밑에 세개가 하위개념)

구체적으로 들어가면..
@Service : 서비스 역할을 담당하는 빈을 등록
@Repository : db연동을 위한 빈을 등록
@Controller : 스프링웹 MVC에서 사용하는 컨트롤러로 등록
=> < bean >< /bean>으로 등록하는 것과 동일
=> 빈의 이름을 별도로 지정하지 않으면 클래스명의 첫글자를 소문자로 변경한 이름으로 빈을 등록

2) 객체연결(주입)

@Autowired : 같은 타입의 빈이 컨테이너 내부에 존재하면 자동으로 연결
같은 타입의 빈이 두개 이상인 경우 어떤 빈을 매칭해야하는지 판단을 못한다.

  • 만약 필드명과 빈의 이름이 같은경우 필드명과 이름이 같은 빈이 autowired됨!(좀 깊이 들어간 내용)
  • 같은 타입으로 여러개의 빈이 존재하는 경우 빈을 등록할 때 빈의 이름을 같이 등록=> 일반적

@Qualifier : 같은 타입의 빈이 여러개인 경우 정확하게 매칭시킬 빈의 이름을 명시한다.
@Qualifier("빈의이름")

실습

생성자를 통해서 객체주입

constructor.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">
	<!-- basic -->
	<bean id="dao" class="basic.MemberDAO"/>
	<bean id="insa" class="basic.InsaImpl">
		<!-- constructor-arg가 정의된 갯수를 보면서 매개변수가 몇 개인지 파악 
			constructor-arg가 하나면 매개변수 한 개인 생성자를 호출하고
			ref bean="dao"에 의해서 매개변수의 타입이 dao로 등록된 빈의 타입이라는 것을 판단한다.
		-->
		<constructor-arg><!-- 매개변수1개 -->
			<!-- bean의 id가 dao인 빈을 연결 -->
			<ref bean="dao"/>
		</constructor-arg>
	</bean>
	
	<!-- di.constructor.exam01 -->
	<bean id="dice" class="di.constructor.exam01.Dice"/>
	<bean id="player" class="di.constructor.exam01.Player">
		<constructor-arg ref="dice" /><!-- 위의꺼 약식으로 표현한것 -->
	</bean>
	
	<!-- di.constructor.exam02 -->
	<bean id="logic" class="di.constructor.exam02.LogicImpl"/>
	<bean id="service" class="di.constructor.exam02.ServiceImpl">
		<constructor-arg value="데이먼스이어" type="String"/>
		<constructor-arg value="yours" type="String"/>
		<constructor-arg ref="logic" type="di.constructor.exam02.Logic"/>
	</bean>
	<!-- <constructor-arg value="데이먼스이어" index="0"/>
		<constructor-arg value="yours" index="1"/>
		<constructor-arg ref="logic" index="2"/> -->
		
	<!-- di.constructor.exam03 -->
	<bean id="dao2" class="di.constructor.exam03.MysqlArticleDAO"/>
	<bean id="mgr" class="di.constructor.exam03.WriteArticleMgr">
		<constructor-arg ref="dao2"/>
 	</bean>
</beans>

basic

interface Insa

public interface Insa {
	void addUser(MemberDTO user);
	MemberDTO getUser(String id);
	void setDao(MemberDAO dao);
	MemberDAO getDao();
}

InsaImpl /서비스의 역할


public class InsaImpl implements Insa {
	MemberDAO dao;
	public InsaImpl() {
		System.out.println("기본생성자 - InsaImpl");
	}
	
	public InsaImpl(MemberDAO dao) {
		super();
		this.dao = dao;
		System.out.println("매개변수 1개 생성자 - InsaImpl");
	}

	public MemberDAO getDao() {
		return dao;
	}

	public void setDao(MemberDAO dao) {
		this.dao = dao;
	}

	@Override
	public void addUser(MemberDTO user) {
		dao.add(user);		
	}

	@Override
	public MemberDTO getUser(String id) {
		dao.getUser("id");
		return null;
	}

}

MemberDAO

public class MemberDAO {
	public MemberDAO() {
		System.out.println("기본생성자 - MemberDAO");
	}
	public void add(MemberDTO user){
		System.out.println("db에 insert하기");
	}
	public MemberDTO getUser(String id){
		System.out.println("사용자정보 가져오기 - db에서 조회");
		return null;
	}
}

MemberDTO

public class MemberDTO {
	private String id;
	private String pass;
	private String name;
	public MemberDTO(){
		
	}
	public MemberDTO(String id, String pass, String name) {
		super();
		this.id = id;
		this.pass = pass;
		this.name = name;
	}

	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getPass() {
		return pass;
	}
	public void setPass(String pass) {
		this.pass = pass;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
}

TestMain

public class TestMain {
	public static void main(String[] args) {
		//1. setter메소드를 이용해서 멤버변수를 셋팅하기
//		MemberDAO dao = new MemberDAO();
//		Insa insa = new InsaImpl();
//		insa.setDao(dao);
		
		//2. 생성자를 이용해서 멤버변수를 셋팅
		ApplicationContext factory 
			= new ClassPathXmlApplicationContext("/config/constructor.xml");
		Insa insa = (Insa)factory.getBean("insa");
		
		MemberDTO user = 
				new MemberDTO("jang","1234","장동건");
		insa.addUser(user);

	}

}

di.constructor.exam01

interface AbstractDice

public interface AbstractDice {
	int getDiceValue();
}

interface AbstractPlayer

public interface AbstractPlayer {
	void play();
	int getTotalValue();
}

Dice

public class Dice extends Random implements AbstractDice{
	public Dice() {
		System.out.println("기본 생성자 - Dice");
	}
	public int getDiceValue(){
		return nextInt(6)+1;
	}
}

Dice2

public class Dice2 extends Random implements AbstractDice{
	//그냥 보여주려고 만든거
	public Dice2() {
		System.out.println("Dice2 기본생성자");
	}
	@Override
	public int getDiceValue(){
		return (nextInt(6)+1)*2;
	}
}

Player

public class Player implements AbstractPlayer{
	AbstractDice d;//상위버전으로 만들어야 유연하게 사용할수있음=유지보수적게해도됨
	int totalValue=0;//totalValue변수는 주사위를 굴리고 얻은 결과가 저장되므로 컨테이너가 생성해주지 않아도 된다.
	public Player() {
		
	}
	public Player(AbstractDice d) {
		super();
		this.d = d;
		System.out.println("매개변수 1개 생성자 - Player");
	}
	public void play(){
		totalValue=0;
		for (int i = 0; i < 3; i++) {
			totalValue+=d.getDiceValue();
		}
	}
	public int getTotalValue(){
		return totalValue;
	}
}

Test01

public class Test01 {
	public static void main(String[] args) {
//		Player p = new Player();
//		p.play();
		
		ApplicationContext factory
			= new ClassPathXmlApplicationContext("/config/constructor.xml");
		AbstractPlayer player = (AbstractPlayer)factory.getBean("player");
//		AbstractPlayer player = factory.getBean("player",AbstractPlayer.class);
//		이렇게도 표현할 수 있다 보여준거. 이러면 캐스팅 안해도됨
		player.play();
		System.out.println("세번 굴린 주사위의 합:"+player.getTotalValue());
	}

}

di.constructor.exam02

Constructor Injection을 적용해서 객체가 관리될 수 있도록 작업해주세요

interface Logic

public interface Logic {
	void testLogic();
}

interface MyService

public interface MyService {
	void testService();
}

LogicImpl

public class LogicImpl implements Logic {
	@Override
	public void testLogic() {
		System.out.println("db연동,xml,json,연산등을 수행하는 비지니스 메소드");
	}
}

ServiceImpl

public class ServiceImpl implements MyService {
	String name;
	String msg;
	Logic logic;
	//Main만들때 ServiceImpl의 testService메소드를 호출
	public ServiceImpl() {
		
	}
	
	public ServiceImpl(String name, String msg, Logic logic) {
		super();
		this.name = name;
		this.msg = msg;
		this.logic = logic;
	}
	
	@Override
	public void testService() {
		System.out.println(msg+","+name);
		logic.testLogic();
	}
}

MainTest

public class MainTest {
	public static void main(String[] args) {
		ApplicationContext factory = new ClassPathXmlApplicationContext("/config/constructor.xml");
		MyService bean = (MyService)factory.getBean("service");
		
		bean.testService();
	}
}

di.constructor.exam03

아래와 같은 구성으로 클래스를 작성하고 생성자 방식으로 객체를 주입 받을 수 있도록 구현하세요

interface IArticleDAO

public interface IArticleDAO {
	void insert(ArticleDTO article);
}

interface IwriteArticleMgr

public interface IwriteArticleMgr {
	void write(ArticleDTO article);
}

ArticleDTO

public class ArticleDTO {
	private String name;
	private String title;
	private String content;
	private String date;
	
	public ArticleDTO (){
		
	}
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}
	public String getDate() {
		return date;
	}
	public void setDate(String date) {
		this.date = date;
	}
}

WriteArticleMgr

public class WriteArticleMgr implements IwriteArticleMgr{
	private IArticleDAO ADA;
	
	public WriteArticleMgr() {
		
	}
	
	public WriteArticleMgr(IArticleDAO ADA) {
		super();
		this.ADA = ADA;
	}

	@Override
	public void write(ArticleDTO ADT) {
		ADA.insert(ADT);
	}
}

MysqlArticleDAO

public class MysqlArticleDAO implements IArticleDAO{
	@Override
	public void insert(ArticleDTO article) {
		System.out.println("Mysql에 삽입하기");
	}
}

OracleArticleDAO

public class OracleArticleDAO implements IArticleDAO{
	@Override
	public void insert(ArticleDTO article) {
		System.out.println("Oracle에 삽입하기");
	}
}

TestMain

public class TestMain {
	public static void main(String[] args) {
		ApplicationContext factory = new ClassPathXmlApplicationContext("/config/constructor.xml");
		
		IwriteArticleMgr mgr = (IwriteArticleMgr)factory.getBean("mgr");
		
		ArticleDTO dto = new ArticleDTO();
		dto.setName("홍길동");
		dto.setTitle("개발자");
		dto.setContent("의존성주입");
		dto.setDate("2024-04-26");
		mgr.write(dto);
	}
}

setter메소드를 통해서 객체주입

setter.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">
	<!-- basic.setter -->
	<bean id="dao" class="basic.setter.MemberDAO"/>
	<bean id="insa" class="basic.setter.InsaImpl">
<!-- property엘리먼트의 name속성은 setter메소드의 set을 빼고 첫글자를 소문자로 변경한 이름(=멤버변수) 
=> name은 setter 메소드명과 관련, setAbc 메소드라면 name은 abc -->
		<property name="dao" ref="dao"/>
	</bean>
	
	<!-- di.setter.exam01 -->
	<bean id="dice" class="di.setter.exam01.Dice"/>
	<bean id="player" class="di.setter.exam01.Player">
		<property name="d" ref="dice"></property>
	</bean>
	
	<!-- di.setter.exam02 -->
	<bean id="logic" class="di.setter.exam02.LogicImpl"/>
	<bean id="service" class="di.setter.exam02.ServiceImpl">
		<property name="name" value="드뷔시"/>
		<property name="msg" value="달빛"/>
		<property name="logic" ref="logic"/>
	</bean>
	
	<!-- di.setter.exam03 -->
	<bean id="dao2" class="di.setter.exam03.MysqlArticleDAO"/>
	<bean id="mgr" class="di.setter.exam03.WriteArticleMgr">
		<property name="ADA" ref="dao2"/>
	</bean>
</beans>

basic.setter

나머지는 위와 동일

InsaImpl

public class InsaImpl implements Insa {
	MemberDAO dao;
	public InsaImpl() {
		System.out.println("기본생성자 - InsaImpl");
	}
	
	public InsaImpl(MemberDAO dao) {
		super();
		this.dao = dao;
		System.out.println("매개변수 1개 생성자 - InsaImpl");
	}

	public MemberDAO getDao() {
		System.out.println("getDao()");
		return dao;
	}

	public void setDao(MemberDAO dao) {
		System.out.println("setDao()");
		this.dao = dao;
	}

	@Override
	public void addUser(MemberDTO user) {
		dao.add(user);		
	}

	@Override
	public MemberDTO getUser(String id) {
		dao.getUser("id");
		return null;
	}

}

TestMain

public class TestMain {
	public static void main(String[] args) {
		ApplicationContext factory 
			= new ClassPathXmlApplicationContext("/config/setter.xml");
		Insa insa = (Insa)factory.getBean("insa");
		
		MemberDTO user = 
				new MemberDTO("jang","1234","장동건");
		insa.addUser(user);
	}
}

di.setter.exam01

Player

public class Player implements AbstractPlayer{
	AbstractDice d;//상위버전으로 만들어야 유연하게 사용할수있음=유지보수적게해도됨
	int totalValue=0;//totalValue변수는 주사위를 굴리고 얻은 결과가 저장되므로 컨테이너가 생성해주지 않아도 된다.
	public Player() {
		//반드시 있어야함
	}
	public Player(AbstractDice d) {
		super();
		this.d = d;
	}
	public AbstractDice getD() {
		return d;
	}
	public void setD(AbstractDice d) {
		this.d = d;
	}
	public void play(){
		totalValue=0;
		for (int i = 0; i < 3; i++) {
			totalValue+=d.getDiceValue();
		}
	}
	public int getTotalValue(){
		return totalValue;
	}
	
}

Test01

public class Test01 {
	public static void main(String[] args) {
		ApplicationContext factory
			= new ClassPathXmlApplicationContext("/config/setter.xml");
		AbstractPlayer player = (AbstractPlayer)factory.getBean("player");
        
		player.play();
		System.out.println("세번 굴린 주사위의 합:"+player.getTotalValue());
	}
}

di.setter.exam02

ServiceImpl

public class ServiceImpl implements MyService {
	String name;
	String msg;
	Logic logic;

	public ServiceImpl() {
		
	}
	
	public ServiceImpl(String name, String msg, Logic logic) {
		super();
		this.name = name;
		this.msg = msg;
		this.logic = logic;
	}
	
	@Override
	public void testService() {
		System.out.println(msg+","+name);
		logic.testLogic();
	}

	public Logic getLogic() {
		return logic;
	}

	public void setLogic(Logic logic) {
		this.logic = logic;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getMsg() {
		return msg;
	}

	public void setMsg(String msg) {
		this.msg = msg;
	}
}

MainTest

public class MainTest {
	public static void main(String[] args) {
		ApplicationContext factory = new ClassPathXmlApplicationContext("/config/setter.xml");
		MyService bean = (MyService)factory.getBean("service");
		
		bean.testService();
	}
}

di.setter.exam03

WriteArticleMgr

public class WriteArticleMgr implements IwriteArticleMgr{
	private IArticleDAO ADA;

	public WriteArticleMgr() {
		
	}
	
	public WriteArticleMgr(IArticleDAO ADA) {
		super();
		this.ADA = ADA;
	}

	@Override
	public void write(ArticleDTO ADT) {
		ADA.insert(ADT);
	}

	public IArticleDAO getADA() {
		return ADA;
	}

	public void setADA(IArticleDAO aDA) {
		ADA = aDA;
	}
}

TestMain

public class TestMain {
	public static void main(String[] args) {
		ApplicationContext factory = new ClassPathXmlApplicationContext("/config/setter.xml");
		
		IwriteArticleMgr mgr = (IwriteArticleMgr)factory.getBean("mgr");
		
		ArticleDTO dto = new ArticleDTO();
		dto.setName("홍길동");
		dto.setTitle("개발자");
		dto.setContent("의존성주입");
		dto.setDate("2024-04-26");
		mgr.write(dto);
	}
}

annotation으로 객체주입

<?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-4.2.xsd">
	<!-- base-package로 등록한 패키지와 패키지의 하위패키지를 모두 스캔해서 어노테이션이 추가된 빈을 생성한다. 
	<context:component-scan base-package="annotation"/>	-->
	
	<context:component-scan base-package="annotation.basic"/>
	<context:component-scan base-package="annotation.exam01"/>
	<context:component-scan base-package="annotation.exam02"/>
	<context:component-scan base-package="annotation.exam03"/>
</beans>

annotation.basic

interface Insa - 변경됨

public interface Insa {
	void addUser(MemberDTO user);
	MemberDTO getUser(String id);
	void setDao(DAO dao);
	DAO getDao();
}

interface DAO - 추가됨

public interface DAO {
	void add(MemberDTO user);
	MemberDTO getUser(String id);
}

MemberDTO - 동일

public class MemberDTO {
	private String id;
	private String pass;
	private String name;
	public MemberDTO(){
		
	}
	public MemberDTO(String id, String pass, String name) {
		super();
		this.id = id;
		this.pass = pass;
		this.name = name;
	}

	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getPass() {
		return pass;
	}
	public void setPass(String pass) {
		this.pass = pass;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
}

MemberDAO

@Component("member")
public class MemberDAO implements DAO{
	public MemberDAO() {
		System.out.println("기본생성자 - MemberDAO");
	}
	public void add(MemberDTO user){
		System.out.println("db에 insert하기");
	}
	public MemberDTO getUser(String id){
		System.out.println("사용자정보 가져오기 - db에서 조회");
		return null;
	}
}

CustomerDAO -추가됨, MemberDAO와 같은 폼

@Component("customer")
public class CustomerDAO implements DAO {
	public CustomerDAO() {
		System.out.println("CustomerDAO의 기본생성자");
	}
	@Override
	public void add(MemberDTO user) {
		System.out.println("CustomerDAO의 add");

	}

	@Override
	public MemberDTO getUser(String id) {
		System.out.println("CustomerDAO의 getUser");
		return null;
	}
}

InsaImpl /서비스의 역할

@Service
public class InsaImpl implements Insa {
	@Autowired //이 기호가 필드위에 붙으면 필드 타입을 확인해서,같은타입의 빈이 컨테이너 내부에 존재하면 자동으로 연결
	@Qualifier("customer")
	DAO dao;
	String msg;
	public InsaImpl() {
		System.out.println("기본생성자 - InsaImpl");
	}
	
	public InsaImpl(DAO dao) {
		super();
		this.dao = dao;
		System.out.println("매개변수 1개 생성자 - InsaImpl");
	}

	public DAO getDao() {
		return dao;
	}

	public void setDao(DAO dao) {
		this.dao = dao;
	}

	@Override
	public void addUser(MemberDTO user) {
		dao.add(user);		
	}

	@Override
	public MemberDTO getUser(String id) {
		dao.getUser("id");
		return null;
	}

}

TestMain

public class TestMain {
	public static void main(String[] args) {
		ApplicationContext factory 
			= new ClassPathXmlApplicationContext("/config/anno.xml");
		Insa insa = (Insa)factory.getBean("insaImpl");
		
		MemberDTO user = 
				new MemberDTO("jang","1234","장동건");
		insa.addUser(user);
	}
}

annotation.exam01

AbstractDice, AbstractPlayer는 동일

Dice

@Service("dice1")
public class Dice extends Random implements AbstractDice{
	public Dice() {
		System.out.println("기본 생성자 - Dice");
	}
	public int getDiceValue(){
		System.out.println("dice1");
		return nextInt(6)+1;
	}
}

Dice2

@Service("dice2")
public class Dice2 extends Random implements AbstractDice{
	public Dice2() {
		System.out.println("Dice2 기본생성자");
	}
	@Override
	public int getDiceValue(){
		System.out.println("dice2");
		return (nextInt(6)+1)*2;
	}
}

Player

@Service("player")
public class Player implements AbstractPlayer{
	@Autowired
	@Qualifier("dice1")
	AbstractDice d;
	int totalValue=0;
	public Player() {
		
	}
	public Player(AbstractDice d) {
		super();
		this.d = d;
		System.out.println("매개변수 1개 생성자 - Player");
	}
	public void play(){
		totalValue=0;
		for (int i = 0; i < 3; i++) {
			totalValue+=d.getDiceValue();
		}
	}
	public int getTotalValue(){
		return totalValue;
	}
}

Test01

public class Test01 {
	public static void main(String[] args) {
		ApplicationContext factory
			= new ClassPathXmlApplicationContext("/config/anno.xml");
		AbstractPlayer player = (AbstractPlayer)factory.getBean("player");
		player.play();
		System.out.println("세번 굴린 주사위의 합:"+player.getTotalValue());
	}
}

annotation.exam02

Logic, MyService는 동일

LogicImpl

@Service
public class LogicImpl implements Logic {
	@Override
	public void testLogic() {
		System.out.println("db연동,xml,json,연산등을 수행하는 비지니스 메소드");
	}
}

ServiceImpl

@Service("service")
public class ServiceImpl implements MyService {
	@Value("everything everywhere all at once")
	String name;
	@Value("인생영화")
	String msg;
	@Autowired
	Logic logic;
	
	public ServiceImpl() {
		
	}
	
	public ServiceImpl(String name, String msg, Logic logic) {
		super();
		this.name = name;
		this.msg = msg;
		this.logic = logic;
	}
	
	@Override
	public void testService() {
		System.out.println(msg+","+name);
		logic.testLogic();
	}
}

MainTest

public class MainTest {
	public static void main(String[] args) {
		ApplicationContext factory = new ClassPathXmlApplicationContext("/config/anno.xml");
		MyService bean = (MyService)factory.getBean("service");
		
		bean.testService();
		
	}
}

annotation.exam03

MysqlArticleDAO

@Repository("mysql")
public class MysqlArticleDAO implements IArticleDAO{
	@Override
	public void insert(ArticleDTO article) {
		System.out.println("Mysql에 삽입하기");
	}
}

OracleArticleDAO

@Repository("oracle")
public class OracleArticleDAO implements IArticleDAO{
	@Override
	public void insert(ArticleDTO article) {
		System.out.println("Oracle에 삽입하기");
	}
}

WriteArticleMgr

@Service("mgr")
public class WriteArticleMgr implements IwriteArticleMgr{
	@Autowired
	@Qualifier("oracle")
	private IArticleDAO ADA;
	
	public WriteArticleMgr() {
		
	}
	public WriteArticleMgr(IArticleDAO ADA) {
		super();
		this.ADA = ADA;
	}

	@Override
	public void write(ArticleDTO ADT) {
		ADA.insert(ADT);
	}
}

TestMain

public class TestMain {
	public static void main(String[] args) {
		ApplicationContext factory = new ClassPathXmlApplicationContext("/config/anno.xml");
		
		IwriteArticleMgr mgr = (IwriteArticleMgr)factory.getBean("mgr");
		
		ArticleDTO dto = new ArticleDTO();
		dto.setName("홍길동");
		dto.setTitle("개발자");
		dto.setContent("의존성주입");
		dto.setDate("2024-04-26");
		mgr.write(dto);
	}
}

과제

아래의 클래스 다이어그램을 보고 DI를 적용하여 클래스를 작성하세요. 이예제는 Constructor Injection과 Setter Injection을 함께 적용해야 하는 예제입니다. xml을 이용해서 설정하여 작업합니다.

exam

exam.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">
	
	<bean id="outputter" class="exam.FileOutputter"/>
	<bean id="msg" class="exam.MessageBean">
		<constructor-arg name="name" value="홍길동"/>
		<property name="greeting" value="안녕하세요"/>
		<property name="outputter" ref="outputter"/>
	</bean>
</beans>

interface InterMessage

public interface InterMessage {
	void sayHello();
}

interface Outputter

public interface Outputter {
	void output(String message);
}

FileOutputter

public class FileOutputter implements Outputter {
	private String filePath;
	@Override
	public void output(String message) {
		System.out.println(message);
	}
	
	public void setFilePath(String filePath) {
		this.filePath = filePath;
	}
	
}

MessageBean

public class MessageBean implements InterMessage {
	private String name;
	private String greeting;
	private Outputter outputter;
	
	public MessageBean() {
		
	}
	
	public MessageBean(String name) {
		super();
		this.name = name;
	}
	
	@Override
	public void sayHello() {
		outputter.output(greeting+", "+name+"님");
	}

	public void setGreeting(String greeting) {
		this.greeting = greeting;
	}

	public void setOutputter(Outputter outputter) {
		this.outputter = outputter;
	}
}

TestApp

public class TestApp {
	public static void main(String[] args) {
		ApplicationContext factory = new ClassPathXmlApplicationContext("config/mission.xml");
		InterMessage msg = (InterMessage)factory.getBean("msg");
		
		msg.sayHello();
		
	}
}

exam2

exam.anno.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-4.2.xsd">

	<context:component-scan base-package="exam.anno" />
</beans>

상위클래스인 interMessage, Outputter는 동일

FileOutputter

@Service("fileoutput")
public class FileOutputter implements Outputter {
	private String filePath;
	@Override
	public void output(String message) {
		System.out.println(message);
	}
	
	public void setFilePath(String filePath) {
		this.filePath = filePath;
	}
	
}

MessageBean

@Service("bean")
public class MessageBean implements InterMessage {
	@Value("홍길동")
	private String name;
	@Value("안녕하세요")
	private String greeting;
	
	@Autowired
	@Qualifier("fileoutput")
	private Outputter outputter;
	
	public MessageBean() {
		
	}
	
	public MessageBean(String name) {
		super();
		this.name = name;
	}
	
	@Override
	public void sayHello() {
		outputter.output(greeting+", "+name+"님");
	}

	public void setGreeting(String greeting) {
		this.greeting = greeting;
	}

	public void setOutputter(Outputter outputter) {
		this.outputter = outputter;
	}
}

TestApp

public class TestApp {
	public static void main(String[] args) {
		ApplicationContext factory = new ClassPathXmlApplicationContext("config/exam.anno.xml");
		InterMessage msg = (InterMessage)factory.getBean("bean");
		
		msg.sayHello();
		
	}
}

gpt 질문

스프링에서 어노테이션할때 왜 기본생성자가 있어야해?

ChatGPT
스프링에서 어노테이션을 사용할 때 기본 생성자가 필요한 이유는 주로 의존성 주입(Dependency Injection)과 관련이 있습니다. 스프링은 객체의 의존성을 주입하기 위해 기본 생성자를 사용합니다.

의존성 주입은 객체 간의 결합도를 줄이고 유연성을 높이는데 사용됩니다. 스프링은 빈(bean)을 관리하고, 런타임 시에 필요한 의존성을 주입하여 객체를 생성합니다. 이를 위해서는 객체가 스프링에 의해 인스턴스화될 때 기본 생성자를 사용할 수 있어야 합니다.

기본 생성자가 없는 클래스의 경우, 스프링은 의존성을 주입할 수 없으므로 빈으로 등록할 수 없습니다. 이는 스프링이 프로퍼티나 생성자를 통해 의존성을 주입하는 데 제약이 됩니다.

따라서 스프링을 사용하여 빈을 관리하고 의존성을 주입하려면 해당 클래스에 기본 생성자가 있어야 합니다.

본 포스팅은 멀티캠퍼스의 멀티잇 백엔드 개발(Java)의 교육을 수강하고 작성되었습니다.

0개의 댓글