올해 1월에 만들어놓고... 요 근래에 들어서 속도를 올리는 중이다. 

이제 1.3.0 버전이 나올 예정인데... 번역은 더디기만 하다.

10월말까지 해서 번역을 완료하고, 1.3.0.BUILD-SNAPSHOT 보고 업글하여 연말에는 번역을 마치는 것을 목표로 하고 있다.

구글번역기, 다음사전 을 애용중...

스프링부트가 가지고 있는 강력한 기능 중 하나가, 바로 액츄에이터 이다. 그 중에서 내가 지금까지 몰랐던 Remote Shell에 대한 기능을 살펴본다. 리모트쉘은 별다른 코딩을 하지 않아도 사용이 가능하다.

리모트쉘의 의존성은 다음과 같다.

dependencies {
    compile("org.springframework.boot:spring-boot-starter-security")
    compile("org.springframework.boot:spring-boot-starter-remote-shell")
    // 생략
}

org.springframework.boot:spring-boot-starter-security 을 추가하지 않으면 다음 클래과 같은 예외가 발생하며 실패한다.

Caused by: java.lang.ClassNotFoundException: org.springframework.security.config.http.SessionCreationPolicy
    at java.net.URLClassLoader$1.run(URLClassLoader.java:372)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 42 more
:bootRun FAILED

SSH와 관련해서 필요한 것으로 보인다. 리모트쉘의 기본포트는 2000번이다. 이 부분은 다음에 있는 설정코드에서 수정가능하다. 리모트쉘에서 사용하는 속성은 다음과 같다. 자세한 내용은 레퍼런스 문서를 살펴보기 바란다.

# REMOTE SHELL
shell.auth=simple # jaas, key, simple, spring
shell.command-refresh-interval=-1
shell.command-path-patterns= # classpath*:/commands/**, classpath*:/crash/commands/**
shell.config-path-patterns= # classpath*:/crash/*
shell.disabled-commands=jpa*,jdbc*,jndi* # comma-separated list of commands to disable
shell.disabled-plugins=false # don't expose plugins
shell.ssh.enabled= # ssh settings ...
shell.ssh.key-path=
shell.ssh.port=
shell.telnet.enabled= # telnet settings ...
shell.telnet.port=
shell.auth.jaas.domain= # authentication settings ...
shell.auth.key.path=
shell.auth.simple.user.name=
shell.auth.simple.user.password=
shell.auth.spring.roles=

내가 테스트를 위해 설정한 속성은 다음과 같다. application.yml:

# @author: honeymon
 
management:
  security:
    enabled: true
shell:
  telnet: # Tel
    enabled: true
    port: 10000
  ssh:
    enabled: true
    port: 10001
  auth:
    simple:
      user:
        name: honeymon
        password: remote-shell

리모트쉘에 접근하는 방법은 다음과 같다.

ssh -p <port-number> <shell.auth.simple.user.name 값>@접근서버 IP 혹은 호스트명
//위의 설정에 따르면 다음과 같이 접근이 가능하다.
ex) $ ssh -p 10001 honeymon@localhost

텔넷으로 접근하려면 다음의 의존성을 추가해야 한다.

If you want to also enable telnet access you will additionally need a dependency onorg.crsh:crsh.shell.telnet

search.maven.org crsh.shell.telnet 검색 telnet 접속해보려고 했더니 오류가 발생...

Caused by: java.lang.NoSuchMethodError: org.crsh.vfs.Resource.<init>(Ljava/net/URL;)V
    at org.crsh.telnet.TelnetPlugin.init(TelnetPlugin.java:61)
    at org.crsh.plugin.PluginManager.getPlugins(PluginManager.java:83)
    at org.crsh.plugin.PluginContext.start(PluginContext.java:327)
    at org.crsh.plugin.PluginLifeCycle.start(PluginLifeCycle.java:104)
    at org.springframework.boot.actuate.autoconfigure.CrshAutoConfiguration$CrshBootstrapBean.init(CrshAutoConfiguration.java:230)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:349)
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:300)
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:133)
    ... 17 more

처음 접근할 경우에는 다음과 같이 인증키를 저장할지를 묻는다. 

리모트쉘로 접근하면 다음과 같은 화면을 볼 수 있다. 

리모트쉘에서 사용할 수 있는 명령어는 help 를 타이핑하면 다음과 같은 내용을 볼 수 있다. 

> help
Try one of these commands with the -h or --help switch:
 
