'IT 관련/스프링(스프링5 레시피)'에 해당되는 글 4건

레시피 2-2내용은 별 내용 없어서 생략했다.


 이번 장에서는 POJO 인스턴스에 대한 레퍼런스 자동 연결 기능을 보도록 하자.



1. Autowired


 POJO 필드에 @Autowired 어노테이션을 붙이면 그 필드에 호환되는 빈을 찾아서 연결한다.

 필드 변수를 초기화해주지 않아도 자동으로 호환되는 레퍼런스를 찾아 초기화해준다는 것이다.


 다음 예제는 이전 포스팅에서 다루었던 SequenceGenerator 예제를 변형한 것이다.


Sequence

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
package com.apress.springrecipes.sequence;
 
public class Sequence {
    private final String id;
    private final String prefix;
    private final String suffix;
    
    public Sequence(String id, String prefix, String suffix) {
        this.id = id;
        this.prefix = prefix;
        this.suffix = suffix;
    }
    
    public String getId() {
        return id;
    }
    
    public String getPrefix() {
        return prefix;
    }
    
    public String getSuffix() {
        return suffix;
    }
    
    
}
 
cs


SequenceDao

1
2
3
4
5
6
7
8
package com.apress.springrecipes.sequence;
 
public interface SequenceDao {
    public Sequence getSequence(String sequenceId);
    
    public int getNextValue(String sequenceId);
}
 
cs


SequenceDaoImpl

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
package com.apress.springrecipes.sequence;
 
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
 
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;
 
@Component("sequenceDao")
public class SequenceDaoImpl implements SequenceDao {
    private final Map<String, Sequence> sequences = new HashMap<>();
    private final Map<String, AtomicInteger> values = new HashMap<>();
    
    public SequenceDaoImpl() {
        sequences.put("IT"new Sequence("IT""30""A"));
        values.put("IT"new AtomicInteger(10000));
    }
    
    public Sequence getSequence(String sequenceId) {
        return sequences.get(sequenceId);
    }
    
    public int getNextValue(String sequenceId) {
        AtomicInteger value = values.get(sequenceId);
        return value.getAndIncrement();
    }
}
 
cs


Main

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.apress.springrecipes.sequence;
 
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
 
public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext("com.apress.springrecipes.sequence");
        
        SequenceService sequenceService = context.getBean(SequenceService.class);
        
        System.out.println(sequenceService.generate("IT"));
        System.out.println(sequenceService.generate("IT"));
    }
}
 
cs


여기까지는 이전 포스팅과 똑같다.


다음에 설명하는 SequenceService가 이번 포스팅의 핵심 내용이다.


 SequenceService

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
package com.apress.springrecipes.sequence;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
 
@Service
public class SequenceService {
    @Autowired
    private SequenceDao sequenceDao;
    
    public SequenceService() {}
    
    public SequenceService(SequenceDao sequenceDao) {
        this.sequenceDao = sequenceDao;
    }
    
    public void setSequenceDao(SequenceDao sequenceDao) {
        this.sequenceDao = sequenceDao;
    }
    
    public String generate(String sequenceId) {
        Sequence sequence = sequenceDao.getSequence(sequenceId);
        int value = sequenceDao.getNextValue(sequenceId);
        return sequence.getPrefix() + value + sequence.getSuffix();
    }
}
 
cs

 

 SequenceService 클래스는 서비스 클래스로, DAO(Data Access Object)와 연동하여 요청을 처리해주는 클래스다. (이런 구현 방법이 실제로 자주 쓰인다.)

 @Service 어노테이션이 붙어있기 때문에 SequenceService는 스프링 빈으로 등록되고, @Autowired가 있기 때문에 sequenceDao 필드엔 이에 호환되는 SequenceDaoImpl 클래스가 자동으로 연결된다. 그렇기 때문에 Main 클래스에서 sequenceService.sequenceDao 필드를 초기화하는 내용이 없음에도 generate() 메소드를 호출해도 오류가 생기지 않는 것이다.


배열, 맵 연결

 배열형 프로퍼티에 @Autowired를 붙이면 스프링은 매치되는 모든 빈을 찾아서 연결하고, type-safe한 컬렉션에 @Autowired를 붙였을 때도 호환되는 모든 빈을 찾아서 연결된다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class SequenceGenerator{
 
    @Autowired
    private PrefixGenerator[] prefixGenerators;
}
 
 
public class SequenceGenerator{
    @Autowired
    private List<PrefixGenerator> prefixGenerators;
}
 
