티스토리 뷰

728x90
반응형

1. IoC

IoC(Inversion of Control)제어의 역전이라고도 한다.

즉, 메소드나 객체의 호출 작업을 개발자가 직접 결정하는 것이 아니라, 외부에서 결정되는 것을 의미한다.

기존에는 

[ 객체 생성 => 의존성 객체 생성(클래스 내부에서 생성) => 의존성 객체 메소드 호출 ]

의 순서로 객체가 만들어지고 실행되었다.

하지만 스프링에서는 다음과 같은 순서로 진행된다.

[ 객체 생성 => 의존성 객체 주입 (제어권을 스프링에게 위임하여, 스프링에서 만들어놓은 객체 주입) => 의존성 객체 메소드 호출 ]

스프링이 모든 의존성 객체를 스프링이 실행될 때 다 만들어주고, 필요한 곳에 주입시킴으로써, Bean들은 singleton pattern을 가지고, 사용자가 제어의 흐름을 컨트롤하는 것이 아니라 스프링이 대신 작업을 처리한다.

그러면 위의 순서에서 의존성 객체 주입에 대해 알아보자.


2. DI

DIDependency Injection의 약어로, 의존 관계 주입 기능이다.

스프링이 다른 프레임워크와 차별화되어 제공하는 기능으로, 객체를 직접 생성하지 않고, 외부에서 생성한 후 주입시켜주는 방식이다.

 

[ DI의 장점 ] 

1. 모듈 간의 결합도가 낮아진다.

2. 유연성, 확장성이 높아진다.

3. 재사용성을 높여준다.

4. 테스트에 용이하다.

5. 코드를 단순화 시켜준다.

6. 객체 간의 의존 관계 설정이 가능하다.

 

객체 생성 방법에는 다음의 2가지가 있다.

1. new( )를 통한 객체 생성

2. 외부에서 생성된 객체를 setter( ) 혹은, 생성자를 통해 사용하기

 

출처:  https://private.tistory.com/39

 

 

그동안 객체를 사용하기 위해서는 new, 혹은 getter/setter 기능을 사용해야 했다. 

하지만, 한 애플리케이션에는 이러한 객체가 무수히 많이 존재하고, 서로 참조하고 있어 의존성이 높을 수 밖에 없다.

자바는 객체지향프로그래밍으로 낮은 결합도와 높은 캡슐화를 대변하므로, 높은 의존성은 지양된다.

따라서, 의존성을 낮추기 위해 Spring 컨테이너를 사용하는 것이다. 

 

아래 그림에서 확인해보자.

A객체에서 사용(의존)하는 B~F 객체는 A 객체에서 직접 생성하지 않고, 외부(IoC 컨테이너)에서 생성된 뒤, A의 setter 혹은 constructor에 주입되어 사용되므로, '의존성 주입' 이라 한다.  

 

출처:  https://private.tistory.com/39

 


3. Bean

그렇다면 'Bean'이란 무엇일까? 

Bean이란, 스프링 IoC 컨테이너가 생성하고 관리하는 애플리케이션 객체를 의미한다.

Bean은 deault가 singleton scope이고, bean 정의에 대해 container에 단 하나의 객체만 존재한다. 

scope의 종류에는 prototype, session, request 등이 있다.

 

스프링 컨테이너에는 다음의 종류가 있다.

 

- BeanFactory : 빈 객체를 생성, 관리하는 클래스로, factory pattern을 구현한 것이다. 팩토리는 의존성 주입을 통해 빈 객체를 생성, 관리한다.

 

- ApplicationContext : 빈 팩토리와 유사하지만 향상된 형태의 컨테이너로, 이미지 파일 로드, 국제화 지원 텍스트 메시지관리 등의 추가 기능을 제공한다. 


그러면 Constructor Injection과 Setter Injection을 하는 방법을 알아보자.

 

1. xml 파일에 bean 하나하나 등록하기

 

MessageImpl.java

package pack;

import other.MyInfo;
import other2.OutFileInter;

public class MessageImpl implements MessageInter{
	private String name1,name2; //Constructor Injection을 해보자.
	private int year;
	private MyInfo myInfo;
	