NAME       DESCRIPTION
autoconfig Display auto configuration report from ApplicationContext
beans      Display beans in ApplicationContext
cron       manages the cron plugin
dashboard  a monitoring dashboard
egrep      search file(s) for lines that match a pattern
endpoint   Invoke actuator endpoints //앱에 설정된 애드포인트 목록들을 확인가능하다.
env        display the term env
filter     a filter for a stream of map
java       various java language commands
jmx        Java Management Extensions
jul        java.util.logging commands
jvm        JVM informations
less       opposite of more
mail       interact with emails
man        format and display the on-line manual pages
metrics    Display metrics provided by Spring Boot
shell      shell related command
sleep      sleep for some time
sort       sort a map
system     vm system properties commands
thread     JVM thread commands
help       provides basic help
repl       list the repl or change the current repl

리모트쉘은 CRaSH를 사용했다. 배너를 바꾸고 싶은데... 그 중에서 우와!!하면서 감탄했던 것이 대시보드!

화면크기에 따라 리사이징도 된다! +_+)b

스프링 액츄에이터SpringBoot actuator 에서 제공하는 엔드포인트 중 하나인 metrics 정보를 모니터링할 수 있는 metrics


리모트쉘로 원격접속해서 애플리케이션의 상태를 살필 수 있는 수단이 생겼다는 건 애플리케이션을 관리하는데 더욱 편해진다는 것이다. 리모트쉘로 접근해서... endpoint invoke shutdown을 실행하면!!

당신은 주금!!(애플리케이션을 켜로 터미널로 서버에 접속해야하는 번거로움이 생길 것이다).

리모트쉘에서 애플리케이션을 끄기 위해서는

리모트쉘에서 셧타운을 실행하기 위해서는 application.properties(or yml)에 다음 항목을 추가해야한다.

endpoints.shutdown.enabled=true

이렇게 가볍게 스프링부트가 제공하는 기능 중 하나인 리모트쉘Remote shell을 살펴봤다. 리모트쉘을 통해서 애플리케이션의 상태를 모니터링하고 제어하는 것이 가능해졌다. 스프링부트를 기반으로 배포하는 앱에는 반드시 넣어줘야할 녀석이었다. 바로! 추가!

스프링부트 소개

0. 스프링부트SpringBoot란?

Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can "just run". We take an opinionated view of the Spring platform and third-party libraries so you can get started with minimum fuss. Most Spring Boot applications need very little Spring configuration.

  • 스프링부트는 단독실행되는, 실행하기만 하면 되는 상용화 가능한 수준의 스프링 기반 애플리케이션을, 쉽게 만들어낼 수 있다.
  • 최소한의 설정으로 스프링 플랫폼과 서드파티 라이브러리들을 사용할 수 있도록 하고 있다.

스프링 기반의 애플리케이션을 개발하기 쉽도록 기본설정되어 있는 설정을 기반으로 해서 빠르게 개발할 수 있도록 해주는 개발플랫폼이랄까?

0.1. 스프링부트 기능

  • Create stand-alone Spring applications

    단독실행가능한 스프링애플리케이션을 생성한다.,

  • Embed Tomcat, Jetty or Undertow directly (no need to deploy WAR files)

    내장형 톰캣, 제티 혹은 언더토우를 내장(WAR 파일로 배포할 경우에는 필요없음)

  • Provide opinionated 'starter' component to simplify your build configuration

    기본설정되어 있는 'starter' 컴포넌트들을 쉽게 추가

  • Automatically configure Spring whenever possible

    가능한 자동설정되어 있음

  • Provide production-ready features such as metrics, health checks and externalized configuration

    상용화에 필요한 통계, 상태 점검 및 외부설정을 제공

  • Absolutely no code generation and no requirement for XML configuration

    설정을 위한 XML 코드를 생성하거나 요구하지 않음


1. 스프링부트 시작하기

1.1. 스프링부트 프로젝트 생성하기

  • 주의사항

    • 네트워크가 연결되어 있어야 한다.

      그렇다면, 네트워크가 연결되지 않은 인트라넷 환경에서는 어떻게 해야할까? = 넥서스Nexus 에 스프링부트 설정을 해야겠지요? 사실, 안해봐서 모르겠음. @_@);;

    • Maven 혹은 Gradle 플러그인이 IDE에 설치되어 있어야 한다.

1.1.1. http://start.spring.io/ 에서 생성하기

1.1.1.1. 프로젝트 메타데이터를 등록

  • Maven 보다는 Gradle
    • Maven 예제가 많은 편이지만, Maven의 골, 페이즈만으로는 프로젝트의 필요한 기능을 모두 지원하지 못할 수도 있음
    • Gradle은 Groovy DSL로 구성되어 있어서 그루비를 익혀야하지만, 지원되는 기능을 익히고 나면 훨씬 강력해짐
  • 배포형태에 따라서 war 또는 jar
    • 기본적으로는 단독실행가능지만, 프로젝트 환경에 따라 배포할 수도 있으니 war도 가능

