스프링부트는 내장 웹 서버로 톰캣이 자동 설정되어있다.
spring-boot-starter-web이 톰캣을 가져온다.
톰캣은 아래와 같이 직접 구현하여 실행시킬 수도 있다. (대부분은 스프링부트로 바로 실행시킬 것이다..)
public class Application {
public static void main(String[] args) throws LifecycleException {
// SpringApplication.run(Application.class, args);
// 1 Tomcat 객체 생성
Tomcat tomcat = new Tomcat();
// 2 포트 설정, 커넥터 연결
tomcat.setPort(8080);
tomcat.getConnector();
// 3 컨텍스트 추가
Context context = tomcat.addContext("/", "/");
// 4 서블릿 생성 (웹 페이지)
HttpServlet servlet = new HttpServlet() {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter writer = resp.getWriter();
writer.println("<html><head><title>");
writer.println("My Tomcat Server");
writer.println("</title></head>");
writer.println("<body><p>Hello Tomcat</p></body>");
writer.println("</html>");
}
};
// 5 톰캣에 서블릿 추가
String servletName = "helloServlet";
tomcat.addServlet("/", servletName, servlet);
// 6 컨텍스트에 서블릿 매핑 (url 에 해당 서블릿 매핑)
context.addServletMappingDecoded("/hello", servletName);
// 7 톰캣 실행 및 서버가동 유지
tomcat.start();
tomcat.getServer().await();
}
}
스프링부트는 위 일련의 과정을 상세하고 유연하게 자동설정해준다.
ServletWebServerFactoryAutoConfiguration
은 서블릿 웹 서버를 생성하고, 여기서 TomcatServletWebServerFactoryCustomizer
를 통해 서버를 커스터마이징 한다. (1 ~ 2 과정)
또한 DispatcherServletAutoConfiguration
에서 서블릿을 만들고 등록한다. (3 ~ 6 과정)
컨테이너, 서버 포트
tomcat 대신 jetty, undertow, netty 등의 다른 웹서버로 바꿀 수 있다. (단, netty 는 webflux)
메이븐에서 exclusion 태그에 tomcat 을 담아 톰캣을 제외시키고, 다른 디펜던시로 (예를들면) undertow 로 교체할 수 있다.
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
또한 간단한 프로퍼티 등록으로 다양한 웹서버 기능을 사용할 수 있다.
application.properties
# 스프링부트 실행 시 웹애플레키이션을 실행시키지 않음.
spring.main.web-application-type=none
# 포트번호를 지정
server.port=7070
# 포트번호를 임의로 지정 (Random Port)
server.port=0
또한 프로퍼티 파일말고도, 빈 설정을 통해 포트 정보를 확인하고 설정할 수 있다.
ApplicationListener<ServletWebServerInitializedEvent>
의 구현체를 만들고 메소드를 이용하면 된다.
@Component
public class PortListener implements ApplicationListener<ServletWebServerInitializedEvent> {
@Override
public void onApplicationEvent(ServletWebServerInitializedEvent servletWebServerInitializedEvent) {
ServletWebServerApplicationContext applicationContext = servletWebServerInitializedEvent.getApplicationContext();
int port = applicationContext.getWebServer().getPort();
System.out.println(port);
}
}
HTTP, HTTP2
https 서버 접근
스프링부트에서 웹서버를 실행할 때 localhost:8080 으로 보통 실행시킨다.
여기서 https 를 사용하도록 해보자.
우선 로컬에서 키스토어(인증서) 를 하나 만들자.
keytool -genkey -alias tomcat -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -validity 4000
그리고 프로퍼티 설정에 방금 만들어준 키스토어 정보를 입력해준다. 그러면 스프링부트는 이 속성을 읽어서 https 인증서를 브라우저에게 전송할 것이다.
application.properties
server.ssl.key-store=keystore.p12
server.ssl.key-store-password=123456
server.ssl.keyStoreType=PKCS12
server.ssl.keyAlias=tomcat
server.port=8443
server.http2.enabled=true
일반적인 인증기관에서 발급하는 pub key는 대부분의 브라우저가 알고 있다.
하지만 로컬에서 인증서를 만들면 브라우저는 무슨 인증서인지 알지 못한다. 그래서 브라우저 주소창에 url을 치면 https 이지만 인증서를 모르기 때문에 접근할 지 되묻는다.
(크롬 브라우저 기준) 밑에 고급을 눌러서 localhost(안전하지 않음)로 이동을 눌러주면 된다.
혹시 그런 링크가 없을 시에는 브라우저를 다시 시작하고, 오른쪽 세로 점 3개 아이콘 클릭 > 설정 > 안전확인 > 보안 > 인증서 관리 > 인증서 이름 검색 > 신뢰 > 이 인증서 사용 시 "항상 신뢰" 로 변경해 준다. (mac 기준)
이제 웹사이트에 접속된 것이 보인다. 물론 코딩해놓은 것이 없어서 Whitelabel Error Page 가 보일 것이다. 하지만 서버는 연결된 것이다.
curl 명령어로 콘솔에서 서버 정보를 받아올 수 도 있다.
$ curl -I -k https://localhost:8443/
curl 명령어 옵션
-k
: https 사이트를 SSL certificate 검증 없이 연결한다.-I
: Information 으로 HTTP 응답 유형, 결과, content-type, content-length, Date 를 출력한다.
새로운 커넥터 활성화
프로퍼티 파일에 https 설정을 했는데, http 서버도 다른 포트로 열고 싶다면, 아래처럼 코딩을 해서 http 커넥터를 만들 수 있다.
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
public ServletWebServerFactory serverFactory() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
tomcat.addAdditionalTomcatConnectors(createStandardConnector());
return tomcat;
}
private Connector createStandardConnector() {
Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
connector.setPort(8080);
return connector;
}
}
이렇게 하고 애플리케이션을 실행시키면, 포트 8443 에서는 https 서버가, 포트 8080에서는 http 서버가 열린 것이 보일 것이다.
HTTPS2 활성화
application.properties
# http2 활성화 추가
server.http2.enabled=true
이 조건만 추가하면 http2 통신도 사용할 수 있다.
$ curl -I -k https://localhost:8443/
>> HTTP/2 404
>> ...
실행가능한 jar 파일
애플리케이션을 실행시킬 때 주로 사용하는 메이븐 명령어이다.
# target 폴더 및 하위 파일 모두 삭제
$ mvn clean
# target 폴더 생성, jar 파일 생성
$ mvn package
# maven 라이프사이클 중 테스트 건너뛰기(시간단축)
$ mvn package -DskipTests
# 스프링부트 실행
$ java -jar target/springgoman-0.0.1-SNAPSHOT.jar
mvn package
명령 실행 시 jar 하나를 만들어 주는데, 이 파일 하나로 스프링부트를 실행할 수 있다.
spring-boot-maven-plugin 은 스프링부트 프로젝트를 패키징해준다. (pom.xml 설정파일에 의존성이 추가되어 있다.)
자바에는 내장 jar 를 로딩하는 표준적 방법은 없다. 따라서 같은 이름의 파일은 애플리케이션 클래스와 라이브러리의 경로를 구분한다.org.springframework.boot.loader.jar.JarFile
은 내장 jar를 읽고 org.springframework.boot.loader.Launcher
가 어플리케이션을 실행시킨다.
'Java, Kotlin, Spring > Spring, Spring Boot' 카테고리의 다른 글
Springboot - 외부설정, 프로파일 (6) | 2021.01.16 |
---|---|
Springboot - SpringApplication (4) | 2021.01.15 |
Springboot 자동설정(AutoConfiguration) (2) | 2021.01.14 |
Springboot 프로젝트 생성, 이니셜라이져 (2) | 2021.01.14 |
Spring - null-safety (3) | 2021.01.13 |
댓글