반응형

개요 : 아주 간단하게 Docker를 이용해서 Spring 프로젝트 이미지를 생성 후 실행해 보도록 하겠습니다.

 

1. spring project build

  - WebController.java

@Controller
public class WebController {

    @GetMapping("/")
    public String sample() {
        return "sample";
    }

}

  - sample.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Docker</title>
</head>
<body>
  <span>Docker!</span>
</body>
</html>

 

- gradle 기준 : 터미널에서 ./gradlew build

 

2. Dockrfile 생성

  - 프로젝트 Root 경로 바로 아래에 Dockerfile 생성

FROM openjdk:11  # 컴파일 할 jdk 버전

WORKDIR /usr/src/app # 모든 작업 파일 기준 위치

ARG JAR_PATH=./build/libs # 변수 사용하듯이 선언해서 사용

COPY ${JAR_PATH}/IPGeoCheck-0.0.1-SNAPSHOT.jar ${JAR_PATH}/IPGeoCheck-0.0.1-SNAPSHOT.jar
# 빌드한 jar 파일을 도커 컨터이너 내부로 옮겨주는 작업

CMD ["java","-jar","./build/libs/IPGeoCheck-0.0.1-SNAPSHOT.jar"]
# jar 파일 실행 명령

 

3.  도커 이미지 빌드

  - 터미널에서 아래와 같이 명령어 실행(도커 파일이 있는 위치에서)

docker build . -t springbootapp (도커 이미지 빌드)

 

 

4. 도커 이미지 실행

  - p 옵션을 넣어서 실행한다.

    도커 내부 네트워크와 외부 네트워크를 연결하기 위한 포트 연결(로컬 포트 / 도커 내부 포트)

    주의 : 포트 옵션을 주지 않으면 도커 이미지를 실행 되었으나 접근이 안되는 현상이 발생된다.

docker run -p 8080:8080 springbootapp(이미지 실행)

※ 문제점 : 어플리케이션 코드의 변경으로 인해서 도커 이미지를 매번 다시 빌드해서 실행해야 한다.

이러한 불편함을 해소하고자 Volume 옵션을 사용한다.

 

 

5. 볼륨(Volume) 옵션을 이용한 도커 이미지 실행

docker run -p 8080:8080 -v $(pwd):/usr/src/app springbootapp(볼륨을 사용한 이미지 실행)
# -v "local 참조할 경로" : "참조할 도커 이미지 경로"
Volume 옵션은 실행에 필요한 파일을들 컨테이너 내부에서 참조할 수 있도록 해줍니다.
로컬 경로에 존재하는 모든 파일들을 도커 컨테이너 내부에서 사용할 수 있습니다.

 

728x90
반응형

'Docker' 카테고리의 다른 글

[Docker] docker compose 이용해서 Wordpress 세팅  (0) 2023.09.26
반응형

자바의 자료형은 크게 기본 타입(primitive type)과 참조 타입(reference type)으로 나뉩니다.

기본 타입은 byte, char, short, int, long, float, double, boolean

참조 타입은 class, interface가 있습니다.

이때 기본 자료타입(primitive type)을 객체로 다루기 위해서 사용하는 클래스들을 래퍼 클래스(wrapper class)라고 합니다.

 

래퍼 클래스는 기본 유형을 래핑하고 변환 메서드, 비교 메서드 및 유틸리티 메서드와 같은 추가 기능을 제공하는 Java 표준 라이브러리의 클래스입니다. 각 기본 유형에는 해당 래퍼 클래스가 있습니다.

 

  • Byte: wraps a byte value
  • Short: wraps a short value
  • Integer: wraps an int value
  • Long: wraps a long value
  • Float: wraps a float value
  • Double: wraps a double value
  • Character: wraps a char value
  • Boolean: wraps a boolean value

 

래퍼 클래스는 기본 유형을 객체로 취급해야 하는 상황에서 주로 사용됩니다. 예를 들어 Integer 클래스를 사용하여 컬렉션에 int 값을 저장하거나 Integer 개체를 개체를 예상하는 메서드에 대한 인수로 전달할 수 있습니다.

