Spring/Spring Boot

[Spring Boot] 토비의 스프링 부트 강의 - 독립 실행형 서블릿 애플리케이션

미소서식지 2023. 6. 30. 08:07

HTTP Request and Response

반드시 머리 속에 잘 담고 있어야 함

웹의 표준 프로토콜을 통해 요청이 어떻게 들어가고 응답이 오는지

어떻게 구성되어 있는지

어떤 요청을 받아서 이렇게 메소드에 전달해주는구나 매핑하는데 이렇게 사용하네 어떻게 응답이 만들어지네

이런 걸 잘 알고 있어야 함!!

바디가 되는 건지, 헤더가 되는 건지, 응답 코드가 되는 건지, 또 다른 작업을 하는 건지 잘 분간 못할 수도 있음

평범한 자바 메소드의 요청과 어떻게 매핑하고 응답하는지 잘 알아야 함

요청과 응답이라는 관점에서 이렇게 연결되는구나 빠르게 떠올라야!

새로운 기술을 볼 때도 요청 & 응답 어떻게 가져오지? 빠르게 생각해야 함!

Request

  • Request Line : Method, Path, HTTP Version
  • Headers
  • Message Body

Response

  • Status Line : HTTP Version, Status Code, Status Text
  • Headers : Content Type (of Body)
  • Message Body

 

Containerless Application

StandAlone Program이 Servlet Container의 역할 대체하도록 만들기

StandAlone Program이 Servlet Container 띄우고 이게 Bean을 띄우도록 하는 것

 

 

Tomcat (aka. Java Servlet Container)

Tomcat을 임베드 해서 띄울 수 있도록 하는 것 == 내장형 Tomcat

Spring Initialzr 에도 내장형 Tomcat이 들어가있음

 

WebServer

Spring Boot가 Tomcat 외의 컨테이너를 모두 일관된 방식으로 동작하도록 추상화를 해놔서 그러함

 

public class HellobootApplication {

	public static void main(String[] args) {
		ServletWebServerFactory serverFactory = new TomcatServletWebServerFactory();
		WebServer webServer = serverFactory.getWebServer();
		// Tomcat Servlet Container 동작
		webServer.start();
	}

}

톰캣 서버 띄우는 코드

 

톰캣 서버 동작 (embedded tomcat)

 

Servlet 등록

Servlet Container (Tomcat) 에 띄우는 Web Component가 Servlet

 

public class HellobootApplication {

	public static void main(String[] args) {
		ServletWebServerFactory serverFactory = new TomcatServletWebServerFactory();
		WebServer webServer = serverFactory.getWebServer(servletContext -> {
			servletContext.addServlet("hello", new HttpServlet() {

				@Override
				protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
					resp.setStatus(200);
					resp.setHeader("Content-Type", "text/plain");
					resp.getWriter().print("Hello Servlet");
				}
			}).addMapping("/hello");
		});
		// Tomcat Servlet Container 동작
		webServer.start();
	}

}

 

Servlet 등록

 

 

익명 Class

프로그램 내에서 별로 재사용될 일이 없는 객체일 경우

익명, 이름이 없다는 것은 별로 기억되지 않아도 된다는 것이며, 나중에 다시 불러질 이유가 없다는 뜻을 내포한다. 

즉, 프로그램에서 일시적으로 한번만 사용되고 버려지는 객체라고 보면 된다. (일회용 클래스)

 

익명 클래스는 클래스 정의와 동시에 객체를 생성할 수 있다.

따로 클래스 정의 없이 메소드 내에서 바로 클래스를 생성해 인스턴스화 할 수 있으며, 이렇게 클래스의 선언과 객체의 생성을 동시에 하기 때문에 단 한 번만 사용될 수 있고, 익명으로 정의된 클래스는 일회용으로써 사용되고 버려진다.

그래서 만일 어느 메소드에서 부모 클래스의 자원을 상속받아 재정의하여 사용할 자식 클래스가 한번만 사용되고 버려질 자료형이면, 굳이 상단에 클래스를 정의하기보다는, 지역 변수처럼 익명 클래스로 정의하고 스택이 끝나면 삭제되도록 하는 것이 유지보수면에서나 프로그램 메모리면에서나 이점을 얻을 수 있다.

 

// 부모 클래스
class Animal {
    public String bark() {
        return "동물이 웁니다";
    }
}

public class Main {
    public static void main(String[] args) {
        // 익명 클래스 : 클래스 정의와 객체화를 동시에. 일회성으로 사용
        Animal dog = new Animal() {
        	@Override
            public String bark() {
                return "개가 짖습니다";
            }
        }; // 단 익명 클래스는 끝에 세미콜론을 반드시 붙여 주어야 한다.
        	
        // 익명 클래스 객체 사용
        dog.bark();
    }
}

 

Objects.requireNonNull

 @ForceInline
public static <T> T requireNonNull(T obj) {
    if (obj == null)
        throw new NullPointerException();
    return obj;
}

파라미터로 입력된 값이 null 이라면 NPE(NullPointerException)가 발생하고, 그렇지 않다면 입력값을 그대로 반환하는 간단한 메소드이다. 

 

requireNonNull을 사용하는 이유

null 을 참조하여 예외가 발생하나, requireNonNull 에 null 이 들어가나 똑같이 NPE가 발생하는 것은 마찬가지 일텐데, 그렇다면 대체 왜 requireNonNull 을 사용하는 것 일까?

그 이유는 바로 빠른 실패 (Fail-Fast) 이다. 디버깅을 쉽게 하기 위해서는 문제가 발생한 경우 즉각적으로 감지할 필요가 있다. 문제의 원인과 문제의 발생 지점이 물리적으로 멀리 떨어져 있다면 디버깅하기 힘들 것이다. 

 

또한 널 체크 시 가독성 때문에 requireNonNull을 사용한다.

 

https://hudi.blog/java-requirenonnull/

 

Bean으로 등록

class만 가능?

interface는 안되나?

 

Template Method pattern

 

Spring Boot 특징

@annotation 등을 활용하여 스프링 빈 관리 및 스프링 컨테이너 실행 등을 해준다.

항상 하드 코딩한 방식보다는 유연화된 방식으로 개발하는 것을 선호하는 것 같다.

추상화를 많이 이용한다. = 즉 의존성을 주입할 때도 그냥 클래스 자체의 객체를 생성해서 의존성을 주입하는 것이 아니라, 그것의 추상화된 버전인 인터페이스를 형성해서 주입해준다. 그래서 소스코드의 변경을 최소화한다.

요새는 array를 만들어서 쓰기보단 Collection을 만들어서 쓴다.

 

IntelliJ Shortcuts

introduce local variable(자동 변수생성)  : command + option + v

System.out.println() : sout

Generate getter & setter : command + n

블럭 선택 : shift + option 

한줄 선택 : shift + command

블럭마다 옮겨다니기 : option

한 줄 이동 : shift + command + 위/아래

한 줄 삭제 : cmd + delete

매개변수 보기 : cmd + p

quick documentation : fn + f1

context actions : option + enter (lambda 등으로 변환 가능)

override method : control + o

refactoring : ^T

search everywhere : shift + shift

add static import for '~' : option + enter

type hierarchy : ^H

 

두 번째 탭으로 들어가면 구현하고 있는 Super Class들 볼 수 있음