public class SequenceGenerator{
    @Autowired
    private Map<String, PrefixGenerator> prefixGenerators;
}
 
 
cs


 이와 같은 경우 prefixGenerators에 호환되는 모든 빈들이 연결된다.



2. @Autowired로 POJO 메소드와 생성자 연결


 @Autowired는 POJO Setter 메서드, 생성자에도 적용할 수 있다.

 그렇게 되면 세터 메서드와 생성자의 패러미터로 들어오는 변수에 호환되는 빈이 자동으로 연결된다. (패러미터는 여러개 있어도 가능하다)


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
package com.apress.springrecipes.sequence;
 
import org.springframework.beans.factory.annotation.Autowired;
 
public class SequenceGenerator {
    private PrefixGenerator prefixGenerator;
    private String suffix;
    private int initial;
    private int counter;
 
    public SequenceGenerator() {
    }
 
    public SequenceGenerator(PrefixGenerator prefixGenerator, String suffix, int initial) {
        this.prefixGenerator = prefixGenerator;
        this.suffix = suffix;
        this.initial = initial;
    }
 
    //@Autowired
    public void setPrefixGenerator(PrefixGenerator prefixGenerator) {
        this.prefixGenerator = prefixGenerator;
    }
 
    @Autowired
    public void myOwnCustomInjectionName(PrefixGenerator prefixGenerator) {
        this.prefixGenerator = prefixGenerator;
    }
 
    public void setSuffix(String suffix) {
        this.suffix = suffix;
    }
 
    public void setInitial(int initial) {
        this.initial = initial;
    }
 
    public synchronized String getSequence() {
        StringBuilder builder = new StringBuilder();
        builder.append(prefixGenerator.getPrefix());
        builder.append(initial + counter++);
        builder.append(suffix);
        return builder.toString();
    }
}
 
cs


 위에서 Setter 메소드에 @Autowired 어노테이션을 붙여 prefixGenerator에 매칭되는 빈 오브젝트를 자동으로 찾아서 집어넣는다.


 스프링에서 기본적으로는 @Autowired를 붙인 프로퍼티는 필수 프로퍼티로 취급되어, 매칭되는 빈이 없으면 예외가 발생한다. @Autowired의 required 속성값을 false로 지정하면 선택적 프로퍼티로 취급되어 빈을 못 찾아도 그냥 지나친다.

1
2
3
4
5
6
7
8
public class SequenceGenerator {
    ...
    @Autowired(required = false)
    public void myOwnCustomInjectionName(PrefixGenerator prefixGenerator) {
        this.prefixGenerator = prefixGenerator;
    }
}
 
cs



3. 모호한 자동 연결 명시하기


@Primary

 스프링에서는 @Primary를 붙여 후보 빈을 명시한다. 여러 빈이 자동 연결 대상일 때, 특정한 빈에 우선권을 부여하는 것이다.


@Qualifier

 @Qualifier에 이름을 줘서 후보 빈을 명시할 수도 있다.


4. 여러곳에 분산된 POJO 참조 문제 해결


 어플리케이션 규모가 커지면 모든 POJO 설정을 하나의 자바 구성 클래스에 담기 어렵기 떄문에, 보통 POJO 기능에 따라 여러 자바 구성 클래스로 나눠서 관리한다. 그런데 자바 구성 클래스가 여러개 있으면 서로다른 클래스에 정의된 POJO를 자동으로 연결하거나 참조하기가 쉽지 않다.

 이는 다음의 두가지 방법으로 해결 가능하다.


 방법1. 자바 구성 클래스가 위치한 경로마다 어플리케이션 컨텍스트를 초기화

1
2
3
AnnotationConfigApplication context = new AnnotationConfigApplicationContext(PrefixConfiguration.class
                                                            SequenceGeneratorConfiguration.class)
 
cs



 방법2. @Import로 구성 파일을 나눠서 임포트

1
2
3
4
5
6
@Configuration
@Import(PrefixConfiguration.class)
public class SequenceConfiguration{
    ....
 
}
cs


 

4. 레퍼런스

스프링 5 레시피(4판) - 한빛 미디어


'IT 관련 > 스프링(스프링5 레시피)' 카테고리의 다른 글

스프링 프로젝트 생성  (0) 2020.02.23
Chap 2.1 자바로 POJO 구성하기  (0) 2020.02.23
스프링 시작(Chapter1)  (0) 2020.02.20
블로그 이미지

