반응형

이번 시간에는 github의 webhook을 이용해서 소스코드를 push를 하면 자동적으로 소스코드가 배포될 수 있도록 해보겠습니다.

참고로 이번 과정에서는 jenkins pipeline이 구축되어 있는 상태에서 시작합니다.

jenkins 파이프라인이 처음이시라면 저의 블로그에 "토이 프로젝트_STEP 04"를 보고 한 번 따라 해보시길 추천드립니다.

 

Github

github Repotisory > Settings > Webhooks > Add webhook

 

 

webhook

  • Payload URL - 젠킨스 서버 주소에 /generic-webhook-trigger 경로를 추가하고 token를 입력합니다.
    • http://locahost:8080를 입력하시면 정상적으로 동작하지 않습니다. (외부에서 접근할 수 있도록 젠킨스 서버를 Forwarding)
    • ngrok 어플리케이션을 이용하면 서버를 쉽게 Forwarding 할 수 있습니다.
  • Content type - application/json 타입을 사용합니다.
  • Add webhook 버튼을 누릅니다.

 

github에서 하는 webhook 설정은 모두 끝났습니다.

 

이제 전에 구축한 jenkins 파이프라인에 webhook 설정을 추가하도록 하겠습니다.

 

Jenkins

jenkins pipeline Configuration

jenkins pipeline Configuration

Post content parameters

  - push한 사용자 이름으로 빌드를 유발시키도록 하겠습니다.

 

Token

   - 위에서 작성한 토큰 정보를 작성합니다.

 

 

Optional filter

  - Post content parameters에 매핑될 사용자 아이디를 작성합니다. 

 

이것으로 webhook 설정은 끝났습니다.

이제 한 번 webhook을 이용해서 빌드를 유발하도록 하겠습니다.

 

소스코드를 push 하면 아래와 같이 webhooks > Recent Deliveries에서 webhook에 대한 정보를 확인하실 수 있습니다.

초록색으로 체크가 되었다면 정상적으로 jenkins에게 이벤트를 전달했다고 생각하시면 될 것 같습니다.

 

728x90
반응형

'Jenkins' 카테고리의 다른 글

[Jenkins] fatal : Authentication failed for 'https://github.com~'  (0) 2022.06.02
반응형

토이 프로젝트로 혼자서 클라우드 서비스를 이용하여 웹 개발부터 배포까지 온 과정을 경험해 보았습니다.

이 과정을 단계별로 나누어서 정리해 보려고 합니다.!

많은 피드백은 감사합니다!

 

목차 

STEP 01) NCP 서버 

STEP 02) AWS RDS, S3

STEP 03) Web Application 개발

STEP 04) Jenkins pipeline 배포

STEP 05) Domain 등록

 


이번에는 AWS Route53 서비스를 이용해서 도메인을 등록해보겠습니다.

 

가비아에서 구매 한 도메인을 AWS Route53에 등록해보겠습니다.

Route53에서도 도메인 구매가 가능합니다

 

1. 호스팅 영역 > 호스팅 영역 생성

 

 

2. 도메인 정보 입력

  - 도메인 이름 : 구매한 도메인

  - EC2 퍼블릭 IP

  - 퍼블릭 호스팅 영역 : 인터넷에서 트래픽을 라우팅하고자 하는 방법을 지정하는 레코드를 포함합니다.

 

3. NameServer 등록

  - NS : 네임서버 레코드로 도메인에 대한 네임서버의 권한을 가지고 있는지 알려주는 레코드

  - SOA : 도메인의 정보를 가지고 있는 레코드

 

 

4. 가비아에 AWS 네임서버 등록

  - 호스팅업체의 네임서버를 사용해도 무방합니다.

 

가비아에 등록된 네임서버

5. 도메인과 EC2 인스턴스 IP 연결

  - 레코드 생성 클릭

 

 

레코드 이름 : 라우팅할 이름을 설정합니다.