1.1.1.2. [Generate Project] 버튼클릭

  • 'artifact' 이름으로 된 zip 파일 다운로드

1.1.1.3. IDE에서 Import Project

1.1.2. STS에서 생성하기

1.1.2.1. [File]-[New]-[Spring Starter project] 선택

1.1.2.2. 사용하려는 스프링 starter 선택

  • 최초에는 필요한 라이브러리들을 다운로드 받는데 상단한 시간이 소요된다.

1.2. 스프링부트 프로젝트 실행

  • [Run as] - [Spring Boot App] 선택
  • [gradle] - [Tasks quick launcher] 을 이용해서 실행
    • 프로젝트 지정된 JDK 버전과 IDE 실행 JDK 버전이 다르면...
  • 프로젝트 생성 위치에서 $ gradle bootRun 명령 실행

2. 스프링부트 구성 살펴보기

2.1. 최초 생성된 스프링부트 프로젝트 살펴보기

2.1.1. jar 프로젝트

  • build.gradle
//코드 생략
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'spring-boot'
apply plugin: 'io.spring.dependency-management'
 
jar {
    baseName = 'demo'
    version = '0.0.1-SNAPSHOT'
}
//코드생략
dependencies {
    compile("org.springframework.boot:spring-boot-starter-web")
    testCompile("org.springframework.boot:spring-boot-starter-test")
}
  • {artifact-name}Application.java
  • IDE에서 Java Application project로 인식
  • build 태스크 실행시 demo.jar 생성
  • 실행
$ java -jar demo.jar

2.1.2. war 프로젝트

  • build.gradle
//코드생략
apply plugin: 'java'
apply plugin: 'eclipse-wtp'
apply plugin: 'idea'
apply plugin: 'spring-boot'
apply plugin: 'io.spring.dependency-management'
apply plugin: 'war'
 
war {
    baseName = 'demowar'
    version = '0.0.1-SNAPSHOT'
}
//코드생략
configurations {
    providedRuntime
}
 
dependencies {
    compile("org.springframework.boot:spring-boot-starter-web")
    providedRuntime("org.springframework.boot:spring-boot-starter-tomcat")
    testCompile("org.springframework.boot:spring-boot-starter-test")
}
  • public class ServletInitializer extends SpringBootServletInitializer 클래스가 있음
  • IDE에서 웹프로젝트로 인식
  • build 태스크 실행시 demowar.war 생성
  • 실행

2.1.3. Excutable JAR

2.2. @SpringBootApplication

  • 코드
/**
 * Indicates a {@link Configuration configuration} class that declares one or more
 * {@link Bean @Bean} methods and also triggers {@link EnableAutoConfiguration
 * auto-configuration} and {@link ComponentScan component scanning}. This is a convenience
 * annotation that is equivalent to declaring {@code @Configuration},
 * {@code @EnableAutoConfiguration} and {@code @ComponentScan}.
 * 
 * @author Phillip Webb
 * @since 1.2.0
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Configuration
@EnableAutoConfiguration
@ComponentScan
public @interface SpringBootApplication {
 
    /**
     * Exclude specific auto-configuration classes such that they will never be applied.
     * @return the classes to exclude
     */
    Class<?>[] exclude() default {};
 
}
  • @SpringBootApplication 애노테이션이 선언된 애플리케이션 클래스는 패키지 루트에 위치하는 것이 좋다.
    • 물론 @ComponentScan에 별도의 패키지를 지정할 수 있지만 굳이~ 그렇게 하지 맙시다.
    • Locating the main application class 의 기본적인 구조를 따르는 걸 권장하고 싶음
      com
      +- example
           +- myproject
               +- Application.java
               |
               +- domain
               |   +- Customer.java
               |   +- CustomerRepository.java
               |
               +- service
               |   +- CustomerService.java
               |
               +- web
                   +- CustomerController.java

3. 스프링부트 설정

3.1. 스프링부트 자동설정AutoConfig

3.1.1. autoconfigure 패키지 확인

3.1.2. @Conditional, @ConditionalOnBean, @ConditionalOnMissingBean, @ConditionalOnClass 조건에 따라 스프링 빈Bean 으로 등록

  • @ConditionalOnBean
  • @ConditionalOnMissingBean
  • @ConditionalOnClass

3.2. 외부설정 하기

  • Common Application properties
  • 스프링부트의 프로퍼티스 확인순서에 따라서 외부요인들을 읽어오게 됨
  • Environment

    3.2.1. application.properties

  • PropertySource

    3.2.2. application.yml

  • YamlPropertySourceLoader

3.2.3. 프로파일즈 활용하기

  • 로컬, 개발, 테스트, 운영 설정을 각각 관리 및 적용
  • Profiles - springframework
  • 환경별 설정요소를 한곳에서 집중하여 관리할 수 있음