서기리보이

,

기본적인 스프링 프로젝트 생성에서부터 막힐 수 있기 때문에 미리미리 정리...

 

 

STS 상단의 File - new - Project... 클릭

Spring Starter Project 선택.

프로젝트 명, Type(그레이들/Maven 선택) 값 설정. 나머지 값들은 기본으로 두면 됨.

그 다음 Next-Next-Finish 하면 프로젝트 생성.

 

불필요한 파일들 삭제(빨간 네모 부분)

프로젝트에서 불필요한 파일들을 삭제하고, src/main/java 디렉토리에 필요한 코드를 작성하면 된다.

 

 

 

 

 

 

 

블로그 이미지

서기리보이

,

0. 들어가기에 앞서


 이번 장의 주제는 스프링의 주요 기능이다.

 IoC(Inversion of Control. 제어의 역전)은 스프링 프레임워크의 심장부라고 할 수 있다. IoC 컨테이너는 POJO(Plain Old Java Object. 오래된 방식의 단순 자바 객체)를 구성하고 관리하는데, 스프링 프레임워크의 가장 중요한 의의가 이 POJO로 자바 애플리케이션을 개발하는 것이므로 스프링의 주요 기능은 대부분 IoC 컨테이너 안에서 POJO를 구상하고 관리하는 일과 연관되어있다.


* '빈(bean)' = 'POJO 인스턴스'

* '컴포넌트(component)' = 'POJO 클래스'



1. 자바로 POJO 구성하기


목적

스프링 IoC 컨테이너에서 어노테이션을 붙여 POJO 관리하기.


해결책

 @Configuration, @Bean을 붙인 자바 구성 클래스를 만들거나, @Component, @Repository, @Service, @Controller 등을 붙인 자바 컴포넌트를 구성하여 POJO 클래스를 설계한다.

 IoC 컨테이너는 이렇게 어노테이션(annotation)을 붙인 자바 클래스를 스캐닝하여 어플리케이션의 일부인 것 처럼 POJO 인스턴스/빈을 구성한다.


예제

 순차번호 생성기(다목적 시퀀스 생성기) 어플리케이션 개발을 위해 SequenceGenerator를 다음과 같이 구현한다.

 Sequence는 prefix, suffix, initial 세가지 프로터피를 가지고, getSequence() 메소드를 호출하면 이 세가지 값이 조합된 시퀀스가 리턴된다.


SequenceGenerator

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
package com.apress.springrecipes.sequence;
 
import java.util.concurrent.atomic.AtomicInteger;
 
public class SequenceGenerator {
 
    private String prefix;
    private String suffix;
    private int initial;
    private final AtomicInteger counter = new AtomicInteger();
 
    public SequenceGenerator() {
    }
 
    public void setPrefix(String prefix) {
        this.prefix = prefix;
    }
 
    public void setSuffix(String suffix) {
        this.suffix = suffix;
    }
 
    public void setInitial(int initial) {
        this.initial = initial;
    }
 
    public String getSequence() {
        String builder = prefix +
                initial +
                counter.getAndIncrement() +
                suffix;
        return builder;
    }
}
cs


 이제 @Configuration, @Bean 어노테이션을 이용하여 자바 POJO를 생성하는 클래스 SequenceGeneratorConfiguration을 다음과 같이 구현한다.


SequenceGeneratorConfiguration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.appress.springrecipes.sequence.config;
 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
import com.apress.springrecipes.sequence.SequenceGenerator;
 
//@Configuration : 이 클래스가 구성클래스임을 알림
@Configuration
public class SequenceGeneratorConfiguration {
    //@Bean : @Configuration 어노테이션이 달린 클래스의 빈(Bean) 인스턴스 정의부
    @Bean
    public SequenceGenerator sequenceGenerator() {
        SequenceGenerator seqgen = new SequenceGenerator();
        seqgen.setPrefix("30");;
        seqgen.setSuffix("A");
        seqgen.setInitial(100000);
        
        return seqgen;
    }
}
 