레코드 유형 : ec2로 라우팅할 경우 ipv4로 라우팅합니다.

값 : ec2 인스턴스 퍼블릭 IP

TTL : DNS에 ip 주소를 저장하는 시간

 

 

레코드를 생성하면 시간이 조금 지나서 등록한 도메인으로 접속이 가능합니다!

Route53은 Free tier 사용하더라도 월별 호스팅 가격 및 쿼리(도메인을 통해서 AWS에 접속하는 횟수) 비용이 발생합니다.

  - Rout53 요금제

728x90
반응형
반응형

토이 프로젝트로 혼자서 클라우드 서비스를 이용하여 웹 개발부터 배포까지 온 과정을 경험해 보았습니다.

이 과정을 단계별로 나누어서 정리해 보려고 합니다.!

많은 피드백은 감사합니다!

 

목차 

STEP 01) NCP 서버 

STEP 02) AWS RDS, S3

STEP 03) Web Application 개발

STEP 04) Jenkins pipeline 배포

STEP 05) Domain 등록


이번에는 젠킨스 파이프라인을 구축해보도록 하겠습니다.

 

젠킨스 파이프라인 구성 순서

1. pipeline 구조 생성

2. github clone

3. gradle build

4. ssh를 이용해서 파일 전송 후 applicaton 기동

 

1. pipeline 구조 생성

젠킨스 파이프라인 구성에 앞서 구조부터 생성해보도록 하겠습니다.

 

1.1) pipeline 생성

Dashboard > 새로운 Item > name 작성하고 OK

 

 

1.2) 샘플을 실행 시켜봅시다. (Advanced Project Options 탭에서 우측상단의 Hello Wold 선택하고 저장)

 

1.3) 파이프라인 실행

  - 파이프라인 구조를 생성하고 샘플 Script를 실행해보았습니다. 이제 본격으로 파이프라인 구성을 해보도록 하겠습니다.

 

2. github clone

jenkins pipeline은 Pipeline Syntax를 이용해서 Script를 생성해서 구성합니다.

 

2.1) Pipeline Syntax > Sample Step(git: Git 선택 혹시 안보이신다면 jenkins관리에서 github plugin을 설치하시기 바랍니다.)

 

2.2) github repository url을 작성하시고 배포할 Branch를 선택합니다.

 

2.3) 첫 Jenkins 세팅이라면 Credentials 없으실텐데요. 아래 Add > Jenkins 클릭하시면 아래와 같은 창이 나옵니다.

    - Kind를 Username with password를 선택 후 Password에는 github token을 넣어줍니다. github token 발급은 바로 아래에서 설명드리겠습니다.

    - ID는 중복되지 않도록 작성하시면 됩니다.

 

2.4) github token 발급

github > Settings > 오르쪽 카테고리에서 Developer settings 선택

 

 

Note - token을 구분할 수 있도록 작성하고 Expiration으로 토큰의 기간을 정한다.

Select scopes - 필요한 권한을 체크한다.(저는 repo, admin:repo_hook 체크)

repo : repository 권한

admin:repo_hook : webhook에 필요한 hook 권한

 

Generate token을 클릭하면 token이 발급됩니다.

아래와같이 발급된 토큰을 복사해서 사용하면됩니다. 토큰 기간만료 또는 분실시 같은 방법으로 토큰을 발급받으면 됩니다.

 

 

다시 jenkins로 위에서 추가한 Credentials를 선택하고 Generate Pipeline Script 클릭하면 Script가 생성됩니다.

 

 

Syntax에서 생성한 Script를 pipeline으로 가져와서 그대로 붙여줍니다.

 

 

github clone에 성공하였습니다!

 

 

3. gradle build

build stage를 추가하도록 하겠습니다.

  - build는 clone으로 가져온 소스에 포함되어 있는 gradle wrapper를 이용합니다. 자신의 소스코드에 맞게 위치를 지정해서 gradle          build를 해주시면 됩니다.

 

 