	private String spec;//Setter Injection용
	private OutFileInter fileInter;
	
	public MessageImpl() {
		
	}
	public MessageImpl(String name1, String name2, int year, MyInfo myInfo) {
		this.name1=name1;
		this.name2=name2;
		this.year = year;
		this.myInfo = myInfo;
		
	}
	
	public void setSpec(String spec) {//Setter Injection
		this.spec = spec;
	}
	
	public void setFileInter(OutFileInter fileInter) {//Setter Injection
		this.fileInter = fileInter;
	}
	
	public void sayHi() { //출력 담당 메소드
		
		String msg = "이름1: "+name1
					+" 이름2: "+name2+"\n"
					+"연도: "+(year+21)+"\n"
					+"정보: "+myInfo.myData();
		msg=msg+"\n"+spec;
		System.out.println(msg);
		//msg를 파일로 출력
		fileInter.outFile(msg);
	}
	

}

init.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:aop="http://www.springframework.org/schema/aop"
	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.3.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
	
	<!-- 스프링은 default가 싱클톤이므로 scope에 singleton을 생략할 수 있다. -->
	<!-- scope에 쓸 수 있는 것: singleton. prototype, session, request -->
	<bean id="impl" name="star, good" class="pack.MessageImpl" scope="singleton"> <!--1-->
		<!-- index로 매핑 순서 지정 가능 -->
		
		<!-- Constructor Injection --> <!--2-->
		<constructor-arg index="0">
			<value>안녕하세요</value>
		</constructor-arg>
		<constructor-arg index="1">
			<value>반가워요</value>
		</constructor-arg>
		
		<constructor-arg type="int" value="2000" index="2"></constructor-arg>
		<constructor-arg type="other.MyInfo" ref="myInfo" index="3"/>
		
		
		<!-- Setter injection --> <!--3-->
		<property name="spec" value="정보처리기사"></property>
		<property name="fileInter">
			<ref bean="outFileInterImpl"/>
		</property>
		
	</bean>
	<bean id ="myInfo" class="other.MyInfo"></bean> <!--4-->	
	<bean id="outFileInterImpl" class="other2.OutFileInterImpl"> <!--5-->
		<property name="filePath" value="c:/mywork/happy.txt"></property>
	</bean>
	
	
</beans>

 

1) MessageImpl 클래스의 객체 생성하고, id는 impl로 지정하기 (name은 여러 개 설정할 수 있지만 id는 한 개만 가능)

2) Counstor Injection - <constroctor-arg> 태그 사용 

MessageImpl의 생성자의 인자로는 순서대로 name1, name2, year, myInfo가 들어간다. 

index를 따로 지정하지 않으면, constructor-arg의 순서대로 인자에 들어간다. 

index를 지정하여 주입할 수도 있다.

3) Setter Injection - <property> 태그 사용

   * 주의: property의 name은 setter의 set뒤의 명칭의 첫글자를 소문자로 바꾼 것이다. 일종의 약속이다.

    (ex. setSpec()이면, property name ="spec" )

setter 혹은 생성자의 인자로 객체가 들어갈 경우, bean으로 해당 객체를 생성하여 ref 태그를 이용하여 참조할 수 있도록 한다.

4) MyInfo 클래스의 객체를 myInfo라는 아이디로 생성

5) OutFileInterImpl 클래스의 객체를 outFileInterImpl 이라는 아이디로 생성

 


2. annotation 사용하기 

 

component-scan을 사용하여, base-package에 현재 패키지 이름을 작성하면, Class-Path 아래의 @Component, @Service, @RestController, @Controller 어노테이션을 찾아 Bean으로 등록해준다. 

(주의! com.example.demo 외부의 어노테이션은 component-scan의 대상이 아님)

 

 

[Container에 Spring Bean으로 등록해주는 Annotation]


- @Bean: 개발자가 컨트롤 할 수 없는 외부 라이브러리 Bean으로 등록하고 싶은 경우 (메소드로 return 되는 객체를 Bean으로 등록) 
- @Component: 개발자가 직접 컨트롤할 수 있는 클래스(직접 만든)를 Bean으로 등록하고 싶은 경우 (선언된 Class를 Bean으로 등록) 
- @Controller, @Service, @Repository: @Component를 비즈니스 레이어에 따라 명칭을 달리 지정해준 것.

 

 