cs



 스프링은 @Configuration이 달린 구성 클래스를 보면 일단 그 안의 빈(Bean)인스턴스 정의부, 즉 @Bean을 붙인, 빈 인스턴스를 생성해 반환하는 메서드를 찾는다.


 구성 클래스의 메소드에 @Bean을 붙이면 빈이 생성되는데 @Bean의 name 속성값을 지정해 빈 이름을 지정해 줄 수 있다.(ex : @Bean(name="mys1") -> 생성되는 빈 이름은 mys1으로 생성됨.). name 속성값을 지정해주지 않으면 원본 메소드 이름과 같은 이름의 빈이 생성된다.


 

 다음 단계로 어노테이션을 붙인 자바 클래스를 스캐닝하기 위해 IoC 컨테이너를 인스턴스화해야한다.


 스프링에서 제공하는 IoC 컨테이너는 기본 구현체인 Bean Factory, 그리고 이와 호환되는 고급 구현체인 Application Context 두가지가 있다.


 둘은 각각 빈 팩토리, 어플리케이션 컨텍스트에 접근하기위한 인터페이스다. 그리고 Application Context는 BeanFactory의 하위 인터페이스라서 호환성이 보장된다.


 * Application Context는 기본 기능에 충실하면서도 Bean Factory보다 발전된 기능을 가지고 있으니, 리소스 제약을 받는 상황이 아니라면 Application Context를 사용하는게 좋다.


 ApplicationCotext는 인터페이스이므로, 사용하려면 구상 클래스(concrete class)가 필요하다. 스프링에서 지원하는 ApplicationContext의 몇가지 구상체 중에서, AnnotationConfigApplicationContext가 가장 최근 작품이고, 유연하기 때문에 사용이 권장된다.


 이제 Main클래스를 통해 시퀀스 생성기를 실행하는 것을 보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.apress.springrecipes.sequence;
 
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
 
import com.appress.springrecipes.sequence.config.SequenceGeneratorConfiguration;
 
public class Main {
    public static void main(String[] args){
        //ApplicationContext를 구현한 구상 클래스들 중 AnnotationConfigApplicationContext 사용
        ApplicationContext context = new AnnotationConfigApplicationContext(SequenceGeneratorConfiguration.class);
        
        //getBean() 메소드로 구성 클래스에 선언된 빈을 가져옴
        SequenceGenerator generator = context.getBean(SequenceGenerator.class);
        
        System.out.println(generator.getSequence());
        System.out.println(generator.getSequence());
    }
}
cs


2. POJO 클래스에 @Component를 붙여 DAO 빈 생성하기


 지금까지는 구성클래스 값을 하드코딩해서 스프링 빈을 인스턴스화했다.

 실제로 POJO는 대부분 DB나 유저 입력을 이용해 인스턴스화한다. 이번에는 더 현실적인 시나리오로, Domain 클래스와 DAO(Data Access Object)를 이용해 POJO을 생성한다.

 DB를 실제로 구현하진 않고, DAO 클래스에 하드코딩할 것이다. (이런 구조가 추후에 많이 사용된다.)


 앞에 나온 시퀀스 생성기에 도메인 클래스, DAO 패턴을 적용하기 위해 클래스 구조를 바꿔야한다. 

 우선 Sequence 도메인 클래스를 만든다.


Sequence

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
package com.apress.springrecipes.sequence;
 
public class Sequence {
    private String id;
    private final String prefix;
    private final String suffix;
    
    public Sequence(String id, String prefix, String suffix) {
        this.id = id;
        this.prefix = prefix;
        this.suffix = suffix;
    }
    
    public String getId() {
        return id;
    }
    
    public String getPrefix() {
        return prefix;
    }
    
    public String getSuffix() {
        return suffix;
    }
}
 
cs



 다음은 DB 데이터 액세스를 처리하는 DAO 인터페이스와 이를 구현한 구상 클래스를 보자.

 

 SequenceDao

1
2
3
4
5
6
7
8
9
10
package com.apress.springrecipes.sequence;
 
public interface SequenceDao {
    //DB 테이블에서 sequenceId로 POJO나 Sequence 객체를 로드함
    Sequence getSequence(String sequenceId);
    
    //다음 시퀀스 값을 얻어옴
    int getNextValue(String sequenceId);
}
 
cs


SequenceDaoImpl

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
package com.apress.springrecipes.sequence;
 
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
 
import org.springframework.stereotype.Component;
 
@Component("sequenceDao")
public class SequenceDaoImpl implements SequenceDao {
    private final Map<String, Sequence> sequences = new HashMap<>();
    private final Map<String, AtomicInteger> values = new HashMap<>();
    
    //생성자에서 데이터베이스를 하드코딩으로 구현함
    public SequenceDaoImpl() {
        sequences.put("IT"new Sequence("IT""30""A"));
        values.put("IT",  new AtomicInteger(10000));
    }
    