build까지 성공하였습니다! 애플리케이션이 배포되기까지 거의 다 왔습니다!

 

 

4. ssh를 이용해서 파일 전송 후 applicaton 기동

빌드된 파일을 전달하기위해서는 jenkins에 publish over ssh plugin이 설치되어있어야 합니다.

 

플러그인이 설치되면 Dashboard > Jenkins 관리 > Configure System으로 이동해서 Publish over SSH에 서버 정보를 입력하면 됩니다.

 

저는 AWS EC2 서버를 사용하고있습니다.

EC2 접속에 필요한 pem 키를 Key에 붙여넣어줍니다.

Name : syntax에서 참조될 이름

Hostname : private ip

Username : ec2에서 사용되는 username

Remote Dircetory : 베이스 디렉토리(참고, 이 디렉터리 기준으로 파일이 전송되고, 스크립트가 실행된다.)

 

 

모두 작성하시고 Test Configuration를 클릭하시면 문제 없으면 Success가 표시됩니다.

 

Pipeline Syntax로 돌아가서 Step : sshPublisher: Send build artifacts over SSH 선택

Souce files : 빌드된 파일 위치입니다.

Remove prefix : 소스파일에서 원본 파일의 디렉토리를 어디까지 포함할 것인지 설정입니다.(여기서는 jar 파일 하나만 선택되도록 설정)

Remote directory : 위에서 선택된 jar 파일을 해당 디렉터리 아래에 위치시킵니다.

Exec command : 파일을 전송한 다음 실행할 shell

 

마지막으로 Pipeline에 stage를 추가해서 위 script를 붙여줍니다.

 

최종 pipeline script

pipeline {
    agent any

    stages {
        stage('github clone') {
            steps {
                git credentialsId: 'tutorial-jenkins-token', url: 'https://github.com/kgc0120/daily_special.git'
            }
        }
        
        stage('build'){
            steps{
                sh'''
                    echo build start
                    ./gradlew clean bootJar
                '''
            }
        }
        
        stage('publish over ssh'){
            steps{
                sshPublisher(publishers: [sshPublisherDesc(configName: 'aws-daily-special'
                , transfers: [sshTransfer(cleanRemote: false
                , excludes: ''
                , execCommand: 'sh /dailySpecial/app/nonstop/deploy.sh'
                , execTimeout: 120000, flatten: false, makeEmptyDirs: false
                , noDefaultExcludes: false
                , patternSeparator: '[, ]+'
                , remoteDirectory: '/app/nonstop/springboot-webservice/build/libs'
                , remoteDirectorySDF: false
                , removePrefix: 'build/libs', sourceFiles: 'build/libs/*.jar')]
                , usePromotionTimestamp: false
                , useWorkspaceInPromotion: false
                , verbose: false
                )])
            }
        }
    }
}

 

pipeline을 실행시켜보면 서버 배포까지 정상적으로 성공하였습니다!!

 

 

정말 시행착오도 많았고 길었던 Jenkins pipeline 구축이었습니다... ㅜ

다음번에는 github webhooke을 이용해서 소스코드를 push 하면 젠킨시가 자동으로 배포되도록 해보겠습니다.

728x90
반응형
반응형

Spring에서 @Value 애노테이션은 설정 파일(yml, properties)에 있는 정보를 가져오는데 주로 사용됩니다.

@Value로 설정 파일 값을 가져오는 변수가 null인 경우 점검해보아야 하는 부분을 정리하였습니다. 

 

1. 어느 @Value 애노테이션을 사용했는지 import 확인

lombok이 아닌 spring 애노테이션을 사용하자

import org.springframework.beans.factory.annotation.Value;

 

2. static 변수에는 값을 넣을 수 없다.

예시는 application.properties 파일에서 active.root 값을 Config class에서 path 변수에 저장해서 사용하고 있습니다.