요약하면 기본 유형과 래퍼 클래스의 주요 차이점은 기본 유형은 프로그래밍 언어에 내장된 기본 데이터 유형인 반면 래퍼 클래스는 기본 유형을 래핑하고 추가 기능을 제공하는 클래스라는 것입니다.

 

int Integer
기본타입 참조타입
산술 연산 가능함 산술 연산 불가능
null로 초기화 불가능 null 초기화 가능

 

추가적으로 기본 타입의 데이터를 wrapper 클래스의 인스턴스로 변환하는 과정을 박싱(Boxing)이라고 하고, 래퍼 클래스의 인스턴스에 저장된 값을 다시 기본 타입의 데이터로 꺼내는 과정을 언박싱(UnBoxing)이라고 합니다.

728x90
반응형

'JAVA' 카테고리의 다른 글

Java 스트림(Stream) 정리  (0) 2021.07.17
반응형

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
반응형
반응형

데코레이터 패턴(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
반응형
반응형

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

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

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

 

목차 

STEP 01) NCP 서버 

STEP 02) AWS RDS, S3

STEP 03) Web Application 개발

STEP 04) Jenkins pipeline 배포

STEP 05) Domain 등록

 

 


 

* Web Application 개발은 앞에서 살펴보았던 AWS 서비스를 사용하는 방법만 소개하도록 하겠습니다.

 

개발 환경

 - SpringBoot 2.6.6

 - Mariadb 2.7.5

 - Gradle 7.4.1

 

1. RDS 연결(yml 설정)

  - 이전 RDS 설정 확인

spring:
  datasource:
    url: jdbc:mariadb://rds end point 주소 + prot + schema name
      예) jdbc:mariadb://rds.amazonaws.com:3306/rdstest
    driver-class-name: org.mariadb.jdbc.Driver
    username: admin
    password: 패스워드

 

2. S3 연결

  - 이전 S3 설정 확인

1.  spring cloud starter 의존성 추가

  - build.gradlew

implementation 'io.awspring.cloud:spring-cloud-starter-aws:2.3.1'

 

2. yml 설정

cloud:
  aws:
    credentials:
      access-key: access key
      secret-key: secret key
    s3:
      region: ap-northeast-2
      endpoint: s3-bucket

 

  - access key, secrey key 새 액세스 키 만들기로 생성

 

 

- region, endpoint 작성

  endpoint는 :::뒤에 복/붙

 

AwsS3Config.java

 

package com.bumblebee.dailyspecial.domain.aws;

import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author bumblebee
 */
@Configuration
public class AwsS3Config {

    @Value("${cloud.aws.credentials.access-key}")
    private String accessKey;

    @Value("${cloud.aws.credentials.secret-key}")
    private String secretKey;

    @Value("${cloud.aws.s3.region}")
    private String region;

    @Bean
    public AmazonS3Client amazonS3Client() {
        BasicAWSCredentials awsCreds = new BasicAWSCredentials(accessKey, secretKey);
        return (AmazonS3Client) AmazonS3ClientBuilder.standard()
                .withRegion(region)
                .withCredentials(new AWSStaticCredentialsProvider(awsCreds))
                .build();
    }

}

 

AwsS3Service.java

 

package com.bumblebee.dailyspecial.domain.aws;

import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.CannedAccessControlList;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.bumblebee.dailyspecial.domain.comutils.CommonUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;

