스프링 [Spirng] DI(Dependency Injection) 의존성 주입이란

반응형

DI (Dependency Injection) - 의존 주입

스프링은 기본적으로 DI를 기반으로 동작한다.

의존하는 타입의 객체를 직접 생성하는것과,

1. 
public void print(String filePath) throws IOException {  
try(BufferedReader br = new BufferedReader(new FileReader(filePath))){  
....  
2. 
public class FileEncryptor {  
private Encryptor encryptor = new Encryptor();  
....

또는 외부에서 전달 받을수도있다.

1. public class FileEncryptor {  
private Encryptor encryptor;  
  
public FileEncryptor(Encryptor enc){  
this.encryptor = enc;  
}  
.....

외부에서 생성자를 통해 의존 객체를 전달받는 경우 FileEncryptor 객체를 생성할때 의존하는 객체를
생정자의 파라미터로 전달해야한다.

1. 
public static void main(String[] args){  
Encryptor enc = new Encryptor();  
FileEncryptor fileEncryptor = new FileEncryptor(enc);  
try {  
fileEncryptor.encrypt(new Fil(args[0]), new File(args[1]));  
} catch(IOException ex) { .... }

의존 객체를 직접 생성하는 방식의 단점

1. 
public void print(String filePath) throws IOException {  
try(BufferedReader br = new BufferedReader(new FileReader(filePath))){  
....  
2. public class FileEncryptor {  
private Encryptor encryptor = new Encryptor();  
....

만일 Encryptor 클래스이 하위 클래스인 FastEncryptor 클래스를 사용하는 상황이 발생하면

1.
 public class FileEncryptor {  
private Encryptor encryptor = new FastEncryptor();  
.....

FileEncryptor 클래스는 사용할 객체의 타입이 Encryptor인지 FastEncryptor 클래스인지
중요하지 않음에도 FastEncryptor 클래스의 객체를 사용하기 위해 Encryptor 대신 FastEncryptor를 FileEncryptor
클래스의 코드를 변경해야한다. Encryptor클래스 대신 FastEncryptor 클래스 객체를 사용해야하는 코드가 많다면
그에 비례해서 변경해주어야한다. 어질ㅇ어질;;

DI를 사용하는 방식의 코드는 의존 객체를 외부에서 조립 따라서 생성자를 이용해 의존 객체를 전달받을수있따

1. 
public class FileEncryptor {  
private Encryptor encryptor;  
public FileEncryptor(Encryptor encryptor) {  
//생성자로 전달받은 객체를 필드에 할당  
this.encryptor = encryptor;  
}

public void encrypt(File src, File target) throws IOException {  
.....  
// DI방식으로 전달 받은 객체를 사용  
encryptor.encrypt(data, 0, len);  
.....  
}  
}
  1. //다른 코드에서 의존 객체를 사용할 클래스에 생성(선언)하고
Encryptor enc = new Encryptor();  

//의존 객체를 전달(사용)해 줌

FileEncryptor fileEnc = new FileEncryptor(enc);  

FileEncryptor이 스스로 의존하는 객체를 생성하지 않고, 외부에서 누군가 의존객체를
FileEncryptor에 넣어준다는 의미로 이런 방식을 DI라 부른다.(다른말론 객체를 연결(wire))
따라서 누가 객체를 생성하면 객체를 서로 연결해주는 역할을 하는것이 조립기이다.

2022-01-06

혼자해석해,… JAVA에서 객체만 선언해서 쉽게 사용하기 위해 스프링이 필요하고, XML에 연결 조립.

메이븐 프로젝트에 의존설정 생략 예제.

사용할 예쩨

User 클래스와 PasswordChangeService 클래스는 생성자를 통해서 필요한 값을 전달받는다.

즉, 생성자 방식을 사용 AuthenticationService와 UserRepository는 set 메서드를 이용해서 필요한 값을 전달받는다. 즉 프로퍼티 설정방식을 이용한다.

bean태그와 property태그 그리고 constructor-arg 태그는 각각 생성할 객체와 프로퍼티 방식의 DI 설정 그리고 생성자 방식의 DI 설정을 위해 사용된다.

<bean id="OOOO" class="OOO.OOO.OOO.OOO"> </bean>

class 속성을 스프링 컨테이너가 생성할 객체의 클래스 이름을 값으로 받는다 즉 패키지 이름을 포함한 완전한 클래스의 이름 (경로를 찾으면된다)

id 속성의 값으론 bean 태그를 이용해서 생성하는 스프링 빈 객체의 고유한 이름으로 사용한다 id 속성으로 지정한 빈의 이름은 다른 bean 태그에서 참조할 때 사용된다.

id 속성값을 지정하지 않을경우 임의로 class이름뒤에 #0과 같은 이름이 부여된다. # 뒤의 숫자는 스프링이 알맞게 붙여주는 번호이다.

constructor-arg 태그 : 생성자 방식 설정.

User.java

User 클래스는 생성자를 이용해서 필요한 값을 전달받고 있다. User 객체를 스프링 빈 으로 설정하려면 생성자에 전달할 값을 설정해주어야 하고 이에 사용되는 태그가 constructor-arg 태그이다. User.java파일에 선언된 변수의 값을 XML을통해 대입.

config.xml

User파일을 사용할 bean 이름은 user1, user2로 구분하고 값은

<constructor-arg value=""/>

로 작성한다.

객체를 생성할 때 생성자에 전달할 파라미터 값을 설정해주어야 할 경우 bean 태그의 자식 태그로 constructor-arg 태그를 사용한다 . JAVA로 진행시 new User(“bkchoi”, “1234”);

int와 같은 기본 데이터 타입, Integer와 같은 래퍼타입, String등의 값을 설정할 때는

<value> 

태그나 value속성을 사용한다. 혹은 ref 속성을 사용할수있따.

 <constructor-arg ref="user1"/>
<property> 태그 : 프로퍼티 방식 설정

프로퍼티 설정 박식을 사용하는 경우 태그를 사용한다. name 속성을 이용해 프로퍼티 이름을 지정, 프로퍼티 값은 태그나 value 속성 그리고 태그나 ref 속성을 이용해 설정할 수 있다.

config.xml

34라인 - 프로퍼티 태그를 사용하면 setthreshold() 형식의 메서드를 이용해 값을 설정한다.

AuthenticationService.java

XML을 이요해서 생성할 객체 목록과 DI 설정을진행했고, 설정 파일을 이용해 스프링 컨테이너를 생성할 차례.

XML 파일을 이용해 스프링설정 파일을 작성했으므로 GenericXmlApplicationContext(제네릭) 클래스를 사용해서 스프링 컨테이너를 생성하면된다.

mainByXML.java

14 - 새성자를 호출할때 classpath:config.xml을 파라미터로 전달했는데 , 클래스 패스에 위치한 config.xml 파일을 스프링설정 으로 사용한다는 것을 의미한다.

설정 파일을 이용해서 스프링 컨테이너를 생성했다면 그 다음으로 getBean()메서드를 이용해 빈 객체를 구할수 있다.

ctx.getBean("", *.class);

이름은 authenticationService이고 타입이 AuthenticationService인 빈 객체를 구하고 있다. 즉 AuthenticationService.java

MainByXml 클래스는 GenericXmlApplicationContext 클래스를 이용해서 스프링 컨테이너를 생성하고 getBean() 메서드를 이용해 이름이 authenticationService인 빈을 구하고 있다.

26 - getBean()메서드를 호출할 때 빈 이름을 지정하지 않고 타입만 전달하고 있는데 이 경우 getBean()메서드는 기술된 타입에 해당하는 빈을 구해서 리턴한다. 즉 27라인의 정보를담아 리턴.

출력결과 :

GenericXmlApplicationContext설정파일 지정

스프링을 설정할 때 관련된 것들을 별도의 설정 파일로 나눠 보관한다.

EX)

회원관련된 빈 설정은 spring-member.xml

게시판 관련된 빈 설정은 spring-board.xml

DB연동 관련 빈 설정은 spring-datasource.xml

스프링 설정을 여러 파일에 분리해서 넣었다면 설정파일 목록을 GenericXmlApplicationContext생성자에 전달해 주면된다 생성자 파라미터는 가변인자라서 한 개 이상의 값을 파라미터로 전달 받을수있다.

스프링 설정이 클래스패스 루트가 아닌 다른 곳에 위치한다면 루트를 기준으로 경로 형식을 입력하면된다.

EX ) “classpath:/conf/spring/conf.xml”);

클래스 패스가 아닌 파일 시스템에서 설정 파일을 읽어오고 싶다면, classpath:접두어 대신 file: 접두어를 사용하면된다

file:접두어 뒤에 상대경로와 절대 경로를 사용할 수 있는데, 상대 경로를 사용하면 java를 실행하는 현재 디렉토리 기준으로 상대 경로를 계산한다.

특정 경로에 있는 모든 XML파일을 설정 파일로 사용하고 싶은경우 * (애스터리크)를 사용해서 지정할 수 있다.

22.01.12

public class FilePrintor {

public void print(String filePath) throws IOException{

try(BufferedReader br = new BufferedReader(new FileReader(filePath))){

.....

fileprintor 클래스는 BufferedReader객체를 생성해 사용한다(의존한다.)

print메서드를 실행하기 위해선 BufferedReader가 필요하고 이런식으로 기능을 실행하기 위해서 다른 클래스를 필요로 할때 이것을 의존한다라고 말한다.

fileprintor클래스에서 print()메서드 내부에서 의존하는 타입의 객체를 직접 생성해 로컬 변수로 보관했다.

의존하는 타입을 필드로 정의할수도있다.

public class FileEncryptor{

private Encryptor encryptor = new Encryptor();

.....

의존하는 타입의 객체를 직접 생성하지 않고 외부에서 전달받을수있다

private String Time;

.....

public void setTime(String time){

this.Time = time;

}

......

의존 객체를 직접 생성하면(스프링을 di로 설정하지않으면)

private Encryptor encryptor = new Encryptor();

.....

직접 짜여진 코드가 있고, 만일 요구사항의 변화로 Encryptor(); 의 하위 클래스인 FastEncryptor클래스를 사용하는 상황이 발생하게될경우 직접 생성한 객체의 내용도 new FastEncryptor();로 변경해주어야한다.

만일 Encryptor클래스 대신 FastEncryptor클래스 객체를 사용해야 하는 경우가 많다면, 설정된 코드들을 전부 변경해주어야 한다.

반응형