분류 전체보기

VS Code(Remote SSH)

2023. 2. 5. 21:07
728x90

VS Code의 Remote SSH사용하는 이유

Local Machine에서 개발 가능하지만 Server 개발일경우 원격으로 개발을 해야하는 경우가 있을수있다. 이럴떈 Local에서 개발을 한후 Server로 이동시켜야한다.

사용하는 Local Machine이 windows인 반면 개발해야하는 환경이 Linux라면 Linux Machine에 접속하여 개발을해야한다.

결론-> VSCode의 Remote Development Extension을 사용하면 Remote Machine을 Local Machine 처럼 생각될수있게 개발하는것이 가능하다.


또한 EC2 를 사용하여 AWS 배포를 할때, VsCode 를 사용하여 SSH 연결을 한다면, EC2 즉 서버에 배포한 코드를 조금더 빠르게 수정하고 테스트 해볼수있다.


위 그림처럼 Local OS에서 VSCode로 작업한 것을 SSH Tunnel을 통해 Remote Machine으로 보내는 형태로 작업을 진행할것이다.
(SSH 외 Containers 또는 WSL을 사용하여 개발을 할수있지만 요번 글은 SSH를 사용해보도록 하겠다)




VS Code에서 SSH를 통한 원격 개발 과정

  1. VSCode의 확장탭에서 Remote Development를 검색하고 설치한다.



  2. F1키를 눌러 >Remote-SSH:... 를 클릭한다.



  1. 클릭후 UserId@host(ip)를 입력해준다.
    ex) 필자 같은경우는 (리눅스 UserId= chanyoun) 따라서 -> chanyoun@ip를 입력했다.



  2. 그후 Select SSH configuration file to update 라는 text가 보인다. 여기서 우리가 Config File을 저장할 위치를 설정해줘야하는데
    C:\Users\<본인의 윈도우 계정 아이디>\.ssh\<설정파일이름> 식으로 경로를 지정하면된다.



  3. 경로를 지정하게되면 VSCode에서 Host added! 라는 알림창이 뜨게되며, Host가 추가될것이다.



  4. 그후 다시 F1키를 눌러 >Remote-SSH를 입력하면 전에는 보이지않았던 host가 보이게되고 클릭하면 아래와같은 새로운 VSCode 창이 뜨게된다.



  5. 이후 팔레트 창에 (필자는 Linux사용) 설정해준 Linux hostid에대한 비밀번호를 입력하면
    아래 사진처럼 왼쪽하단에 SSH-IP 형태로 연결이된다!.



  6. 마지막으로 ctrl+o를 이용해 원하는 디렉토리에서 작업을 할수있게 된다.




확인 테스트

Virtualbox를 통해 Linux를 실행시킨후 Linux의 cs16디렉토리에있는 main.java코드를 수정한다.

Linux에서 수정하면 -> VSCode로 업데이트가 잘되는지
VSCode에서 코드 수정시 Linux에서 코드가 업데이트 되는지 확인한다.


  1. 현재 main.java의 상태



  2. Linux에서 코드를 수정할때 VSCode에서 업데이트 되는지 확인한다.



    Linux에서 코드 추가후 저장을 누르면 자동적으로 VSCode에도 주석이 추가되는것을 볼수있다.



  3. VSCode에서 코드 수정시 Linux에서 코드가 업데이트 되는지 확인한다.

    주석추가 후 저장




    이번에도 VSCode에서 추가한 주석이 Linux에도 자동적으로 추가가 되는것을 알수있다.

728x90

'CS' 카테고리의 다른 글

CS) 객체지향(OOP)  (0) 2023.02.08
CS) Virtual Memory  (0) 2023.02.08
CS) Byte padding  (0) 2023.02.08
CS) 프로세스 메모리 구조  (0) 2023.02.08
CS) CPU구조와 동작과정  (0) 2023.02.08
728x90

Spring을 사용하는 이유

DIP 를 위반하는 간단한 예시

class LightBulb {
    void turnOn() {
        System.out.println("LightBulb: Bulb turned on...");
    }

    void turnOff() {
        System.out.println("LightBulb: Bulb turned off...");
    }
}

class Switch {
    private LightBulb lightBulb;

    public Switch() {
        this.lightBulb = new LightBulb();
    }

    void operate() {
        // ... some logic ...
        lightBulb.turnOn();
        // ... some logic ...
    }
}

위와 같은 예가 있다 가정한다. 위 예는 DIP(Dependency Inversion Principle) 를 위배한다. 그이유는 Switch 클래스가 LightBulb 라는 구체 클래스에 의존하기 때문이다. 이렇게되면 만약 lightBulb 가아닌 다른 빛을 내는 기기의 의존성을 주입받기 위해선 Switch 클래스를 수정해야한다.