    public Sequence getSequence(String sequenceId) {
        return sequences.get(sequenceId);
    }
    
    public int getNextValue(String sequenceId) {
        AtomicInteger value = values.get(sequenceId);
        return value.getAndIncrement();
    }
}
 
cs



 SequenceDaoImpl 클래스에 @Component("sequenceDao")를 붙이면 스프링은 이 클래스를 이용해 POJO를 생성한다. @Component에 넣은 값("sequenceDao")으로 빈 이름으로 할당된다.

 @Component는 스프링이 발견할 수 있게 POJO에 붙이는 범용 어노테이션이다. 스프링에는 Persistent(영속화), Service(서비스), Presentation(표현)의 세 레이어가 있는데, @Repository, @Service, @Controller가 각각 이 세 레이어를 가리키는 어노테이션이다.


 POJO의 쓰임새가 명확하지 않을 땐 그냥 @Com[onent를 붙여도 되고, 특정 용도에 맞게 쓰려면 구체적으로 명시하는 편이 좋다.(ex: @Repository는 발생한 예외를 DataAccessException으로 감싸 던지기 때문에 디버깅시 유리함)


스캐닝 커스터마이징

 기본적으로 스프링은 @Configuration, @Bean, @Component, @Repository, @Service, @Controller가 달린 클래스를 모두 감지하는데, 필터를 적용하여 스캐닝 과정을 커스터마이징하면 원하는 어노테이션만 골라서 컨텍스트에 포함시키거나 제외할 수 있다.

 모든 패키지를 스캐닝하면 시동 과정이 쓸데없이 느려 질 수 있어서 유용하다.


 다음 예시와 같이 필터를 적용 할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.apress.springrecipes.sequence.config;
 
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
 
@Configuration
@ComponentScan(
        includeFilters = { 
                @ComponentScan.Filter(
                        type = FilterType.REGEX, 
                        pattern = {"com.apress.springrecipes.sequence.*Dao""com.apress.springrecipes.sequence.*Service" }
                }, 
        excludeFilters = {
                @ComponentScan.Filter(
                        type = FilterType.ANNOTATION, 
                        classes = {org.springframework.stereotype.Controller.class }
                }
        )
 
public class SequenceGeneratorConfiguration {
 
}
 
cs



 스프링에서 지원하는 필터 표현식은 네종류다. 

- annotation : 필터 대상 어노테이션 타입 지정

- assignable : 필터 대상 클래스/인터페이스 지정

- regex : 정규 표현식을 이용한 클래스 매칭으로 대상 클래스 지정

- aspectj : AspectJ 포인트컷 표현식으로 클래스를 매칭하여 대상 클래스 지정


 위 예시에서는 regex, annotation 표현식을 이용해 필터링을 적용하였다.

 includeFilters에서 com.appress.springrecipes.sequence.*Dao/*Service 형태의 이름을 가진 클래스를 포함하도록 했기 때문에, 어노테이션이 달려있지 않아도 스프링이 자동 감지한다.

 excludeFilters에서는 Controller 클래스를 지정해 제외시켰다.


 테스트는 다음의 코드로 진행한다.


 Main

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.apress.springrecipes.sequence;
 
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
 
public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext("com.apress.springrecipes.sequence");
        
        SequenceDao sequenceDao = context.getBean(SequenceDao.class);
        
        System.out.println(sequenceDao.getNextValue("IT"));
        System.out.println(sequenceDao.getNextValue("IT"));
    }
}
 
cs



3. 레퍼런스

스프링 5 레시피(4판) - 한빛 미디어




블로그 이미지

서기리보이

,

1. 환경 구축


 스프링 프레임워크를 이용한 개발을 위한 개발툴(IDE)에는 이클립스, STS, 인텔리제이, 메모장 등을 사용할 수 있는데, 글쓴이는 STS를 이용한다.


 최신 STS4 버전을 이용하고, jdk 1.8.0_241 버전을 이용한다.


 설치방법은 다음의 '나 연구소'라는 블로그에 정리가 잘 되어있으니 (링크)를 참조하면 좋을 듯 하다.


 설치를 완료하고, SpringToolSuite4.exe 를 실행하면 이클립스와 거의 똑같은 화면이 뜬다.



2. 메이븐 프로젝트 임포트 및 실행

 

 STS4를 실행하면 다음과 같은 화면이 뜬다.


 여기서 Create new Spring Starter Project를 클릭하고, 그 후 설정은 이번에는 모두 기본값으로 두고 진행한다.


 이후 File - Import 을 클릭하고, Maven/Existing Maven Project 옵션을 선택한다.


 이후 디렉토리 설정에서 ch01/springintro_mvn 디렉토리를 지정한다.



 여기서 Import Maven Projects 창에서 pom.xml com.apress.springrecipes... 이 내용이 보이면 프로젝트가 정상적으로 임포트 된 것이다.


 이 상태가 됬다면 Finish하면 된다.


 이후 프로젝트를 선택하고 RunAs - Maven Build 옵션을 선택하고, 팝업창이 뜨면 Run하면 빌드된다.


 이제 F5를 눌러 프로젝트 디렉토리를 갱신해보면 하위 디렉토리에 target 디렉토리사 새로 생겨있다. 이 디렉토리 아래 springintro_mvn-4.0.0-SNAPSHOT.jar 파일을 우클릭하고 Run as - Run configurations 옵션을 선택하면 실행 설정을 편집하는 팝업이 뜬다.


여기서 좌측에 Java application을 선택하고, Main Class 박스에 이 프로젝트의 메인 클래스 com.apress.springrecipes.hello.Main을 입력한다.(탐색 기능을 쓰면 정확히 찾을 수 있음)


 이제 Run 버튼을 클릭하면 인사말이 뜬다.

실행 결과



3. 그레이들 프로젝트 임포트 및 실행


 그레이들은 메이븐보다 최근에 나온 빌드 스크립트로, 조만간 메이븐을 대체할 예정이다.


 STS에서 그레이들을 사용하려면 우선 Buildship 확장 플러그인을 설치해야한다.

 STS상단 메뉴에서 Help - Eclipse Marketplace 를 선택하고, Gradle 키워드로 검색한다.

 (책에서는 2.0버전을 설치하라고 되어있지만 현재는 3.0버전밖에 없음)


 이제 예제 소스를 임포트하는 단계다.

 File - Import 에서 Gradle/Existing Gradle Projects 옵션으로 넘어간다.

 디렉토리는 예제 소스의 ch01/springintro 디렉토리로 설정한다.




 이후 프로젝트를 선택하고 Run 하면 실행된다.


 책에서는 프로젝트를 빌드하고, libs 디렉터리의 springintro.jar 파일을 선택에 Run configurations 설정에서 Main class를 설정해줘야한다고 하는데 이 과정이 필요없이 바로 실행이 됬다.

 빌드쉽 버전 차이 때문에 그런게 아닐까 싶다.


 배움이 즐거운 개발자님의 포스팅을 통해 빌드하는 법을 찾았다.(링크)

 

 우선 STS에서 Gradle Tasks 뷰를 띄워야한다.

 우측 상단에 커맨드 검색 기능을 이용해 Show View(Gradle Tasks) 커맨드를 선택하여 Gradle Tasks 뷰를 띄우고, 해당 프로젝트의 build/jar를 더블 클릭하면 빌드된다.


 그러면 실제 디렉토리에 다음과 같이 jar 파일이 생성되어있다.

 



 

3. 빌드 스크립트


 자바 애플리케이션을 개발하다보면 JAR 파일이나 구성 파일 복사, 컴파일에 필요한 클래스패스 설정, JAR 의존체 다운로드 등 자잘한 작업이 많은데, 자바 빌드 툴이 이를 대신 처리한다.

 빌드 파일만 있으면 빌드시 원 개발자가 의도한 작업을 그대로 재현할 수 있기 때문에 자바 빌드 툴은 중요하다. 메이븐 pom.xml, 그레이들 build.gradle 파일만 있으면 빌드 툴에 무관하게 다른 유저, 다른 시스템에서도 일관되게 빌드할 수 있다.

 자바 개발자들은 대부분 빌드 스크립트로 메이븐 pom.xml이나 이보다 나중에 나온 build.gradle을 사용한다.

 이 부분은 아직 빌드 스크립트를 본 적 없어서 이해가 가지 않을 수 있으니 일단 넘어가자.


4. 레퍼런스

스프링 5 레시피(4판) - 한빛 미디어

https://m.blog.naver.com/PostView.nhn?blogId=pyj721aa&logNo=221613874213&proxyReferer=https%3A%2F%2Fwww.google.com%2F - STS 설치

https://github.com/nililee/spring-5-recipes - 스프링 예제

https://galid1.tistory.com/500 - 그레이들 빌드 하는 법.

블로그 이미지

서기리보이

,