[Container에 있는 Spring Bean을 찾아 주입시켜주는 Annotation] 

 

- @Autowired: Controller에 있는 Spring Bean을 찾아 주입시켜주는 Annotation. IoC 컨테이너에 있는 참조할 Bean을 찾아 주입. singleton이므로, 자동 주입 가능

- (@Qualifier: @Autowired와 함께하는 어노테이션으로, 이름에 의한 매핑이 가능)

- @Resource: @Autowired와 마찬가지로 Bean 객체를 주입시키는데, Autowired는 타입으로, Resource는 이름으로 연결

 

 

더 많은 어노테이션은 다음의 문서 참고하기

https://velog.io/@gillog/Spring-Annotation-%EC%A0%95%EB%A6%AC

 

[Spring] Annotation 정리

Annotation(@)은 사전적 의미로는 주석이라는 뜻이다. 자바에서 사용될 때의 Annotation은 코드 사이에 주석처럼 쓰여서 특별한 의미, 기능을 수행하도록 하는 기술이다.

velog.io


예시

 

anno2.Sender2.java

package anno2;

import org.springframework.stereotype.Component;

@Component("s2") //<bean id="s2" class="anno2.Sender2.java">
public class Sender2 implements SenderInter{ //다른 클래스에서 호출될 클래스 
	public void show() {
		System.out.println("2 show method 수행됨.");
	}
}

s2라는 아이디로 bean 생성하기


 

anno2_1.Test.java

package anno2_1;

import org.springframework.stereotype.Component;

@Component
public class Test {
	public void abc() {
		System.out.println("다른 패키지에 있는 클래스의 메소드를 호출");
	}
}

Test 클래스 bean 생성


 

anno2.SenderProcess.java

package anno2;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;

import anno2_1.Test;
//@Component("sprocess")
//@Component("senderProcess")//아래와 같은 의미 (클래스명에서 첫글자 소문자로 한 것이 default)
@Component
@ComponentScan("anno2_1") //다른 패키지에 있는 클래스의 어노테이션을 스캔
public class SenderProcess {
	//@Autowired//내부적으로 setter 만들고 setter injection 수행
	//private Sender sender; //현재 프로젝트에서 객체 변수와는 상관없이 어디선가 만들어진 Sender 객체 주호를 치환
	/*
	public void setSender(Sender sender) {
		this.sender = sender;
	}*/
	
	@Autowired
	//@Qualifier("s1")
	@Qualifier("s2")//@Autowired와 함께하는 어노테이션으로 이름에 의한 매핑이 가능해짐.
	private SenderInter inter;//type에 의한 매핑으로 SenderInter의 자식 클래스 객체 주소를 치환
	
	/*public Sender getSender() {
		return sender;
	}*/
	
	
	@Autowired
	private Test test;
	
	
	public void displayData() {
		System.out.println("displayData 메소드 처리");
		inter.show();
		test.abc();
	}
}

@Component => 클래스 명이 SenderProcess이므로, @Component("senderProcess")와 동일한 의미이다. 

 

@ComponentScan("anno2_1") => anno2_1 패키지의 모든 어노테이션을 찾아 Bean으로 등록한다.

 

@Autowired 부분을 보면, @Qualifier에 s2가 들어있으므로, inter는 이름이 s2인 Bean과 매핑이 될 것이다. 

 

@Autowired가 private Test test 위에 있으므로, Test 타입의 Bean이 test에 주입된다.

 


[참고]

http://www.incodom.kr/spring/%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88

https://devlog-wjdrbs96.tistory.com/165

https://velog.io/@gillog/Spring-Annotation-%EC%A0%95%EB%A6%AC

반응형

'WEB > Spring' 카테고리의 다른 글

[Spring] MVC의 Controller  (0) 2021.12.20
[Spring] MVC 패턴 이해하기  (0) 2021.12.19
[Spring] root-context와 servlet-context (스크랩)  (0) 2021.12.18
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함