path 변수를 클래스 변수(static 변수)로 지정해서 테스트 해보도록 하겠습니다.

 

Config.java

@Component
public class Config {

    @Value("${active.root}")
    private static String path;

    public String getPath() {
        return path;
    }
}

 

application.properties

active.root=home

 

Test Code

@SpringBootTest
class ConfigServiceTest {

    @Autowired
    Config config;

    @Test
    void findActiveRootTest() {
        String root = "home";
        Assertions.assertEquals(config.getPath(), root);
    }

}

 

Test Code 결과

org.opentest4j.AssertionFailedError: 
Expected :null
Actual   :home

 

null 이 출력되는 것을 확인할 수 있습니다.

Config class에서 static 변수를 일반 전역 변수로 수정하면 문제를 해결됩니다.

 

3. Spring Bean으로 생성된 객체가 아닌 경우

Spring은 애플리케이션 로딩 시점에 스프링 컨테이너 내부에서 모든 빈들을 등록하면서 @Value 애노테이션 안의 값들을 설정 파일에서 읽어들여 변수에 저장합니다.

그 결과 Spring에서 싱글톤으로 관리되는 빈이 아닌 새로운 객체로 생성하게 되면 @Value 애노테이션으로 설정 파일을 읽어들이는 변수는 null로 값이 저장되지 않습니다.

 

Test Code

  - @Autowired를 제거하고 new를 이용해서 Config 인스턴스를 생성하였습니다.

@SpringBootTest
class ConfigServiceTest {

    @Test
    void findActiveRootTest() {

        Config config = new Config();

        String root = "home";
        Assertions.assertEquals(config.getPath(), root);
    }

}

 

Test Code 결과

org.opentest4j.AssertionFailedError: 
Expected :null
Actual   :home

 

Test Code

 - 정상으로 값이 저장되는 경우

 - new 연산자를 이용해서 인스턴스를 생성해서 사용하고 있는 것은 아닌지 확인해 보자!

@SpringBootTest
class ConfigServiceTest {

    @Autowired
    Config config;

    @Test
    void findActiveRootTest() {
        String root = "home";
        Assertions.assertEquals(config.getPath(), root);
    }

}
728x90
반응형
반응형

1. Jar 파일 생성하기

1. File > Project Structure

 

2. Artifacts > + 버튼 클릭 > JAR > From modules with dependencies...

 

 

3. Main Class - Jar 실행 파일을 생성할 경우 Main Class 선택 / 외부 추가용 Jar 파일 생성할 경우 생략

    

 

4. 위 2번 순서에 Output directory 위치에 Jar 파일 생성

 

 

2. 외부 Jar 파일 추가해서 사용하기

Spring Boot 프로젝트에 위에서 생성한 printjar 파일을 외부 jar 파일로 추가해서 사용해 보도록 하겠습니다.

 

위에서 생성한 printjar 파일 내부 클래스

package lib;

public class PrintJarMain {

    public static void print() {
        System.out.println("PrintJar Call!!");
    }

    public void test() {
        System.out.println("test");
    }


}

 

1. File > Project Structure

 

 

2. Modules > main > + 버튼 클릭 > JARs or Directories... > 위에서 생성한 printjar 파일 선택

 

3. Main 함수

  - 외부 jar로 추가한 printjar 내부 클래스의 메소드 호출

@SpringBootApplication
public class AopApplication {

    public static void main(String[] args) {

        PrintJarMain printJarMain = new PrintJarMain();
        System.out.println("<<<<<===============>>>>>>>>>");
        printJarMain.print();
        System.out.println("<<<<<===============>>>>>>>>>");
        printJarMain.test();
        System.out.println("<<<<<===============>>>>>>>>>");
        SpringApplication.run(AopApplication.class, args);
    }

}

 

4. 결과

<<<<<===============>>>>>>>>>
PrintJar Call!!
<<<<<===============>>>>>>>>>
test
<<<<<===============>>>>>>>>>