/**
 * @author bumblebee
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class AwsS3Service {

    private final AmazonS3Client amazonS3Client;

    @Value("${cloud.aws.s3.endpoint}")
    private String bucketName;

    public String uploadFileV1(String category, MultipartFile multipartFile) {
        validateFileExists(multipartFile);

        String fileName = CommonUtils.buildFileName(category, multipartFile.getOriginalFilename());

        ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setContentType(multipartFile.getContentType());

        try (InputStream inputStream = multipartFile.getInputStream()) {
            amazonS3Client.putObject(new PutObjectRequest(bucketName, fileName, inputStream, objectMetadata)
                    .withCannedAcl(CannedAccessControlList.PublicRead));
        } catch (IOException e) {
//            throw new FileUploadFailedException();
        }

        return amazonS3Client.getUrl(bucketName, fileName).toString();
    }

    private void validateFileExists(MultipartFile multipartFile) {
        if (multipartFile.isEmpty()) {
//            throw new EmptyFileException();
        }
    }

}

 

AwsS3Config class에 amazonS3Client 메소드를 @Bean으로 등록합니다.

파일을 업로드가 필요한 로직에 AwsS3Service class에서 uploadFIleV1 메소드를 이용해서 S3에 업로드 합니다.

예)

awsS3Service.uploadFileV1("Img", multipartFile);

 

그 외 다운로드 및 다중 업로드 기능도 제공하고 있습니다.

 

참조

  - Springboot로 S3 파일 업로드하기

728x90
반응형
반응형

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

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

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

 

목차 

STEP 01) NCP 서버 

STEP 02) AWS RDS, S3

STEP 03) Web Application 개발

STEP 04) Jenkins pipeline 배포

STEP 05) Domain 등록


1. NCP(Naver CLoud Platform)

  - 네이버 클라우드 서비스로 1년간 Free Tier 서비스를 이용할 수 있습니다.

  - 네이버 클라우드 서비스를 사용해 보고 싶어서 서버는 NCP Sorver를 선택

  - 네이버 클라우드 서비스라서 언어가 매우 친숙함.

 

https://www.ncloud.com/

 

NAVER CLOUD PLATFORM

cloud computing services for corporations, IaaS, PaaS, SaaS, with Global region and Security Technology Certification

www.ncloud.com

 

2. NCP에서는 다양항 클라우드 서비스를 제공합니다.

  - Free Tier에서는 아래 설명과 같이 Micro Server를 1년간 무료로 1대를 제공합니다. 

  - Compute > Server 선택

  - NCP server guide(https://guide.ncloud-docs.com/docs/compute-server-prep)

 

 

3. Server > 서버 생성

 

 

4. 서버 이미지 선택에서 서버 타입 Micro 선택 후 centos-7.8-64 선택  

 

 

5. 서버 설정 탭에서 Free Tier 서버에 맞게 설정 후 다음

  - 본 이미지는 Micro 타입 서버를 이미 1개 생성해서 하나 더 생성할 수 없어서 Compact 타입으로 설정 후 진행하였습니다.

  - SSD 서버는 Micro 타입 서버를 지원하지 않습니다.

 

 

6. 인증키 설정에서 서버에 접속할 관리자 비밀번호를 생성합니다.

  - 항상 인증키는 안전한 곳에 저장!

 

 

7. 네트워크 접근 설정은 생성 할 서버에 대한 방화벽 설정이라고 생각하시면 될 것 같습니다. 

 

 

8. ACG 설정에서 접근 소스는 접속에 허용될 ip 대역을 의미합니다.

  - 웹 서비스를 접근할 8080 포트를 허용합니다.

  - 서버 ssh에 접근되는 22 포트를 허용합니다. (서버 접근은 myip로 하여 보안을 강화하는 게 좋습니다.)

 

 

9. 이제 생성된 서버에 접근해보도록 하겠습니다.

  ssh에 접근에 많이 사용되는 tool인 putty를 이용해 보도록 하겠습니다.

  ncp에 새로 생성된 서버를 클릭해 보시면 포트 포워딩 정보에 서버 접속용 공인 ip와 외부 포트가 있습니다.

  해당 정보를 아래 위치에 작성하고 Open!

  [MacOS putty 참고 블로그]

   - https://velog.io/@wlgus2134/MAC-PUTTY-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0

 

putty

10. 리눅스 관리자 계정은 root이고, password는 위에서 입력한 관리자 비밀번호로 접속이 가능합니다!

 

 

NCP 클라우드 플랫폼을 이용해서 아주 간편하게 Web Server를 구동시킬 수 있는 서버 한 대가 생성되었습니다!

공인 ip를 발급받아야지 저희가 구동시킨 Web Server에 접근할 수 있습니다.

다음 Step에서 Application를 개발하고 진행하도록 하겠습니다.

 

 

728x90
반응형
반응형

프로토타입 패턴(Prototype Pattern)

  - 프로토타입 패턴은 생성패턴(Creational Pattern) 중 하나이다.
  - 생성 패턴은 인스턴스를 만드는 절차를 추상화하는 패턴이다.
  - 생성 패턴에 속하는 패턴들은 객체를 생성, 합성하는 방법이나 객체의 표현방법을 시스템과 분리해준다.

  - 기존 인스턴스를 복제하여 새로운 인스턴스를 만드는 방법이다.

  - 프로토타입 패턴은 원형이 되는 인스턴스를 사용해 새롭게 생성할 객체의 종류를 명시하여 새로운 객체가 생성될 시점에 인스턴스의 타입이 결정되도록 하는 패턴입니다

  - 생성하고자 하는 객체의 클래스에서 Cloneable의 clone() 메서드를 재정의되어야 한다.

 

장점

  - 구현 클래스에 직접 연결하지 않고 객체를 복사할 수 있습니다.(새 인스턴스를 만드는 것보다 비용적인 면에서 효율적일 수 있다.)

  - 복잡한 객체를 만드는 과정을 숨길 수 있다.

  - 추상적인 타입을 리턴할 수 있다.

단점

  - 복제한 객체를 만드는 과정 자체가 복잡할 수 있다.(특히, 순환 참조가 있는 경우)

코드

 - Mountain.class

package com.bumblebee.designpattern.creational.prototype;

import java.util.ArrayList;
import java.util.List;

public class Mountain implements Cloneable{

    private List<String> mountainList;

    public Mountain() {
        this.mountainList = new ArrayList<>();
    }

    public Mountain(List<String> mountainList) {
        this.mountainList = mountainList;
    }

    public List<String> getMountainList() {
        return mountainList;
    }

    public void mountainListAll() {
        this.mountainList.add("구룡산(306M)");
        this.mountainList.add("북악산(342M)");
        this.mountainList.add("아차산(295M)");
        this.mountainList.add("응봉산(95M)");
        this.mountainList.add("서대문 안산(295M)");
        this.mountainList.add("용마산(348M)");
        this.mountainList.add("인왕산(339M)");
        this.mountainList.add("남산(279M)");
        this.mountainList.add("불암산(509M)");
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
    	//return super.clone(); 얕은 복사(shallow copy)
        return new Mountain(new ArrayList<>(this.mountainList)); //깊은 복사(Deep Copy)
    }
}

 

  - MountainTest.class

  - Cloneable 인터페이스를 구현하여 Mountain 클래스를 생성하였고 clone() 메소드를 통해 깊은 복사 방식으로 인스턴스를 복제 하였습니다. java에서는 기본으로 얕은 복사를 제공한다.

package com.bumblebee.designpattern.creational.prototype;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
class MountainTest {

    @Test
    void prototypePattern() throws CloneNotSupportedException {

        Mountain mountain = new Mountain();
        mountain.mountainListAll();

        Mountain seoulMountain = (Mountain) mountain.clone();
        Mountain seoulMountain2 = (Mountain) mountain.clone();
        List<String> mountainList = seoulMountain.getMountainList();
        List<String> mountainList2 = seoulMountain2.getMountainList();

        mountainList.add("관악산(632M)");
        mountainList2.remove("북악산(342M)");

        System.out.println(mountain.getMountainList());
        System.out.println(mountainList);
        System.out.println(mountainList2);

    }

}

 

  - 결과

 

정리

 - DB에 접근해서 데이터를 핸들링하는 비용이 크므로 매번 DB에 접근이 필요하지 않는 데이터라면 프로토타입 패턴을 이용해서 객체를 복사해서 사용하는 방법이 유용할 것 같다.

728x90
반응형
반응형

프록시 패턴(Proxy Pattern)

  - Proxy는 대리자, 대변인 이라는 뜻이다. 

  - 프록시 패턴은 구조패턴(Structural Pattern) 중 하나이다.
  - 구조 패턴은 작은 클래스들을 상속과 합성을 이용하여 더 큰 클래스를 생성하는 방법을 제공하는 패턴이다.

  - 인터페이스나 구현을 복합하는 것이 아니라 객체를 합성하는 방법을 제공한다.

    이는 컴파일 단계에서가 아닌 런타임 단계에서 복합 방법이나 대상을 변경할 수 있다는 점에서 유연성을 갖는다.

 

프록시의 주요 기능

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

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

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

 

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

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

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

 

프록시 패턴의 장점

  - 제어의 흐름을 변경하거나 다른 로직을 수행하기 위해 사용한다.

  - 객체에 대하여 접근할 때에 Wrapper Class를 두어 접근에 대한 통제를 위해 사용된다.

 

코드

  * 더하기 빼기 계산기 로직을 구현 예제 (프록시 패턴을 이용해서 계산 시간을 출력)

 

  - 계산기 interface

 

public interface Calculator {

    public int plus(int left, int right);
    public int subtract(int left, int right);

}

 

  - 계산기 interface 구현 service

 

public class CalculatorService implements Calculator{

    private int result;

    @Override
    public int plus(int left, int right) {
        result = left + right;
        return result;
    }

    @Override
    public int subtract(int left, int right) {
        result = left - right;
        return result;
    }
}

 

  - 프록시 패턴을 사용하지 않은 테스트

 

@SpringBootTest
class CalculatorServiceTest {

    @Test
    void calculatorService() {

        Calculator calculatorService = new CalculatorService();

        int left = 10000;
        int right = 5000;

        int plusResult = calculatorService.plus(left, right);
        int subtractResult = calculatorService.subtract(left, right);

        assertEquals(plusResult, left+right);
        assertEquals(subtractResult, left-right);

    }

}

 

  - 프록시 패턴 클래스

 

public class CalculatorServiceProxy implements Calculator{

    private int result;

    @Override
    public int plus(int left, int right) {
        long beforeTime = System.currentTimeMillis();

        result = left + right;
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        long afterTime = System.currentTimeMillis();
        long secDiffTime = (afterTime - beforeTime)/1000;
        System.out.println(" plus 계산 시간(m) : "+secDiffTime);

        return result;
    }

    @Override
    public int subtract(int left, int right) {
        long beforeTime = System.currentTimeMillis();

        result = left - right;
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        long afterTime = System.currentTimeMillis();
        long secDiffTime = (afterTime - beforeTime)/1000;
        System.out.println("subtract 계산 시간(m) : "+secDiffTime);

        return result;
    }
}

 

- 프록시 패턴을 사용한 테스트

 

@SpringBootTest
class CalculatorServiceTest {

    @Test
    void calculatorServiceProxy() {

        Calculator calculatorServiceProxy = new CalculatorServiceProxy();

        int left = 10000;
        int right = 5000;

        int plusResult = calculatorServiceProxy.plus(left, right);
        int subtractResult = calculatorServiceProxy.subtract(left, right);

        assertEquals(plusResult, left+right);
        assertEquals(subtractResult, left-right);

    }


}

 

결과 : plus 계산 시간(m) : 1
        subtract 계산 시간(m) : 2

 

 

정리

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

 - 테스트 코드를 보면 생성 객체만 바꿈으로서 Calculator interface는 영향을 받지 않게 Proxy 클래스를 통해서 원하는 목적에 맞게 흐름을 조정할 수 있었다. 해당 패턴은 Spring 프레임워크에 AOP 동작원리에 사용되어지고 있다.

 * 중요한 점은 흐름제어만 할 뿐 결과값을 조작하거나 변경시키면 안된다.

 

참조 

 - https://readystory.tistory.com/132?category=822867

728x90
반응형

+ Recent posts