취미로 음악을 하는 개발자

[Spring Boot] 의존 주입 방법 본문

공대인/Spring[Boot]

[Spring Boot] 의존 주입 방법

영월특별시 2019. 7. 29. 21:26
728x90

Spring과 Spring Boot의 의존 주입 차이


1) Spring

- bean configuration xml을 이용한 의존 주입

- 자바 코드를 이용한 의존 주입

- 어노테이션을 이용한 의존 주입


2) Spring Boot

- 자바 코드를 이용한 의존 주입

- 어노테이션을 이용한 의존 주입



@SpringBootApplication

: 아래와 같은 기능을 동시에 실행


@Configuration

: 자바 코드로 작성된 클래스를 스프링 설정으로 사용함을 의미


@EnableAutoConfiguration

: Spring Application Context를 만들 때 지정해 둔 설정 값들을 이용하여 자동으로 설정하는 기능을 킴


@ComponetScan

: 지정한 위치 이하에 있는 @Component와 @Configuration이 붙은 클래스를 스캔해서 Bean으로 등록



프로젝트 생성




코드 구현


1
2
3
4
5
package com.study.springboot.bean;
 
public interface Printer {
    public void print(String message);
}
cs


1
2
3
4
5
6
7
8
package com.study.springboot.bean;
 
public class PrinterA implements Printer{
    @Override
    public void print(String message) {
        System.out.println("Printer A : " + message);
    }
}
cs

* PrinterB는 A에서 B로만 바꿔주시면 됩니다.


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
32
33
34
35
36
37
38
39
40
41
42
package com.study.springboot.bean;
 
public class Member {
    private String name;
    private String nickname;
    private Printer printer;
    
    public Member() {}
    public Member(String name, String nickname, Printer printer) {
        this.name = name;
        this.nickname = nickname;
        this.printer = printer;
    }
    
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public String getNickname() {
        return nickname;
    }
 
    public void setNickname(String nickname) {
        this.nickname = nickname;
    }
 
    public Printer getPrinter() {
        return printer;
    }
 
    public void setPrinter(Printer printer) {
        this.printer = printer;
    }
    
    public void print() {
        printer.print("Hello " + name + " : " + nickname);
    }
}
cs


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
32
33
34
35
36
37
38
39
package com.study.springboot.bean;
 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
// 클래스를 스프링 설정으로 사용함
@Configuration
public class Config {
    // 메소드의 리턴 값을 빈 객체로 사용함
    @Bean
    public Member member1() {
        // Setter Injection (Setter 메소드를 이용한 의존성 주입)
        Member member1 = new Member();
        member1.setName("홍길동");
        member1.setNickname("도사");
        member1.setPrinter(new PrinterA());
        
        return member1;
    }
    
    @Bean(name="hello") // 별도의 이름으로 Bean 등록
    public Member member2() {
        // COnstructor Injection (생성자를 이용한 의존성 주입)
        return new Member("전우치""도사"new PrinterA());
    }
    
    @Bean
    public PrinterA printerA() {
        return new PrinterA();
    }
    
    @Bean PrinterB printerB() {
        return new PrinterB();
    }
    
    // bean : Spring이 IoC 방식으로 관리하는 객체
    // beanFactory : 스프링의 IoC를 담당하는 핵심 컨테이너
    // Applicationontext : beanFactory를 확장한 IoC 컨테이너
}
cs


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
32
33
34
35
36
37
38
39
package com.study.springboot;
 
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
 
import com.study.springboot.bean.Config;
import com.study.springboot.bean.Member;
import com.study.springboot.bean.Printer;
 
//@SpringBootApplication
public class Ex02JavaCodeDiApplication {
 
    public static void main(String[] args) {
        //SpringApplication.run(Ex02JavaCodeDiApplication.class, args);
        
        // 1. IoC 컨테이너 생성
        ApplicationContext context =
                new AnnotationConfigApplicationContext(Config.class);
        
        // 2. Member Bean 가져오기
        Member member1 = (Member)context.getBean("member1");
        member1.print();
        
        // 3. Member Bean 가져오기
        Member member2 = context.getBean("hello", Member.class);
        member2.print();
        
        // 4. PrinterB Bean 가져오기
        Printer printer = context.getBean("printerB", Printer.class);
        member1.setPrinter(printer);
        member1.print();
        
        // 5. 싱글톤인지 확인
        if (member1 == member2)
            System.out.println("동일");
        else 
            System.out.println("다른 객체");
    }
}
cs


@SpringBootApplication은 자동으로 Bean을 검색하고 등록하므로 잠시 주석처리를 했고

수동으로 작업하면서 결과를 보도록 한다.


1번은 Config.class를 통해 변수 context의 컨테이너를 생성하는 코드다. 실행하면 아래와 같은 결과가 나온다.

1
2
3
4
5
6
7
8
9
10
11
22:59:31.108 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@5f150435
22:59:31.141 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor'
22:59:31.402 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor'
22:59:31.405 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
22:59:31.409 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
22:59:31.410 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'
22:59:31.418 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'config'
22:59:31.426 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'member1'
22:59:31.458 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'hello'
22:59:31.459 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'printerA'
22:59:31.460 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'printerB'
cs


* 참고로 필자는 처음 실행할 때 bean객체를 찾지 못해서 오류가 떴었는데 이클립스를 재시작하니까 해결되었다.


2번부터 실행하면 각 bean 객체의 메소드를 호출하는데 getBean에 들어가는 파라미터는 bean객체의 메소드 이름을 뜻한다.

참고로 3번의 member2는 'Hello'라는 이름을 사용했기 때문에 'Hello'가 나온 것이고 나머지는 함수의 이름이 출력되었다.