728x90
반응형
반응형

git 캐시를 삭제 후 다시 프로젝트를 PUSH 해줍니다.

 

git rm -r --cached .
git add .
git commit -m "DELETE git cached"

 

추가적으로 .gitignore에 파일이 등록되어 앞으로 파일이 repository에 안 올라가도 히스토리를 통해서 기존 파일 확인이 가능합니다.

중요한 정보가 노출되는 불상사를 막기 위해서는 히스토리도 삭제를 해줘야 합니다.

 

설정 파일인 yml 파일의 히스토리를 삭제해 보도록 하겠습니다. 

--ignore-unmatch 파일 경로( git repository 기준의 경로값)

 

git filter-branch --force --index-filter "git rm --cached --ignore-unmatch *.yml" --prune-empty --tag-name-filter cat -- --all
git push origin master --force

 

이상으로 git 캐시 삭제와 히스토리 삭제를 알아보았습니다!

728x90
반응형

'Git' 카테고리의 다른 글

[Git] Mac SSH키 생성  (0) 2022.03.12
[Git] 기존 프로젝트 Git Repository 연결  (0) 2021.06.06
[Git] push 했는데 잔디가 안 심어질 때..  (0) 2021.05.09
[Git] SSH키 설정  (0) 2020.12.12
반응형

데코레이터 패턴(Decorator Pattern)

  - 데코레이터 패턴은 프록시 기법을 사용하는 디자인 패턴 중에 하나입니다.

  - GOF 디자인 패턴에서는 의도에 따라 두 가지 패턴으로 구분하였습니다. 

 

프록시의 주요 기능

프록시를 통해서 할 수 있는 일은 크게 2가지로 나뉜다.

1. 접근 제어 (권한에 따른 접근 차단, 캐싱 등)

2. 부가 기능 추가 (다른 로직을 추가하는 등의 부가 기능을 수행, 예) 실행 시간을 측정해서 로그를 남긴다.)

 

* GOF 디자인 패턴에서는 의도에 따라서 프록시 패턴과, 데코레이터 패턴으로 구분한다.

  - 프록시 패턴 : 접근 제어가 목적

  - 데코레이터 패턴 : 새로운 기능 추가가 목적

 

프록시 패턴의 장점

  - 부가 기능을 추가하여서 원하는 흐름에 맞게 조정할 수 있습니다.

 

코드

 * 메시지를 출력하는 기능에 메시지를 꾸며주는 기능을 데코레이터 패턴을 이용해서 적용해 보겠습니다.

 

Component.java

  - interface로 Component 생성

 

public interface Component {
    String operation();

}

 

RealComponent.java

  - 실제 Component 구현체

 

@Slf4j
public class RealComponent implements Component{
    @Override
    public String operation() {
        log.info("RealComponent 실행");
        return "data";
    }
}

 

DecoratorPatternClient.java

  - Component를 실행하는 클라이언트 클래스

 

@Slf4j
public class DecoratorPatternClient {

    private Component component;

    public DecoratorPatternClient(Component component) {
        this.component = component;
    }

    public void execute() {
        String result = component.operation();
        log.info("result={}", result);
    }

}

 

DecoratorPatternTest.java

  - 기본 메시지 출력 기능 테스트

@Slf4j
public class DecoratorPatternTest {

    @Test
    void noDecorator() {
        Component realComponent = new RealComponent();
        DecoratorPatternClient client = new DecoratorPatternClient(realComponent);
        client.execute();
    }
}

결과 : RealComponent 실행

          result=data

 

MessageDecorator.java

  - 데코레이터 패턴을 이용해서 메시지 꾸며주는 기능 추가

  - MessageDecorator는 Component 인터페이스를 구현한다.

 

@Slf4j
public class MessageDecorator implements Component{

    private Component component;

    public MessageDecorator(Component component) {
        this.component = component;
    }