이런 상황을 해결하기위해선

아래와같이 LightBulb 가 인터페이스를 상속받게 하며, Switch 클래스는 생성자를 통해 인터페이스 의존성을 주입받으면 된다.

interface SwitchableDevice {
    void turnOn();
    void turnOff();
}

class LightBulb implements SwitchableDevice {
    @Override
    public void turnOn() {
        System.out.println("LightBulb: Bulb turned on...");
    }

    @Override
    public void turnOff() {
        System.out.println("LightBulb: Bulb turned off...");
    }
}

class Switch {
    private SwitchableDevice device;

    public Switch(LightBulb lightBulb) {
        this.device = lightBulb;
    }

    void operate() {
        // ... some logic ...
        device.turnOn();
        // ... some logic ...
    }
}

위처럼 Switch 는 인터페이스인 SwitchableDevice 를 의존한다. 하지만 아직 문제가 있다. 아직도 LightBulb 외 다른 빛을 내는 기기의 의존성을 주입받기 위해서는 Switch 클래스의 생성자에 수정이 필요하다. 이럴땐 Switch 클래스의 생성자의 파라미터에 LightBulb 가 아닌 SwitchableDevice 를 넘겨주면 된다.


interface SwitchableDevice {
    void turnOn();
    void turnOff();
}

class LightBulb implements SwitchableDevice {
    @Override
    public void turnOn() {
        System.out.println("LightBulb: Bulb turned on...");
    }

    @Override
    public void turnOff() {
        System.out.println("LightBulb: Bulb turned off...");
    }
}

class Switch {
    private SwitchableDevice device;

    public Switch(SwitchableDevice device) {
        this.device = device;
    }

    void operate() {
        // ... some logic ...
        device.turnOn();
        // ... some logic ...
    }
}

class AppConfig {
    Switch configureSwitch() {
        return new Switch(new LightBulb());
    }
}

이렇게하면 이제 Switch 의 빛을 내는 기기를 바꾸고 싶을때 더이상 Switch 클래스를 건드리지 않아도 된다. 즉 AppConfig 라는 클래스에 우리가 사용하고 싶은 구체 클래스를 지정만 해주면 우리는 원하는 Switch 를 얻을수 있게 된다.



Spring 을 사용하는 이유는 다음과 같다.

  1. JAVA를 통해 코드를 짤때 객체를 구현하는 클래스를 Ex)AppConfig 처럼 다른 클래스로 분리해서 코드를 짜야한다. 그렇지 않으면 DIP(의존관계 역전 원칙)원칙 즉 하나의 클래스가 추상클래스와 구체클래스에 동시에 의존할수 있기때문이다.

    • 즉 DIP 의 핵심은 추상화에 의존을 해야한다는 것이다.
  2. 또한 AppConfig처럼 객체를 구현하는 클래스를 따로 분리하는순간 OCP원칙(소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다)에 의하여 우리가 소프트웨어 요소를 새롭게 확장해도 사용영역의 변경은 닫혀있으면서 AppConfig (구성영역)의 코드만 수정하면 되기때문에 OCP원칙도 지킬수 있게된다.

  3. 마지막으로 AppConfig를 통해 객체를 생성하고 연결하는 역활을 담당하게하고, 클라이언트 객체는 실행에 대한 책임만을 지게 함으로서 SRP(단일 책임 원칙)을 지킬수있다.

  4. 위 이유들 때문에 AppConfig처럼 구현객체를 생성하며 연결하는 클래스를 따로 구현한다. AppConfig처럼 객체를 생성하고 관리하면서 의존관계를 연결해 주는 것을 IoC컨테이너 또는 DI컨테이너라 한다.

  5. 기존에는 AppConfig를 사용해 직접 객체를 생성 및 의존관계를 주입했지만, 스프링 컨테이너를 사용해 위과정을 자동화 할수있다.!!!!



Container 생성, Bean등록

Spring Container에서는 @Configuration이 붙은 AppConfig를 설정(구성)정보로 사용한다. 이때 @Bean이라 적힌 메서드를 모두 호출해서 반환된 객체를 스프링 컨테이너에 등록한다. 이렇게 스프링 컨테이너에 등록된 객체를 스프링 빈이라 한다.

 @Configuration
 public class AppConfig {

    @Bean
     public MemberService memberService() {
         return new MemberServiceImpl(memberRepository());
     }

   ...
 }