Bean, BeanFactory, ApplicationContext


1) Bean

: Spring이 IoC 방식으로 관리하는 객체 or Spring이 직접 생성과 제어를 담당하는 객체


2) BeanFactory

: Spring의 IoC를 담당하는 핵심 컨테이너를 가리킴

- Bean을 등록, 생성, 조회, 반환하는 기능을 담당

- 이 BeanFactory를 바로 사용하지 않고 이를 확장한 ApplicationContext를 주로 이용


3) ApplicationContext

: BeanFactory를 확장한 IoC 컨테이너

- BeanFactory와 다른 것은 Spring이 제공하는 각종 부가 서비스를 추가로 제공




Annotaiton으로 DI 주입 방법


프로젝트 생성





코드


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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package com.study.springboot.bean;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
 
// 검색된 클래스를 빈으로 등록할 때, 클래스의 첫 글자를 소문자를 바꾼
// 이름을 빈의 이름으로 사용
@Component
public class Member {
    @Value("홍길동")
    private String name;
    @Value("도사")
    private String nickname;
    @Autowired
    @Qualifier("printerA")
    private Printer printer;
    
    public Member() {}
    public Member(String name, String nickname, Printer printer) {
        this.name = name;
        this.nickname = nickname;
        this.printer = printer;
    }
    
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public String getNickname() {
        return nickname;
    }
 
    public void setNickname(String nickname) {
        this.nickname = nickname;
    }
 
    public Printer getPrinter() {
        return printer;
    }
 
    public void setPrinter(Printer printer) {
        this.printer = printer;
    }
    
    public void print() {
        printer.print("Hello " + name + " : " + nickname);
    }
}
cs



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
32
33
34
35
36
package com.study.springboot.bean;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
 
@Controller
public class MyController {
    @Autowired
    Member member1;
    @Autowired
    @Qualifier("printerB")
    Printer printer;
    @Autowired
    Member member2;
    
    @RequestMapping("/")
    public @ResponseBody String root() {
        // 1. Member Bean 가져오기
        member1.print();
        
        // 2. PrinterB Bean 가져오기
        member1.setPrinter(printer);
        member1.print();
        
        // 3. 싱글톤 확인
        if (member1 == member2)
            System.out.println("동일");
        else
            System.out.println("다른 객체");
        
        return "Annotation 사용하기";
    }
}
cs



1
2
3
4
5
6
7
8
9
10
11
package com.study.springboot.bean;
 
import org.springframework.stereotype.Component;
 
@Component("printerA")
public class PrinterA implements Printer{
    @Override
    public void print(String message) {
        System.out.println("Printer A : " + message);
    }
}
cs

* PrinterB는 PrinterA에서 A를 B로 바꿔주시면 됩니다. 


// application.properties

1
server.port=8081
cs



정상적으로 실행됐다면 아래와 같은 결과가 나올 것이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '| '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.6.RELEASE)
2019-07-30 00:08:21.135  INFO 4980 --- [           main] c.s.s.Ex03AnnotationDiApplication        : Starting Ex03AnnotationDiApplication on DESKTOP-L60ATLP with PID 4980 (C:\Users\Tom\eclipse-workspace\ex03_AnnotationDI\bin\main started by Tom in C:\Users\Tom\eclipse-workspace\ex03_AnnotationDI)
2019-07-30 00:08:21.139  INFO 4980 --- [           main] c.s.s.Ex03AnnotationDiApplication        : No active profile set, falling back to default profiles: default
2019-07-30 00:08:22.650  INFO 4980 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8081 (http)
2019-07-30 00:08:22.683  INFO 4980 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2019-07-30 00:08:22.684  INFO 4980 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.21]
2019-07-30 00:08:22.840  INFO 4980 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2019-07-30 00:08:22.840  INFO 4980 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1629 ms
2019-07-30 00:08:23.173  INFO 4980 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2019-07-30 00:08:23.407  INFO 4980 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8081 (http) with context path ''
2019-07-30 00:08:23.410  INFO 4980 --- [           main] c.s.s.Ex03AnnotationDiApplication        : Started Ex03AnnotationDiApplication in 2.844 seconds (JVM running for 4.461)
2019-07-30 00:08:51.352  INFO 4980 --- [on(9)-127.0.0.1] inMXBeanRegistrar$SpringApplicationAdmin : Application shutdown requested.
2019-07-30 00:08:51.357  INFO 4980 --- [on(9)-127.0.0.1] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'
cs



@Component 지정된 이름으로 등록이 됨, 파라미터를 주지 않으면 해당 클래스 이름의 첫 글자가 소문자인 같은 이름으로 등록됨.

@Value Setter 역할과 같이 객체가 생성될 때 값을 지정할 수 있음.

@Autowired 자동 주입.

@Qualifier 정확한 이름으로 값을 주고싶을 때 사용


↓ 자세한 것은 이전에 작성했던 포스트에 정리를 한 것이 있으니 참고하면 좋다.

의존 객체 자동 주입


@RequestMapping url에서 파라미터에 해당하는 부분의 값이 들어왔을 때 해당 메소드를 실행

@ResponseBody restapi의 html헤더나 다른 태그가 붙지 않은 순수한 값을 리턴


'공대인 > Spring[Boot]' 카테고리의 다른 글

[Spring Boot] Model 객체  (1) 2019.07.31
[Spring Boot] 정적 리소스  (0) 2019.07.31
Spring Boot 개념 정리 시작  (0) 2019.07.29
[Spring] Controller 객체 구현 (2)  (0) 2019.05.28
[Spring] Controller 객체 구현 (1)  (0) 2019.05.28
Comments