    @Override
    public String operation() {
        log.info("MessageDecorator 실행");

        String result = component.operation();
        String decoResult = "<< =====" + result + " ===== >>";
        log.info("MessageDecorator 꾸미기 적용 전={}, 적용 후 ={}",result, decoResult);
        return decoResult;
    }
}

 

DecoratorPatterTest.java

  - 클라이언트가 호출하기 전에 MessageDecorator 클래스를 이용해서 부가 기능을 추가 후 클라이언트에게 messageDecorator를 넘겨준다. messageDecorator도 Component를 구현하고 있기 때문에 클라이언트 입장에서는 전혀 문제가 발생하지 않는다.

 

@Slf4j
public class DecoratorPatternTest {

    @Test
    void decorator1() {
        Component realComponent = new RealComponent();
        Component messageDecorator = new MessageDecorator(realComponent);
        DecoratorPatternClient client = new DecoratorPatternClient(messageDecorator);
        client.execute();
    }
}

 

결과 :

 

정리 :

 

데코레이터 패턴의 의도 : 객체에 추가 책임(기능)을 동적으로 추가하고, 기능 확장을 위한 유연한 대안 제공

프록시 패턴의 의도 : 다른 객체에 대한 접근을 제어하기 위해 대리자를 제공

728x90
반응형
반응형

전략 패턴

탬플릿 메서드 패턴은 부모 클래스에 변하지 않는 템플릿을 두고, 변하는 부분을 자식 클래스에 두어서 상속을 사용해서 문제를 해결하였습니다.
전략 패턴은 변하지 않는 부분을 Context 라는 곳에 두고, 변하는 부분을 Strategy 라는 인터페이스를 만들고 해당 인터페이스를 구현하도록 해서 문제를 해결합니다.

상속이 아니라 위임으로 문제를 해결하는 것이다.

전략 패턴에서 Context 는 변하지 않는 템플릿 역할을 하고, Strategy 는 변하는 알고리즘 역할을 합니다.

 

전략 패턴 의도

알고리즘 제품군을 정의하고 각각을 캡슐화하여 상호 교환 가능하게 만들자.

전략을 사용하면 알고리즘을 사용하는 클라이언트와 독립적으로 알고리즘을 변경할 수 있습니다.

 

코드

방식1. 필드에 전략을 보관하는 방식

 ContextV1.java

 

@Slf4j
public class ContextV1 {

    private Strategy strategy; // 전략을 필드 변수로 선언

    public ContextV1(Strategy strategy) {
        this.strategy = strategy;
    }

    public void execute() {
        long startTime = System.currentTimeMillis();
        //비지니스 로직 실행
        strategy.call(); //위임
        //비즈니스 로직 종료
        long endTime = System.currentTimeMillis();
        long resultTime = endTime - startTime;
        log.info("resultTime={}", resultTime);
    }
}

 

변하는 알고리즘

 StrategyLogin1.java

 

@Slf4j
public class StrategyLogin1 implements Strategy {

    @Override
    public void call() {
        log.info("비즈니스 로직1 실행");
    }
}

 

 StrategyLogin2.java

 

@Slf4j
public class StrategyLogin2 implements Strategy {

    @Override
    public void call() {
        log.info("비즈니스 로직2 실행");
    }
}

 

테스트 코드

ContextV1Test.java

 

@Slf4j
public class ContextV1Test {

    @Test
    void strategyV1() {
        StrategyLogin1 strategyLogin1 = new StrategyLogin1();
        ContextV1 contextV1 = new ContextV1(strategyLogin1);
        contextV1.execute();

        StrategyLogin2 strategyLogin2 = new StrategyLogin2();
        ContextV1 contextV2 = new ContextV1(strategyLogin2);
        contextV2.execute();
    }

}

 

전략 패턴 사용은 선 조립, 후 실행으로 생각하면 보다 간단합니다.