3.2.3.1. 기존 방식

  • 설정디렉토리를 분리
    • config/local
    • config/development
    • config/test
    • config/production
  • 빌드시 프로파일을 지정하여 지정한 설정디렉토리의 설정파일을 적용하는 형식을 취함

3.2.3.2. application.properties

  • application-{profiles}.properties
    • application-local.properties
    • application-development.properties
    • application-test.properties
    • application-production.properties

3.2.3.3. application.yaml

  • application.yaml
# 공통설정부분 지정가능
---
spring:
    profiles: local
---
spring:
  profiles: development
---
spring:
    profiles: test
---
spring:
  profiles: production

4. 스프링부트 확장하기

4.1. starter POMs 추가하기

  • Starer POMs
  • 추가시 spring.provides 에 연관된 스프링 라이브러리들이 정의되어 있다.
  • 관련 의존성 라이브러리에 대해서는 starter 프로젝트 내부에 있는 pom.xml 에 정의되어 있음

4.2. 의존성 라이브러리 추가하기

4.2.1. 의존성 버전


● 개인적 목표

  • JDK 8 이상 사용
  • Gradle 사용
  • SpringBoot 적용
    • 스프링 프레임워크 4.0 이상 적용
    • Spring Data JPA 사용


STS(Spring Tool Suite)를 3.7.0 으로 업그레이드를 하고나서 @ConfigurationProperties 애노테이션을 사용한 곳에 경고창이 뜨는 것을 보았다.

그 메시지를 살펴보면

When using @ConfigurationProperties it is recommended to add 'spring-boot-configuration-processor' to your classpath to generate configuration metadata

와 같다. @ConfigurationProperties 을 사용할 때는 spring-boot-configuration-processor를 클래스패스에 설정하는 것을 권장한다고. +_+)

그래서 찾아봤다.
Spring Boot Support in Spring Tool Suite 3.6.4

이런 내용이 있다. 대략,

  • STS 에서 간단하게 스프링부트 애플리케이션 생성하기
  • STS 에서 부트 애플리케이션을 실행하고 디버깅하기
  • STS Properties editor를 이용해서 설정프로퍼타이즈 편집하기
  • @ConfigurationProperties를 사용하는 코드에서 설정프로퍼타이즈 편집하기

의 기능을 사용할 수 있다.

메이븐이라면 pom.xml에다가 아래 의존성을 추가하면 되고

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
</dependency>

그레들이라면 build.gradle에다가 아래 사항을 추가하는 것만으로도 해결완료~!

compile "org.springframework.boot:spring-boot-configuration-processor"

spring-boot-configuration-processor를 활용한 기능은 위에 링크한 글을 (같이) 살펴보자.

SpringBoot으로 구현한 애플리케이션의 DB를 H2Database(http://h2database.com)를 사용한다.

물론 다른 것을 사용할 수도 있다. 개발하고 있는 제품의 특성에 맞춰 h2Database를 선택했을 뿐.

h2database에 접속할 수 있는 웹콘솔로 h2console이 제공되는데, 이 녀석을 애플리케이션에서
함께 실행할 수 있는 방법을 찾고 있었다.

그러다가 찾은 정보가!

spring boot default H2 jdbc connection (and H2 console)

h2database 에 포함된 org.h2.server.web.WebServlet을 등록하면 콘솔을 빈으로 등록하고 웹상으로 접근이 가능한 것이다!

@Bean
public ServletRegistrationBean h2servletRegistration() {
    ServletRegistrationBean registration = new ServletRegistrationBean(new WebServlet());
    registration.addUrlMappings("/h2console/*");
    return registration;
}

위처럼 빈Bean 선언을 하고 실행을 하면! localhost:{port}/h2console으로 접근하면!



JDBC URL은 database 설정에서 url을 복사해서 넣으면 된다. 테스트하려면 jdbc:h2:mem:test

의 모습을 볼 수 있다.

애플리케이션에서는 스프링시큐리티를 이용하여 접근제어를 하고 있다.

로그인을 하면 다음과 같은 백지화면이 나타난다. 그 이유를 찾아보려고 개발자도구를 열어보니



와 같은 메시지가 뜨는 것을 확인한다. 재빨리 검색을 들어가서!

Content-Security-Policy Spring Security - stackoverflow

스프링시큐리티 설정코드 부분에

@Override
  protected void configure(HttpSecurity http) throws Exception {
    http
      // ...
      .headers()
        .addHeaderWriter(new StaticHeadersWriter("X-Content-Security-Policy","script-src 'self'"))
      // ...
  }

다음과 같이 "X-Content-Security-Policy" 선언을 해줘야 한다. 애플리케이션을 재시작하면!



참 쉽죠잉??


+ Recent posts