@Configuration에 의해 AppConfig을 구성정보로 사용한다는 의미이며, @Bean이라 적힌 memberService()에 의해 반환된 객체를 스프링 컨테이너에 등록한다. 이렇게 스프링 컨테이너에 등록된 객체를 스프링 빈이라 하며, 스프링 빈의 이름은 메서드의 명 (memberService)를 사용한다.



SpringContainer 에서 Bean 가져오는 방법

스프링을 사용함으로서 필요한 객체를 AppConfig에서 조회하는게 아닌 스프링 컨테이너에 등록된 스프링빈(객체)을 조회한다. 이때 스프링빈은 applicationContext.getBean()메서드를 통해 찾을수 있다.

ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
 MemberService memberService = applicationContext.getBean("memberService", MemberService.class);

ApplicationContext을 통해 AppConfig안에 있는 환경설정 정보를 가지고 스프링 컨테이너를 만들어준다.

applicationContext.getBean("memberService", MemberService.class);을 통해 bean을 가져온다.

getBean("메서드이름",타입) 형식을 맞춰 입력해주면 된다.



Spring Container

Spring Container을 만드는 2가지 방법이존재한다.

  • XML을 기반으로 만들수있으며
  • 애노테이션 기반의 자바 설정 클래스로 만들수있다.(우리가 위에서 했던 방식)
  • 위 사진처럼 Spring Container에 Spring Bean이 어떻게 저장되는지 알수있다.
  • Bean의 이름은 메서드이 이름, 빈 객체는 메서드의 return 객체가 되는것을 알수있다.

🙏Reference

  • [김영한님 Spring 강의
728x90

'Spring' 카테고리의 다른 글

[SPRING] Bean Scope  (0) 2023.03.05
[SPRING] Bean Life cycle, call back  (0) 2023.03.05
[SPRING] 의존관계 자동 주입  (1) 2023.03.05
[SPRING] Component scan  (0) 2023.03.03
[SPRING] Singleton  (0) 2023.02.26

Java) Java-collection queue

2022. 11. 15. 13:42
728x90

queue = FIFO (First-In-First-out)  구조  

Enqueue = 큐 맨뒤에 데이터가 추가된다.

Dequeue = 큐 맨앞에 데이터가 삭제된다.

java에서 queue를 구현하기위해서는 LinkedList를 사용해 구현한다. 

 

return Method
boolean add(E e)
Inserts the specified element into this queue if it is possible to do so immediately without violating capacity restrictions, returning true upon success and throwing an IllegalStateException if no space is currently available.
E element()
Retrieves, but does not remove, the head of this queue.
boolean offer(E e)
Inserts the specified element into this queue if it is possible to do so immediately without violating capacity restrictions.
E peek()
Retrieves, but does not remove, the head of this queue, or returns null if this queue is empty.
E poll()
Retrieves and removes the head of this queue, or returns null if this queue is empty.
E remove()
Retrieves and removes the head of this queue.

 

add와 offer은 queue에 값을 추가해준다는것은 동일하지만  add는 큐가 꽉차 더이상 값을 추가할수없을때 예외를 발생시키지만 offer는 추가실패를 의미하기위해 false를 return한다. 

poll() 과 remove도 마찬가지이다. poll()은 더이상 뺄 값이없을때 null을 return하지만 remove는 예외를 발생시킨다. (아래예시)

import java.io.IOException;
import java.util.LinkedList;
import java.util.Queue;
 
public class Main {
    
    public static void main(String[] args) throws IOException {
        Queue<Integer> queue = new LinkedList<Integer>();

        queue.add(1);
        queue.offer(2);

        System.out.println(queue.remove());
        System.out.println(queue.remove());
        System.out.println(queue.poll()); // null 리턴
        System.out.println(queue.remove()); // 예외발생
        
        
       
    }
}

poll() -> null, remove -> 예외

peek() = 가장 앞에있는 값을 가리킨다. 이때도 peek()은 queue가 비어있으면 null 리턴

element() = queue가 비어있으면 예외 발생

public class Main {
    
    public static void main(String[] args) throws IOException {
        Queue<Integer> queue = new LinkedList<Integer>();

        queue.add(1);
        queue.offer(2);

        System.out.println(queue.peek()); // -> 1
        System.out.println(queue.element()); // -> 1
        
    }
}
public class Main {
    
    public static void main(String[] args) throws IOException {
        Queue<Integer> queue = new LinkedList<Integer>();

        System.out.println(queue.peek());
        System.out.println(queue.element());
            
    }
}

peek() -> null, element() -> 예외

 

728x90

+ Recent posts