변하지 않는 코드 ContextV1 객체에 변하는 알고리즘인 StrategyLogin1, StrategyLogin2를 생성자에 넣어서 조립하고, 호출이 필요한 시점에 execute()를 이용해서 실행합니다.
스프링 애플리케이션 개발 할 때 애플리케이션 로딩 시점에 의존관계 주입을 통해 필요한 의존관계를 모두 맺어두고
다음에 실제 요청을 처리하는 것과 같은 원리이다.

 

위와 같이 사용하게 되면 변하는 알고리즘인 전략 class가(StrategyLogin1, StrategyLogin2) 계속 생겨날 수밖에 없습니다.

이러한 점을 보완하기 위해서 익명 내부 클래스를 사용합니다.

 

익명 내부 클래스 사용

 

@Slf4j
public class ContextV1Test {

    @Test
    void strategyV2() {
        Strategy strategyLogic1 = new Strategy() {

            @Override
            public void call() {
                log.info("비즈니스 로직1 실행");
            }
        };
        ContextV1 contextV1 = new ContextV1(strategyLogic1);
        contextV1.execute();

        Strategy strategyLogic2 = new Strategy() {

            @Override
            public void call() {
                log.info("비즈니스 로직2 실행");
            }
        };
        ContextV1 contextV2 = new ContextV1(strategyLogic2);
        contextV2.execute();

    }

}

 

람다를 이용해서 보다 더 코드 수를 줄일 수 있습니다.

 

@Slf4j
public class ContextV1Test {

    @Test
    void strategyV3() {
        ContextV1 contextV1 = new ContextV1(() -> log.info("비즈니스 로직1 실행"));
        contextV1.execute();

        ContextV1 contextV2 = new ContextV1(() -> log.info("비즈니스 로직2 실행"));
        contextV2.execute();

    }

}

 

방식2. 필드에 전략을 보관하는 방식

 

전략을 파라미터로 전달 받는 방식, 실행할 때 마다 전략을 유연하게 변경할 수 있다.
단점 역시 실행할 때 마다 전략을 계속 지정해주어야 한다.

 

ContextV2.java

 

@Slf4j
public class ContextV2 {

    public void execute(Strategy strategy) {
        long startTime = System.currentTimeMillis();
        //비지니스 로직 실행
        strategy.call(); //위임
        //비즈니스 로직 종료
        long endTime = System.currentTimeMillis();
        long resultTime = endTime - startTime;
        log.info("resultTime={}", resultTime);
    }
}

 

테스트 코드

ContextV2Test.java

 

@Slf4j
public class ContextV2Test {


    /**
     * 전략 패턴 적용
     */
    @Test
    void strategyV1() {
        ContextV2 context = new ContextV2();
        context.execute(new StrategyLogin1());
        context.execute(new StrategyLogin2());
    }

    /**
     * 전략 패턴 익명 내부 클래스
     */
    @Test
    void strategyV2() {
        ContextV2 context = new ContextV2();
        context.execute(new Strategy() {
            @Override
            public void call() {
                log.info("비즈니스 로직 1 실행");
            }
        });
        context.execute(new Strategy() {
            @Override
            public void call() {
                log.info("비즈니스 로직 2 실행");
            }
        });
    }

    /**
     * 전략 패턴 익명 내부 클래스2, 람다
     */
    @Test
    void strategyV3() {
        ContextV2 context = new ContextV2();
        context.execute(() -> log.info("비즈니스 로직 1 실행"));
        context.execute(() -> log.info("비즈니스 로직 2 실행"));
    }

}

 

참고로 ContextV2 형식의 전략 패턴은 스프링 내부에서 템플릿 콜백 패턴이라고 부른다.

스프링에서 jdbcTemplate, RestTemplate, ~Template 처럼 다양한 템플릿 콜백 패턴이 사용된다.

 

 

참조

 - inflearn(스프링 핵심 원리 - 고급편, 김영한)

728x90
반응형

+ Recent posts