<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>리루</title>
    <link>https://jsonsang2.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Tue, 18 Aug 2026 02:26:12 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>뚱보리루</managingEditor>
    <item>
      <title>Java8 - Optional</title>
      <link>https://jsonsang2.tistory.com/57</link>
      <description>&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;- 비어있을 수 있고, 어떤 값을 갖고 있을 수 있는 컨테이너 인스턴스&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;- null 체크를 하지 않으면 Null Pointer Exception이라는 문제가 발생 할 경우가 잦아질 수 있다.&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;- 매번 Null check 할 수 없고 Human error가 있을 수 있다.&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;- Null을 반환할 수 있는 상황 자체도 문제다.&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;방법 1.&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;- null이 반환될 수 있는 코드에서 미리 null check를 해서 client 코드에 편의를 제공할 수 있다. 하지만 로직상 자꾸 exception 처리를 넣는건 좋은 습관이 아니다.&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;방법 2.&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;- null을 그냥 반환하고 client 코드에서 null check를 한다.&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;- 리턴 값으로만 Optional로 사용하길 권장된다. (매개변수 등으로 사용가능하지만 호출하는 쪽에서 Optional 타칩이지만 null을 넘겨 줄 수 있으므로 이는 NPE가 발생할 수 있는 위험한 방식이다.)&lt;/p&gt;&lt;pre data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;public void optionalParameter(Optional&amp;lt;Param&amp;gt; param){

}

optionalParameter(null);&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;- 맵의 키 타입으로 Optional을 사용하면 안된다. Map의 큰 컨셉 중 하나는 key 값이 null이 아닌 것인데 Optional을 키로 사용했을 경우에 키가 있을 수도, 없을 수도 있다는 것 자체가 문제가 될 수 있다.&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;- 인스턴스 필드타입으로도 사용하지 말자. 어떠한 클래스의 필드가 있을 수도 있고, 없을 수도 있다라는 도메인 클레스 설계는 좋지 못하다.&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;- 컨테이너 성 데이터 타입 (Collection, Map, Stream, Array,Optional)은 이미 자체적으로 비어있는지 여부에 대해서 확인 할 수 있으니 Optional로 한번 더 작업 할 필요가 없다.&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;검사 및 값 가져오기&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;- isPresent()로 있는지 없는지 확인 가능.&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;- Java11 부터는 isEmpty() 도 제공.&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;- get() 을 통해서 값을 가져 올 수 있다.( 값이 들어있을 때는 문제가 없지만 값이 안들어 있으면 NoSuchElementException 발생)&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;- get() 호출 전에 해당 값이 있는지 확인 필요.&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;- 값이 있을 때의 처리는 ifPresent() 를 사용해 처리하면 추가적인 값 확인 없이 사용할 수 있다.&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;- 값을 가져올 때는 orElse()를 사용해서 있으면 값을 꺼내오고, 없으면 새로운 클래스를 만드는 메소드 호출 등의 방법을 사용&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;- orElseGet(Supplier) 를 사용할 수 도 있는데 이 둘의 차이는 orElse의 경우에는 참이든 거짓이든 parameter 속의 내용을 수행하지만 orElseGet의 경우에는 Else인 케이스에만 Supplier를 수행하게 된다. orElse 같은 경우에는 상수같이 이미 만들어진 작업에 대해서는 사용하는 것이 적절하고, 동적으로 무엇을 만들어야 하는 상황에서는 orElseGet이 더 적절할 수 있다.&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;- 중복 Optional일 경우에는 flatMap을 통해서 한번에 까버릴 수 있다.&lt;/p&gt;&lt;pre data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;// 양파까기
Optional&amp;lt;Optional&amp;lt;Day&amp;gt;&amp;gt; day = optional.map(Date::getDay);
Optional&amp;lt;Day&amp;gt; day2 = day1.orElse(Optional.empty());

// flatMap 사용
Optional&amp;lt;Day&amp;gt; test = optional.flatMap(Date::getDay); &lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category># Study/JAVA</category>
      <author>뚱보리루</author>
      <guid isPermaLink="true">https://jsonsang2.tistory.com/57</guid>
      <comments>https://jsonsang2.tistory.com/57#entry57comment</comments>
      <pubDate>Sun, 5 Jul 2020 12:24:46 +0900</pubDate>
    </item>
    <item>
      <title>Steam</title>
      <link>https://jsonsang2.tistory.com/56</link>
      <description>&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;Stream&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;-&lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html&quot; target=&quot;_blank&quot;&gt;https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html&lt;/a&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;- Sequence of elements supporting sequential and parallel aggregate operations.&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;- 연속된 데이터를 처리하는 Operation의 모임&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;- 데이터를 담는 저장소가 아니라 데이터를 소스로 사용해서 어떠한 처리를 하는 것&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;- Functional in nature : Stream으로 전달받은 데이터 다체를 변경하는게 아니라 또다른 Stream을 반환한다.&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;- 들어오는 데이터가 무제한일 수 있다.&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;- 들어오는 데이터가 무제한일 때 Short Circuit 메소드를 사용해 제한할 수 있다.&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;- Stream 이 제공하는 Operation은 계속해서 이어지는 중계형 Operation(Stream을 반환)과 종료 Operation(Stream이 아닌 다른 형태를 반환)으로 나눌 수 있다. (forEach도 stream 반환이 아니라 종료 Operation이다)&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;- Stream&amp;nbsp;데이터 소스는 오직 터미널 오퍼네이션을 실행할 때에만 처리한다. (중계형 Operation들은 Lazy하게 동작한다.)&lt;/p&gt;&lt;pre data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;package com.example.demok;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class RunSomething {

    public static void main(String[] args) {

    }

    public void run(){

        List&amp;lt;String&amp;gt; alphabet = new ArrayList&amp;lt;&amp;gt;();
        alphabet.add(&quot;a&quot;);
        alphabet.add(&quot;b&quot;);
        alphabet.add(&quot;c&quot;);
        alphabet.add(&quot;d&quot;);
        alphabet.add(&quot;e&quot;);

        // Do nothing because of no terminate operation
        alphabet.stream().map( s -&amp;gt; {
            System.out.println(s);
            return s.toUpperCase();
        });

        // Return a list
        List&amp;lt;String&amp;gt; upperCases = alphabet.stream().map( s -&amp;gt; {
            System.out.println(s);
            return s.toUpperCase();
        }).collect(Collectors.toList());

    }
}&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;pallarel stream&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;- ForkJoinPool 을 이용해 여러개의 Thread를 사용해 병렬로 동작한다.&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;- 무조건 paralleaStream을 사용한다고 빠른 것은 아니다.(Context Switch에 시간이 더 걸리는 케이스가 있을 것.)&lt;/p&gt;&lt;pre data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;    @Test
    public void streamTest(){
        List&amp;lt;String&amp;gt; alphabet = new ArrayList&amp;lt;&amp;gt;();
        alphabet.add(&quot;a&quot;);
        alphabet.add(&quot;b&quot;);
        alphabet.add(&quot;c&quot;);
        alphabet.add(&quot;d&quot;);
        alphabet.add(&quot;e&quot;);

        List&amp;lt;String&amp;gt; list = alphabet.parallelStream().map( s -&amp;gt; {
            System.out.println(s + &quot;, &quot; + Thread.currentThread().getName());
            return s.toUpperCase();
        }).collect(Collectors.toList());

        /*
        c, main
        a, ForkJoinPool.commonPool-worker-3
        e, ForkJoinPool.commonPool-worker-2
        b, ForkJoinPool.commonPool-worker-1
        d, ForkJoinPool.commonPool-worker-4
         */
    }&lt;/pre&gt;</description>
      <category># Study/JAVA</category>
      <author>뚱보리루</author>
      <guid isPermaLink="true">https://jsonsang2.tistory.com/56</guid>
      <comments>https://jsonsang2.tistory.com/56#entry56comment</comments>
      <pubDate>Sun, 5 Jul 2020 11:06:03 +0900</pubDate>
    </item>
    <item>
      <title>Java8 함수형 인터페이스</title>
      <link>https://jsonsang2.tistory.com/55</link>
      <description>&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;Functional Interface : &lt;b&gt;Any interface with a SAM(Single Abstract Method) is a functional interface&lt;/b&gt;&lt;span style=&quot;color: rgb(51, 51, 51);&quot;&gt;, and its implementation may be treated as lambda expressions.&lt;/span&gt;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&amp;nbsp;- Java8에서는 Interface에 static method / default method가 사용가능하다. 이러한 추가적인 함수들이 있더라도 SAM이 하나만 존재한다면 Functional Interface라고 할 수 있다.&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&lt;span style=&quot;color: rgb(51, 51, 51);&quot;&gt;&amp;nbsp;- `void do something();` 앞에는 `abstract`가 생략되어 있다고 볼 수있다.&lt;/span&gt;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&amp;nbsp;- Abstract Method가 복수개가 되면 컴파일에러가 발생한다.(`@FunctionalInterface`가 있는 경우)&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&amp;nbsp;- `@FunctionalInterface`는 자바 standard library에 포함되어 있기 때문에 따로 import 되지 않는다.&lt;/p&gt;&lt;pre data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;package com.example.demok;

@FunctionalInterface
public interface Something {
    
    void doSomething();
    
    static void doStatic(){
        System.out.println(&quot;Static method&quot;);
    }
    
    default void doDefault(){
        System.out.println(&quot;Default method&quot;);
    }
    
}
&lt;/pre&gt;&lt;pre data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;package com.example.demok;

public class RunSomething {

    public static void main(String[] args) {

        // Anonymous inner class
        Something something = new Something() {
            @Override
            public void doSomething() {
                System.out.println(&quot;Something&quot;);
            }
        };
        something.doSomething();

        // Lambda expression
        Something newSomething = () -&amp;gt; System.out.println(&quot;New Something&quot;);
        newSomething.doSomething();

        // Lambda expression 2
        Something multiSomething = () -&amp;gt; {
            System.out.println(&quot;New Something 1&quot;);
            System.out.println(&quot;New Something 2&quot;);
        };
        multiSomething.doSomething();

    }
}
&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;특징&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&amp;nbsp;1. 함수를 First class object로 사용 할 수 있다.&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&amp;nbsp; &amp;nbsp;- Lambda expression 같은 형태를 리턴, 매개변수 등 Objcect 같이 사용할 수 있다.&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;2. 순수함수(Pure Function)&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&amp;nbsp; - Side Effect를 만들 수 없다. 함수 밖 변수 변경할 수 없다.&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&amp;nbsp; - 동일한 input이 들어가면 결과는 항상 같아야 한다.&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&amp;nbsp; - 상태가 없다.&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;3. 고차함수(Higher Order Function)&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&amp;nbsp; - 함수가 함수를 매개변수로 사용할 수 있고, 함수를 리턴할 수 있다.&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;자바가 기본으로 제공해주는 함수형 인터페이스들이 있다.&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&amp;nbsp;1. Function&lt;/p&gt;&lt;pre data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;/**
 * Represents a function that accepts one argument and produces a result.
 *
 * &amp;lt;p&amp;gt;This is a &amp;lt;a href=&quot;package-summary.html&quot;&amp;gt;functional interface&amp;lt;/a&amp;gt;
 * whose functional method is {@link #apply(Object)}.
 *
 * @param &amp;lt;T&amp;gt; the type of the input to the function
 * @param &amp;lt;R&amp;gt; the type of the result of the function
 *
 * @since 1.8
 */
@FunctionalInterface
public interface Function&amp;lt;T, R&amp;gt; {

    /**
     * Applies this function to the given argument.
     *
     * @param t the function argument
     * @return the function result
     */
    R apply(T t);
}&lt;/pre&gt;&lt;pre data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;package com.example.demok;

import java.util.function.Function;

public class AppendQuestionMark implements Function&amp;lt;String, String&amp;gt; {


    @Override
    public String apply(String s) {
        return s.concat(&quot;!&quot;);
    }
}
&lt;/pre&gt;&lt;pre data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;package com.example.demok;

import java.util.function.Function;

public class RunSomething {

    public static void main(String[] args) {

        AppendQuestionMark appendQuestionMark = new AppendQuestionMark();
        System.out.println(appendQuestionMark.apply(&quot;Let's Go Home&quot;));

        Function&amp;lt;String, String&amp;gt; concatQuestionMark = (s) -&amp;gt; s.concat(&quot;!&quot;);
        System.out.println(concatQuestionMark.apply(&quot;Let's Go Home&quot;));
    }
}&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&amp;nbsp; &amp;nbsp; 1-1. compose(), andThen()&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&amp;nbsp;- 다른 함수들과 조합해서 사용할 수 있는 함수 제공.&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&amp;nbsp;- compose 내부의 함수 먼저 수행 후, 외부함수 수행&lt;/p&gt;&lt;pre data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;@FunctionalInterface
public interface Function&amp;lt;T, R&amp;gt; {
    /**
     * Returns a composed function that first applies the {@code before}
     * function to its input, and then applies this function to the result.
     * If evaluation of either function throws an exception, it is relayed to
     * the caller of the composed function.
     *
     * @param &amp;lt;V&amp;gt; the type of input to the {@code before} function, and to the
     *           composed function
     * @param before the function to apply before this function is applied
     * @return a composed function that first applies the {@code before}
     * function and then applies this function
     * @throws NullPointerException if before is null
     *
     * @see #andThen(Function)
     */
    default &amp;lt;V&amp;gt; Function&amp;lt;V, R&amp;gt; compose(Function&amp;lt;? super V, ? extends T&amp;gt; before) {
        Objects.requireNonNull(before);
        return (V v) -&amp;gt; apply(before.apply(v));
    }
    /**
     * Returns a composed function that first applies this function to
     * its input, and then applies the {@code after} function to the result.
     * If evaluation of either function throws an exception, it is relayed to
     * the caller of the composed function.
     *
     * @param &amp;lt;V&amp;gt; the type of output of the {@code after} function, and of the
     *           composed function
     * @param after the function to apply after this function is applied
     * @return a composed function that first applies this function and then
     * applies the {@code after} function
     * @throws NullPointerException if after is null
     *
     * @see #compose(Function)
     */
    default &amp;lt;V&amp;gt; Function&amp;lt;T, V&amp;gt; andThen(Function&amp;lt;? super R, ? extends V&amp;gt; after) {
        Objects.requireNonNull(after);
        return (T t) -&amp;gt; after.apply(apply(t));
    }
}&lt;/pre&gt;&lt;pre data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;package com.example.demok;

import java.util.function.Function;

public class RunSomething {

    public static void main(String[] args) {

        Function&amp;lt;String, String&amp;gt; concatQuestionMark = (s) -&amp;gt; s.concat(&quot;?&quot;);
        Function&amp;lt;String, String&amp;gt; concatStarMakr = (s) -&amp;gt; s.concat(&quot;*&quot;);
        Function&amp;lt;String, String&amp;gt; multiFunction = concatQuestionMark.compose(concatStarMakr);
        
        // Would you like something to drink*?
        System.out.println(multiFunction.apply(&quot;Would you like something to drink&quot;));
        // Would you like something to drink?*
        System.out.println(concatQuestionMark.andThen(concatStarMakr).apply(&quot;Would you like something to drink&quot;));
    }
}&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&amp;nbsp; 2. Consume&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&amp;nbsp; - 반환타입은 없고, 입력타입만 존재하는 함수형 인터페이스&lt;/p&gt;&lt;pre data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;/**
 * Represents an operation that accepts a single input argument and returns no
 * result. Unlike most other functional interfaces, {@code Consumer} is expected
 * to operate via side-effects.
 *
 * &amp;lt;p&amp;gt;This is a &amp;lt;a href=&quot;package-summary.html&quot;&amp;gt;functional interface&amp;lt;/a&amp;gt;
 * whose functional method is {@link #accept(Object)}.
 *
 * @param &amp;lt;T&amp;gt; the type of the input to the operation
 *
 * @since 1.8
 */
@FunctionalInterface
public interface Consumer&amp;lt;T&amp;gt; {

    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);
 }&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;3. Supplier&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&amp;nbsp; - 입력타입은 없고 반환타입만 존재하는 함수형 인터페이스&lt;/p&gt;&lt;pre data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;/**
 * Represents a supplier of results.
 *
 * &amp;lt;p&amp;gt;There is no requirement that a new or distinct result be returned each
 * time the supplier is invoked.
 *
 * &amp;lt;p&amp;gt;This is a &amp;lt;a href=&quot;package-summary.html&quot;&amp;gt;functional interface&amp;lt;/a&amp;gt;
 * whose functional method is {@link #get()}.
 *
 * @param &amp;lt;T&amp;gt; the type of results supplied by this supplier
 *
 * @since 1.8
 */
@FunctionalInterface
public interface Supplier&amp;lt;T&amp;gt; {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}
&lt;/pre&gt;&lt;pre data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;package com.example.demok;

import java.util.function.Consumer;
import java.util.function.Supplier;

public class RunSomething {

    public static void main(String[] args) {

        // Hello World!
        Consumer&amp;lt;String&amp;gt; consumer = (s) -&amp;gt; System.out.println(&quot;Hello&quot; + s);
        consumer.accept(&quot;World!&quot;);

        // Hello World!
        Supplier&amp;lt;String&amp;gt; supplier = () -&amp;gt; &quot;Hello World!&quot;;
        System.out.println(supplier.get());
        
    }
}&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;4. Predicate&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&amp;nbsp; - 인자 하나를 받아서 true / false 를 반환해주는 함수형 인터페이스&lt;/p&gt;&lt;pre data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;/**
 * Represents a predicate (boolean-valued function) of one argument.
 *
 * &amp;lt;p&amp;gt;This is a &amp;lt;a href=&quot;package-summary.html&quot;&amp;gt;functional interface&amp;lt;/a&amp;gt;
 * whose functional method is {@link #test(Object)}.
 *
 * @param &amp;lt;T&amp;gt; the type of the input to the predicate
 *
 * @since 1.8
 */
@FunctionalInterface
public interface Predicate&amp;lt;T&amp;gt; {

    /**
     * Evaluates this predicate on the given argument.
     *
     * @param t the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(T t);
}&lt;/pre&gt;&lt;pre data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;package com.example.demok;

import java.util.function.Predicate;

public class RunSomething {

    public static void main(String[] args) {

        // True
        Predicate&amp;lt;Integer&amp;gt; predicate = (i) -&amp;gt; i &amp;lt; 10;
        System.out.println(predicate.test(5));
    }
}&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;5. UnaryOperator&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&amp;nbsp;- Function의 입출력 두 값의 형태가 동일 할 때 사용가능&lt;/p&gt;&lt;pre data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;package java.util.function;

/**
 * Represents an operation on a single operand that produces a result of the
 * same type as its operand.  This is a specialization of {@code Function} for
 * the case where the operand and result are of the same type.
 *
 * &amp;lt;p&amp;gt;This is a &amp;lt;a href=&quot;package-summary.html&quot;&amp;gt;functional interface&amp;lt;/a&amp;gt;
 * whose functional method is {@link #apply(Object)}.
 *
 * @param &amp;lt;T&amp;gt; the type of the operand and result of the operator
 *
 * @see Function
 * @since 1.8
 */
@FunctionalInterface
public interface UnaryOperator&amp;lt;T&amp;gt; extends Function&amp;lt;T, T&amp;gt; {

    /**
     * Returns a unary operator that always returns its input argument.
     *
     * @param &amp;lt;T&amp;gt; the type of the input and output of the operator
     * @return a unary operator that always returns its input argument
     */
    static &amp;lt;T&amp;gt; UnaryOperator&amp;lt;T&amp;gt; identity() {
        return t -&amp;gt; t;
    }
}
&lt;/pre&gt;&lt;pre data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;package com.example.demok;

import java.util.function.UnaryOperator;

public class RunSomething {

    public static void main(String[] args) {

        UnaryOperator&amp;lt;String&amp;gt; unaryOperator = (s) -&amp;gt; s + &quot;world!&quot;;
        System.out.println(unaryOperator.apply(&quot;Hello &quot;));
    }
}&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;변수 캡쳐&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&amp;nbsp;- 로컬 클래스, 익명 클래스, 람다함수 에서는 외부 변수가 `final`인 경우에만 참조가 가능했다.&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&amp;nbsp;- Java8부터는 `final`이 명시적으로 붙어 있지 않아도 Effective fianl(`final`이 붙어 있지 않지만 실질적으로 변화가 없어 final처럼 사용되는 변수)는 사용가능하다.&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&amp;nbsp;- Effective final 변수가 어디선가 변경된다면 컴파일 에러가 발생한다.&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&amp;nbsp;- 로컬 클래스, 익명 클래스, 네스트 클래스는 각 클래스가 생성되면 해당 클래스에 새로은 scope이 생겨서 변수에 대한 쉐도윙이 일어난다.&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&amp;nbsp;- 람다는 사용되는 메서드와 scope가 같아서 쉐도윙이 되지 않는다.&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: justify;&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;pre data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;package com.example.demok;

import java.util.function.Consumer;

public class RunSomething {

    public static void main(String[] args) {
        
    }
    
    public void run(){
        int localValue = 1;
        
        // Inner Class
        class innerClass {
            int localValue = 2;
            void method(){
                System.out.println(localValue);
            }
        }
        
        // Anonymous class
        Consumer&amp;lt;Integer&amp;gt; consumer = new Consumer&amp;lt;Integer&amp;gt;() {
            @Override
            public void accept(Integer localValue) {
                System.out.println(localValue);
            }
        };
        
        // Lambda
        // Error : Variable 'localValue' is already defined in the scope
        Consumer&amp;lt;Integer&amp;gt; integerConsumer = (localValue) -&amp;gt; System.out.println(localValue);
                
    }
}&lt;/pre&gt;</description>
      <category># Study/JAVA</category>
      <author>뚱보리루</author>
      <guid isPermaLink="true">https://jsonsang2.tistory.com/55</guid>
      <comments>https://jsonsang2.tistory.com/55#entry55comment</comments>
      <pubDate>Sat, 4 Jul 2020 16:16:17 +0900</pubDate>
    </item>
    <item>
      <title>1. 쿠버네티스를 알기위한 기본 사항들</title>
      <link>https://jsonsang2.tistory.com/54</link>
      <description>&lt;p&gt;1.&amp;nbsp;쿠버네티스&amp;nbsp;사용&amp;nbsp;이유.&lt;br /&gt;&amp;nbsp;-&amp;nbsp;대규모&amp;nbsp;서비스를&amp;nbsp;최대한&amp;nbsp;자원을&amp;nbsp;효율적으로&amp;nbsp;사용하기&amp;nbsp;위함.&lt;br /&gt;&amp;nbsp;-&amp;nbsp;기존&amp;nbsp;VM(VMWare,&amp;nbsp;Open&amp;nbsp;Stack)들은&amp;nbsp;가상화는&amp;nbsp;되는데&amp;nbsp;효율이&amp;nbsp;안나왔다.(무거운&amp;nbsp;OS를&amp;nbsp;사용하게&amp;nbsp;돼서)&lt;br /&gt;&amp;nbsp;-&amp;nbsp;dot&amp;nbsp;Cloud&amp;nbsp;라는&amp;nbsp;회사가&amp;nbsp;Linux의&amp;nbsp;cgroup이라는&amp;nbsp;자원&amp;nbsp;격리기술을&amp;nbsp;Container라는&amp;nbsp;기술로&amp;nbsp;만드들고&amp;nbsp;docker라고&amp;nbsp;회사명을&amp;nbsp;변경&lt;br /&gt;&amp;nbsp;-&amp;nbsp;컨테이너&amp;nbsp;가상화&amp;nbsp;기술은&amp;nbsp;서버스간&amp;nbsp;자원격리를&amp;nbsp;해서&amp;nbsp;OS를&amp;nbsp;따로&amp;nbsp;띄우지&amp;nbsp;않아도&amp;nbsp;됨.&lt;br /&gt;&amp;nbsp;-&amp;nbsp;OS&amp;nbsp;가동시간이&amp;nbsp;없기&amp;nbsp;때문에&amp;nbsp;자동화시에&amp;nbsp;엄청&amp;nbsp;빠르고&amp;nbsp;자원&amp;nbsp;효율도&amp;nbsp;매우&amp;nbsp;높음.&lt;br /&gt;&amp;nbsp;-&amp;nbsp;근데&amp;nbsp;도커&amp;nbsp;자체는&amp;nbsp;하나의&amp;nbsp;서비스를&amp;nbsp;컨테이너로&amp;nbsp;가상화시켜서&amp;nbsp;배포를&amp;nbsp;하는거지&amp;nbsp;엄청&amp;nbsp;많은&amp;nbsp;서비스들을&amp;nbsp;운영할&amp;nbsp;때&amp;nbsp;그걸&amp;nbsp;일일이&amp;nbsp;배포하고&amp;nbsp;운영하는&amp;nbsp;역할을&amp;nbsp;하진&amp;nbsp;않는다.&lt;br /&gt;&amp;nbsp;-&amp;nbsp;이런걸&amp;nbsp;해주는게&amp;nbsp;컨테이너&amp;nbsp;오케스트레이션이라는&amp;nbsp;개념이고,&amp;nbsp;여러&amp;nbsp;컨테이너들을&amp;nbsp;관리해주는&amp;nbsp;솔루션이라고&amp;nbsp;보면됨.&lt;br /&gt;&amp;nbsp;-&amp;nbsp;도커가&amp;nbsp;오픈소스라&amp;nbsp;이를&amp;nbsp;활용해&amp;nbsp;오케스트레이션&amp;nbsp;서비스(오케스트레이터)들이&amp;nbsp;많은&amp;nbsp;회사에서&amp;nbsp;나왔는데&amp;nbsp;이&amp;nbsp;중&amp;nbsp;하나가&amp;nbsp;구글의&amp;nbsp;쿠버네티스다.&lt;br /&gt;&amp;nbsp;-&amp;nbsp;쿠버네티스&amp;nbsp;개발시에는&amp;nbsp;여러&amp;nbsp;회사가&amp;nbsp;참여함(ms,&amp;nbsp;google,&amp;nbsp;ibm&amp;nbsp;등등)&lt;br /&gt;&lt;br /&gt;&amp;nbsp;1.1&amp;nbsp;쿠버네티스가&amp;nbsp;해주는&amp;nbsp;자동화&lt;br /&gt;&amp;nbsp;-&amp;nbsp;Auth&amp;nbsp;Scaling&amp;nbsp;:&amp;nbsp;트래픽에&amp;nbsp;따라&amp;nbsp;자원을&amp;nbsp;자동으로&amp;nbsp;구성&lt;br /&gt;&amp;nbsp;-&amp;nbsp;Auto&amp;nbsp;Healing&amp;nbsp;:&amp;nbsp;한&amp;nbsp;서버가&amp;nbsp;장애가&amp;nbsp;나도&amp;nbsp;장애가난&amp;nbsp;서버&amp;nbsp;위에&amp;nbsp;있는&amp;nbsp;서비스들이&amp;nbsp;다른&amp;nbsp;서버로&amp;nbsp;이동시켜주는&amp;nbsp;기능.&lt;br /&gt;&amp;nbsp;-&amp;nbsp;Deployment&amp;nbsp;:&amp;nbsp;기능을&amp;nbsp;통해&amp;nbsp;RollingUpdate,&amp;nbsp;ReCreate&amp;nbsp;기능&amp;nbsp;지원&lt;br /&gt;&lt;br /&gt;&amp;nbsp;1.2&amp;nbsp;VM&amp;nbsp;vs&amp;nbsp;Container&lt;br /&gt;&amp;nbsp;-&amp;nbsp;VM&amp;nbsp;:&amp;nbsp;Host&amp;nbsp;OS&amp;nbsp;위에&amp;nbsp;VM&amp;nbsp;가상화를&amp;nbsp;위한&amp;nbsp;hypervisor가&amp;nbsp;있고&amp;nbsp;그&amp;nbsp;위에서&amp;nbsp;GuestOS&amp;nbsp;구성&lt;br /&gt;&amp;nbsp;-&amp;nbsp;Container&amp;nbsp;:&amp;nbsp;Host&amp;nbsp;OS위에&amp;nbsp;Container&amp;nbsp;가상화를&amp;nbsp;시켜주는&amp;nbsp;여러&amp;nbsp;소프트웨어&amp;nbsp;들이&amp;nbsp;있고(도커,&amp;nbsp;rkt,&amp;nbsp;LXC)&lt;br /&gt;&amp;nbsp;-&amp;nbsp;도커가&amp;nbsp;컨테이너를&amp;nbsp;만들어주는데&amp;nbsp;이&amp;nbsp;컨테이너는&amp;nbsp;서버와&amp;nbsp;이를&amp;nbsp;위한&amp;nbsp;라이브러리를&amp;nbsp;함께&amp;nbsp;이미지로&amp;nbsp;만들&amp;nbsp;수&amp;nbsp;있다.&lt;br /&gt;&amp;nbsp;-&amp;nbsp;도커는&amp;nbsp;여러&amp;nbsp;컨테이너간에&amp;nbsp;Host&amp;nbsp;자원을&amp;nbsp;분리해서&amp;nbsp;사용하게&amp;nbsp;해준다.(namespace,&amp;nbsp;cgroups을&amp;nbsp;사용해&amp;nbsp;격리를하게되고,&amp;nbsp;namespace는&amp;nbsp;커널에&amp;nbsp;관한&amp;nbsp;영역을&amp;nbsp;분리(mnt,pid,net,ipc),&amp;nbsp;cgroups는&amp;nbsp;자원에&amp;nbsp;관한&amp;nbsp;영역을&amp;nbsp;분리(memory,&amp;nbsp;CPU,&amp;nbsp;I/O,&amp;nbsp;network)&amp;nbsp;)&lt;br /&gt;&amp;nbsp;-&amp;nbsp;컨테이너&amp;nbsp;가상화가&amp;nbsp;깔려있는&amp;nbsp;OS에서는&amp;nbsp;개발환경에&amp;nbsp;대한&amp;nbsp;걱정&amp;nbsp;없이&amp;nbsp;배포가&amp;nbsp;가능해짐&lt;br /&gt;&amp;nbsp;-&amp;nbsp;시스템&amp;nbsp;구조적으로&amp;nbsp;컨테이너는&amp;nbsp;한&amp;nbsp;OS를&amp;nbsp;공유하는&amp;nbsp;개념이고,&amp;nbsp;VM은&amp;nbsp;각각의&amp;nbsp;OS를띄워야해&amp;nbsp;컨테이너가&amp;nbsp;빠를&amp;nbsp;수&amp;nbsp;밖에&amp;nbsp;없다.&lt;br /&gt;&amp;nbsp;-&amp;nbsp;보안적으로&amp;nbsp;vm은&amp;nbsp;게스트&amp;nbsp;os가&amp;nbsp;뚫려도&amp;nbsp;다른&amp;nbsp;게스트&amp;nbsp;os나&amp;nbsp;host&amp;nbsp;os&amp;nbsp;와&amp;nbsp;완벽히&amp;nbsp;분리가&amp;nbsp;되어있어&amp;nbsp;영향이&amp;nbsp;없는데,&amp;nbsp;컨테이너는&amp;nbsp;한&amp;nbsp;컨테이너가&amp;nbsp;뚫려&amp;nbsp;os&amp;nbsp;영역에&amp;nbsp;접근가능해지면&amp;nbsp;다른&amp;nbsp;컨테이너가&amp;nbsp;위험에&amp;nbsp;쳐할&amp;nbsp;수&amp;nbsp;있다.&lt;br /&gt;&amp;nbsp;-&amp;nbsp;컨테이너는&amp;nbsp;시스템을&amp;nbsp;모듈별로&amp;nbsp;만들어&amp;nbsp;개발했을&amp;nbsp;때&amp;nbsp;배포&amp;nbsp;및&amp;nbsp;확장부분에&amp;nbsp;있어&amp;nbsp;효율적이다.&amp;nbsp;VM의&amp;nbsp;경우에는&amp;nbsp;새로운&amp;nbsp;게스트&amp;nbsp;OS를&amp;nbsp;띄워야해&amp;nbsp;불필요하게&amp;nbsp;모듈을&amp;nbsp;확장해&amp;nbsp;자원을&amp;nbsp;낭비해야&amp;nbsp;하는&amp;nbsp;경향이&amp;nbsp;있다.&lt;br /&gt;&lt;br /&gt;&amp;nbsp;2.&amp;nbsp;쿠버네티스&amp;nbsp;사용자&lt;br /&gt;&amp;nbsp;&amp;nbsp;2.1&amp;nbsp;쿠버네티스&amp;nbsp;운영자&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;클러스터를&amp;nbsp;운영&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;Installation,&amp;nbsp;Architecture,&amp;nbsp;Networking&lt;br /&gt;&amp;nbsp;&amp;nbsp;2.2&amp;nbsp;쿠버네티스&amp;nbsp;사용자&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;쿠버네티스&amp;nbsp;기능을&amp;nbsp;이용해서&amp;nbsp;서비스를&amp;nbsp;배포&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;Workloads,&amp;nbsp;Service,&amp;nbsp;Storage&amp;nbsp;/&amp;nbsp;Config,&amp;nbsp;Metadata,&amp;nbsp;Cluster&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3.&amp;nbsp;쿠버네티스&amp;nbsp;개념&lt;br /&gt;&amp;nbsp;-&amp;nbsp;Master,&amp;nbsp;Node들로&amp;nbsp;구성된&amp;nbsp;쿠버네티스&amp;nbsp;Cluster&lt;br /&gt;&amp;nbsp;-&amp;nbsp;Node들은&amp;nbsp;자원을&amp;nbsp;제공,&amp;nbsp;Master는&amp;nbsp;쿠버테니스&amp;nbsp;전반적인&amp;nbsp;기능을&amp;nbsp;컨트롤&lt;br /&gt;&amp;nbsp;-&amp;nbsp;클러스터&amp;nbsp;내&amp;nbsp;namespace가&amp;nbsp;쿠버테니스&amp;nbsp;오브젝트들을&amp;nbsp;독립된&amp;nbsp;공간으로&amp;nbsp;분리해준다.&lt;br /&gt;&amp;nbsp;-&amp;nbsp;Namesapce는&amp;nbsp;쿠버네티스&amp;nbsp;최소&amp;nbsp;배포단위인&amp;nbsp;Pod들이&amp;nbsp;있고,&amp;nbsp;Pod들에게&amp;nbsp;외부로부터&amp;nbsp;접근이&amp;nbsp;가능하게&amp;nbsp;해주는&amp;nbsp;Service가&amp;nbsp;있다.&lt;br /&gt;&amp;nbsp;-&amp;nbsp;서로다른&amp;nbsp;Namesapce에&amp;nbsp;있는&amp;nbsp;pod들에게는&amp;nbsp;Service에서&amp;nbsp;연결이&amp;nbsp;불가.&lt;br /&gt;&amp;nbsp;-&amp;nbsp;Pod&amp;nbsp;안에는&amp;nbsp;여러&amp;nbsp;Container들이&amp;nbsp;있고,&amp;nbsp;컨테이너&amp;nbsp;하나&amp;nbsp;당&amp;nbsp;하나의&amp;nbsp;앱이&amp;nbsp;돌아가니,&amp;nbsp;pod&amp;nbsp;하나당&amp;nbsp;여러&amp;nbsp;앱들이&amp;nbsp;돌아갈&amp;nbsp;수&amp;nbsp;있다.&lt;br /&gt;&amp;nbsp;-&amp;nbsp;근데&amp;nbsp;Pod에&amp;nbsp;문제가&amp;nbsp;생겨&amp;nbsp;재생성이&amp;nbsp;되면&amp;nbsp;그&amp;nbsp;안에&amp;nbsp;있는&amp;nbsp;데이터들이&amp;nbsp;다&amp;nbsp;날아가서&amp;nbsp;공용으로&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;Volume을&amp;nbsp;만들어&amp;nbsp;사용&amp;nbsp;가능.&lt;br /&gt;&amp;nbsp;-&amp;nbsp;Namespace에&amp;nbsp;ResourceQuota와&amp;nbsp;LimitRange를&amp;nbsp;달아서&amp;nbsp;pod&amp;nbsp;갯수나&amp;nbsp;cpu/memory를&amp;nbsp;제한할&amp;nbsp;수&amp;nbsp;있다.&lt;br /&gt;&amp;nbsp;-&amp;nbsp;ConfigMap이나&amp;nbsp;Secret을&amp;nbsp;통해서&amp;nbsp;Pod&amp;nbsp;생성시&amp;nbsp;환경변수&amp;nbsp;값이나&amp;nbsp;파일&amp;nbsp;마운팅이&amp;nbsp;가능하다.&lt;br /&gt;&amp;nbsp;-&amp;nbsp;Controller가&amp;nbsp;Pod들을&amp;nbsp;관리해준다.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;Replication&amp;nbsp;Controller,&amp;nbsp;ReplicaSet이&amp;nbsp;기본적인&amp;nbsp;컨트롤러인데,&amp;nbsp;파드가&amp;nbsp;죽으면&amp;nbsp;감지해&amp;nbsp;살려주거나&amp;nbsp;파드의&amp;nbsp;갯수를&amp;nbsp;scale&amp;nbsp;in-out&amp;nbsp;해준다.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;Deployment는&amp;nbsp;배포&amp;nbsp;후&amp;nbsp;새&amp;nbsp;파드들을&amp;nbsp;업그래이드&amp;nbsp;해주고&amp;nbsp;배포시&amp;nbsp;문제가&amp;nbsp;생기면&amp;nbsp;롤백을&amp;nbsp;도와준다.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;DaemonSet은&amp;nbsp;한&amp;nbsp;노드에&amp;nbsp;파드가&amp;nbsp;하나씩만&amp;nbsp;유지되게&amp;nbsp;해준다.&amp;nbsp;(이런&amp;nbsp;케이스는&amp;nbsp;추후&amp;nbsp;설명)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;Job은&amp;nbsp;어떤&amp;nbsp;특정&amp;nbsp;작업만하고&amp;nbsp;종료되어야&amp;nbsp;할때&amp;nbsp;사용,&amp;nbsp;이게&amp;nbsp;주기적인&amp;nbsp;작업이&amp;nbsp;되면&amp;nbsp;Cron&amp;nbsp;Job&amp;nbsp;사용.&lt;/p&gt;</description>
      <category># Study/Container</category>
      <author>뚱보리루</author>
      <guid isPermaLink="true">https://jsonsang2.tistory.com/54</guid>
      <comments>https://jsonsang2.tistory.com/54#entry54comment</comments>
      <pubDate>Mon, 25 May 2020 16:52:29 +0900</pubDate>
    </item>
    <item>
      <title>5. Servlet (써블릿) - DispatcherServlet</title>
      <link>https://jsonsang2.tistory.com/53</link>
      <description>&lt;p&gt;1. 요청이 어떻게 처리되느냐?&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 해당 요청의 정보들을 판단한다.(Multipart, Theme, etc..)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 요청을 처리할 수 있는 Handler를 찾는다. (DispatcherServlet 이 들고있는 여러 종류의 HandlerMapping 중, 기본적으로는 BeanNameUrlHandlerMapping, RequestMappingHandlerMapping 인터페이스가 있다.)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- &lt;span style=&quot;color: #333333;&quot;&gt;RequestMappingHandlerMapping&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;가 @Controller, @GetMapping, @PostMapping 등을 사용한 Handler를 찾아준다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 찾은 Handler를 가져와 어느 HandlerAdapter가 찾아낸 Handler를 실행할 수 있는가를 찾아낸다. 이 경우에는 &lt;span style=&quot;color: #333333;&quot;&gt;RequestMappingHandlerAdaptor가 해당 Handler를 지원한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;- HandlerInternal Method 안에서 Java의 Reflection을 통해서 invokeHandlerMethod를 수행한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;- 해당 Hander를 수행하고, 결과값을 반환한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;- 여러 타입(15가지)의 ReturnValueHandler 중 반환되는 값의 타입을 어던 Handler가 처리해줄 수 있는지 선택된다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;- @RestController(@Controller + @ResponseBody)일 경우에는 RequestResponseBodyMethodProcessor 가 처리해줄 수 있다.( 그리고 이 상황에서는 ModelAndView 값은 Null이다.)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;- Convertor를 사용해 Return 값을 Http Reponse 본문에 넣어주는 역할을 한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <author>뚱보리루</author>
      <guid isPermaLink="true">https://jsonsang2.tistory.com/53</guid>
      <comments>https://jsonsang2.tistory.com/53#entry53comment</comments>
      <pubDate>Sun, 2 Feb 2020 22:12:14 +0900</pubDate>
    </item>
    <item>
      <title>4. Servlet (써블릿) - Servlet Application에 Spring MVC 적용</title>
      <link>https://jsonsang2.tistory.com/52</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. Servlet&amp;nbsp;Application에&amp;nbsp;Spring&amp;nbsp;적용의 의미란?&lt;/h3&gt;
&lt;p&gt;&amp;nbsp;- 스프링이 제공하는 IoC 컨테이너를 활용하겠다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 스프링이 제공하는 서블릿 구현체 DispatcherServlet을 사용하겠다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1-1. (임의로 만든 Servlet에서)&amp;nbsp;&lt;span style=&quot;color: #333333;&quot;&gt;스프링이 제공하는 IoC 컨테이너를 활용하겠다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 의존성 필요&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&amp;lt;dependency&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework&lt;span&gt;&amp;lt;/groupId&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-webmvc&lt;span&gt;&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;lt;version&amp;gt;&lt;/span&gt;5.2.3.RELEASE&lt;span&gt;&amp;lt;/version&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&amp;nbsp;- web.xml 파일 내 Listener 변경(기등록된 리스너를 제거하고, Spring에서 제공하는 ContextLoaderListener 등록)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&amp;nbsp;- &lt;span style=&quot;color: #333333;&quot;&gt;ContextLoaderListener&lt;/span&gt;는 Spring IoC Container (즉, Application Context)를 Servlet Application 생명 주기에 맞춰서 바인딩해준다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&amp;nbsp;- Application Context를 Web Application에 등록되어있는 Servlet들이 사용할 수 있도록 Application Context를 만들어서 &amp;nbsp;이 Application Context를 Servlet Context에 &lt;span&gt;ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE라는 이름으로&amp;nbsp;&lt;/span&gt;등록해주고(*Servlet Context : Servlet 들이 사용할 수 있는 공용의 정보들을 모아두는 공간), Servlet Context가 종료될 시점에 제거해준다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1580627710747&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class ContextLoader {
	public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
    	
        // ...
        
		servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
        
        // ...
    }
}	        &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span&gt;&amp;nbsp;- ApplicationContext를 만들어야하기 때문에 Spring 설정파일이 필요하다. (기본으로는 xml 형태의 설정파일을 사용하지만 java 파일로도 설정파일을 만들 수 있다.)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- &lt;span style=&quot;color: #333333;&quot;&gt;ContextLoaderListener 가 AnnotationConfigWebApplicationContext를 만들 때, AppConfig를 이용해 만든다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;- 그러면 ApplicationContext 안에는 HelloService가 Bean으로 등록되어있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;- 만든 Servlet에서 &lt;span style=&quot;color: #333333;&quot;&gt;ApplicationContext 통해서 &lt;span style=&quot;color: #333333;&quot;&gt;HelloService를 꺼내 쓸 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;a. web.xml에 AnnotationConfigWebApplicationContext, AppConfigf를 파라미터로 한 ContextLoaderListener를 추가.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1580626580658&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE web-app PUBLIC
 &quot;-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN&quot;
 &quot;http://java.sun.com/dtd/web-app_2_3.dtd&quot; &amp;gt;

&amp;lt;web-app&amp;gt;
  &amp;lt;display-name&amp;gt;Archetype Created Web Application&amp;lt;/display-name&amp;gt;

  &amp;lt;!-- Parameter for ContextLoaderListener --&amp;gt;
  &amp;lt;!-- public static final String CONTEXT_CLASS_PARAM = &quot;contextClass&quot;; --&amp;gt;
  &amp;lt;context-param&amp;gt;
    &amp;lt;param-name&amp;gt;contextClass&amp;lt;/param-name&amp;gt;
    &amp;lt;param-value&amp;gt;org.springframework.web.context.support.AnnotationConfigWebApplicationContext&amp;lt;/param-value&amp;gt;
  &amp;lt;/context-param&amp;gt;

  &amp;lt;!-- Parameter for ContextLoaderListener --&amp;gt;
  &amp;lt;!-- public static final String CONFIG_LOCATION_PARAM = &quot;contextConfigLocation&quot;; --&amp;gt;
  &amp;lt;context-param&amp;gt;
    &amp;lt;param-name&amp;gt;contextConfigLocation&amp;lt;/param-name&amp;gt;
    &amp;lt;param-value&amp;gt;me.json.AppConfig&amp;lt;/param-value&amp;gt;
  &amp;lt;/context-param&amp;gt;

  &amp;lt;!-- Register a filter --&amp;gt;
  &amp;lt;filter&amp;gt;
    &amp;lt;filter-name&amp;gt;myFilter&amp;lt;/filter-name&amp;gt;
    &amp;lt;filter-class&amp;gt;me.json.MyFilter&amp;lt;/filter-class&amp;gt;
  &amp;lt;/filter&amp;gt;

  &amp;lt;!-- Mapping filter to servlet--&amp;gt;
  &amp;lt;filter-mapping&amp;gt;
    &amp;lt;filter-name&amp;gt;myFilter&amp;lt;/filter-name&amp;gt;
    &amp;lt;servlet-name&amp;gt;hello&amp;lt;/servlet-name&amp;gt;
  &amp;lt;/filter-mapping&amp;gt;

  &amp;lt;!-- Register Servlet Listener--&amp;gt;
  &amp;lt;!--&amp;lt;listener&amp;gt;--&amp;gt;
    &amp;lt;!--&amp;lt;listener-class&amp;gt;me.json.MyListener&amp;lt;/listener-class&amp;gt;--&amp;gt;
  &amp;lt;!--&amp;lt;/listener&amp;gt;--&amp;gt;

  &amp;lt;!-- Register ContextLoaderListener that is provided by Spring--&amp;gt;
  &amp;lt;!-- * contextClass(Parameter) : AnnotationConfigWebApplicationContext --&amp;gt;
  &amp;lt;!-- * contextConfigLocation(Parameter) : me.json.AppConfig --&amp;gt;
  &amp;lt;listener&amp;gt;
    &amp;lt;listener-class&amp;gt;org.springframework.web.context.ContextLoaderListener&amp;lt;/listener-class&amp;gt;
  &amp;lt;/listener&amp;gt;


  &amp;lt;!-- Register servlet --&amp;gt;
  &amp;lt;servlet&amp;gt;
    &amp;lt;servlet-name&amp;gt;hello&amp;lt;/servlet-name&amp;gt;
    &amp;lt;servlet-class&amp;gt;me.json.HelloServlet&amp;lt;/servlet-class&amp;gt;
  &amp;lt;/servlet&amp;gt;


  &amp;lt;!-- Mapping Servlet with url pattern --&amp;gt;
  &amp;lt;servlet-mapping&amp;gt;
    &amp;lt;servlet-name&amp;gt;hello&amp;lt;/servlet-name&amp;gt;
    &amp;lt;url-pattern&amp;gt;/hello&amp;lt;/url-pattern&amp;gt;
  &amp;lt;/servlet-mapping&amp;gt;

&amp;lt;/web-app&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;b. AppConfig.java 생성&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- ContextLoaderListner의 contextConfigLocation 파라미터로 사용됨&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- @ComponentScan을 이용해 bean 등록&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 과거에는 xml 파일로 많이 사용되었지만 요즘은 xml이 사용되지 않는 추세이므로 java 파일로 대체&lt;/p&gt;
&lt;pre id=&quot;code_1580628397181&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package me.json;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
public class AppConfig {
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;c. HelloService.java 생성&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1580628560147&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package me.json;

import org.springframework.stereotype.Service;

@Service
public class HelloService {

    public String getName(){
        return &quot;json&quot;;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;d. Servlet에서 ApplicationContext 가져오기 및 등록된 Bean(HelloService.class) 활용&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1580628614868&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package me.json;

import org.springframework.context.ApplicationContext;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

import static org.springframework.web.context.WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE;

public class HelloServlet extends HttpServlet {

    @Override
    public void init() throws ServletException {
        System.out.println(&quot;init&quot;);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // Get HelloService Bean that is registered in Application Context
        ApplicationContext context = (ApplicationContext) getServletContext().getAttribute(ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
        HelloService helloService = context.getBean(HelloService.class);

        System.out.println(&quot;doGet&quot;);
        resp.getWriter().print(&quot;&amp;lt;html&amp;gt;&quot;);
        resp.getWriter().print(&quot;&amp;lt;head&amp;gt;&quot;);
        resp.getWriter().print(&quot;&amp;lt;body&amp;gt;&quot;);
        resp.getWriter().print(&quot;&amp;lt;h1&amp;gt;Hello Servlet&amp;lt;/h1&amp;gt;&quot;);
        resp.getWriter().print(&quot;&amp;lt;h1&amp;gt;Hello&quot; + getName() + &quot;&amp;lt;/h1&amp;gt;&quot;);
        resp.getWriter().print(&quot;&amp;lt;h1&amp;gt;Hello&quot; + helloService.getName() + &quot;&amp;lt;/h1&amp;gt;&quot;);
        resp.getWriter().print(&quot;&amp;lt;/body&amp;gt;&quot;);
        resp.getWriter().print(&quot;&amp;lt;/head&amp;gt;&quot;);
        resp.getWriter().print(&quot;&amp;lt;/html&amp;gt;&quot;);
    }

    private Object getName() {
        // Get attribute value that is set in the Servlet listener
        return getServletContext().getAttribute(&quot;name&quot;);
    }

    @Override
    public void destroy() {
        System.out.println(&quot;destroy&quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.25em;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;1-2. 스프링이 제공하는 서블릿 구현체 DispatcherServlet을 사용하겠다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 서블릿을 만들때마다 web.xml에 설정이 늘어난다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 여러 서블릿에서 공통으로 처리하고 싶은 부분이 있는데, (filter로 처리할 수 있긴하지만) Front Controller라는 디자인 패턴이 있다.(모든 요청을 Controller 하나가 받아서 처리한다. 해당 요청을 처리할 핸들러들에게 분배(Dispatch)하는 패턴이다.)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- Spring이 Front Controller 역할을 하는 Servlet을 만들어 놓았는데 그것이 바로 DispatcherServlet이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;466&quot; height=&quot;426&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/T0v9w/btqBFNdo4JE/H91Q2r2WzYSERDmjRGLh21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/T0v9w/btqBFNdo4JE/H91Q2r2WzYSERDmjRGLh21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/T0v9w/btqBFNdo4JE/H91Q2r2WzYSERDmjRGLh21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FT0v9w%2FbtqBFNdo4JE%2FH91Q2r2WzYSERDmjRGLh21%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;466&quot; height=&quot;426&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- DispatcherServlet은 Root WebApplicationContext를 상속받아 새로운 Servlet WebApplicationContext를 만든다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- Root WebApplicationContext : ContextLoaderListener에 의해 ServletContext에 등록된 ApplicationContext로 모든 Servlet에서 사용 가능하다.(Services, Repositories Bean과 같이 다른 DispatcherServlet에서도 공용으로 사용 할 수 있다.)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- Servlet WebApplicationContext : DispatcherServlet에서 Root WebApplicationContext를 상속받아 만든 ApplicationContext로, 해당 DispatcherServlet에서만 사용가능하다. (해당 DispatcherServlet에 한정된 Controller, View 같은 Bean들이 등록된다.)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- DispatcherServlet 은 Front Controller 역할을 한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- /app 으로 시작하는 모든 요청은 DispatcherServlet을 통해 들어온다.&lt;/p&gt;
&lt;pre id=&quot;code_1580645770436&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE web-app PUBLIC
 &quot;-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN&quot;
 &quot;http://java.sun.com/dtd/web-app_2_3.dtd&quot; &amp;gt;

&amp;lt;web-app&amp;gt;
  &amp;lt;display-name&amp;gt;Archetype Created Web Application&amp;lt;/display-name&amp;gt;

  &amp;lt;!-- Parameter for ContextLoaderListener --&amp;gt;
  &amp;lt;!-- public static final String CONTEXT_CLASS_PARAM = &quot;contextClass&quot;; --&amp;gt;
  &amp;lt;context-param&amp;gt;
    &amp;lt;param-name&amp;gt;contextClass&amp;lt;/param-name&amp;gt;
    &amp;lt;param-value&amp;gt;org.springframework.web.context.support.AnnotationConfigWebApplicationContext&amp;lt;/param-value&amp;gt;
  &amp;lt;/context-param&amp;gt;

  &amp;lt;!-- Parameter for ContextLoaderListener --&amp;gt;
  &amp;lt;!-- public static final String CONFIG_LOCATION_PARAM = &quot;contextConfigLocation&quot;; --&amp;gt;
  &amp;lt;context-param&amp;gt;
    &amp;lt;param-name&amp;gt;contextConfigLocation&amp;lt;/param-name&amp;gt;
    &amp;lt;param-value&amp;gt;me.json.AppConfig&amp;lt;/param-value&amp;gt;
  &amp;lt;/context-param&amp;gt;
  
  
  &amp;lt;listener&amp;gt;
    &amp;lt;listener-class&amp;gt;org.springframework.web.context.ContextLoaderListener&amp;lt;/listener-class&amp;gt;
  &amp;lt;/listener&amp;gt;

  &amp;lt;servlet&amp;gt;
    &amp;lt;servlet-name&amp;gt;app&amp;lt;/servlet-name&amp;gt;
    &amp;lt;servlet-class&amp;gt;org.springframework.web.servlet.DispatcherServlet&amp;lt;/servlet-class&amp;gt;
    &amp;lt;init-param&amp;gt;
      &amp;lt;param-name&amp;gt;contextClass&amp;lt;/param-name&amp;gt;
      &amp;lt;param-value&amp;gt;org.springframework.web.context.support.AnnotationConfigWebApplicationContext&amp;lt;/param-value&amp;gt;
    &amp;lt;/init-param&amp;gt;
    &amp;lt;init-param&amp;gt;
      &amp;lt;param-name&amp;gt;contextConfigLocation&amp;lt;/param-name&amp;gt;
      &amp;lt;param-value&amp;gt;me.json.WebConfig&amp;lt;/param-value&amp;gt;
    &amp;lt;/init-param&amp;gt;
  &amp;lt;/servlet&amp;gt;

  &amp;lt;!-- Request that stars with /app/* will come in through DispatcherServlet--&amp;gt;
  &amp;lt;servlet-mapping&amp;gt;
    &amp;lt;servlet-name&amp;gt;app&amp;lt;/servlet-name&amp;gt;
    &amp;lt;url-pattern&amp;gt;/app/*&amp;lt;/url-pattern&amp;gt;
  &amp;lt;/servlet-mapping&amp;gt;

  
&amp;lt;/web-app&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1580645805867&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package me.json;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Controller;

@Configuration
// An applicationContext has this configuration include only Controller.class as a Bean without using default filters
@ComponentScan(useDefaultFilters = false, includeFilters = @ComponentScan.Filter(Controller.class))
public class WebConfig {
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;- DispatcherServlet 중에 /app/hello에 대해서는 HelloController 내 핸들러가 사용된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- &lt;span style=&quot;color: #333333;&quot;&gt;HelloController Bean은 DispatcherServlet 내 ApplicationContext에 등록이 되고, 이 ApplicationContext를 만들 때 DispatcherServlet은 현재 ServletContext에 들어있는 ContextLoaderListener가 만들어준 ApplicationContext를 &amp;nbsp;부모로 사용한다. 부모로 사용되는 ApplicationContext는 AppConfig.class를 갖고 만들어지고, 이는 Controller 빼고 모든 Bean을 등록하게 되어있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1580645457535&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package me.json;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Controller;

@Configuration
// An applicationContext has this configuration has defaultFilters as beans and excludes only Controller.class
@ComponentScan(excludeFilters = @ComponentScan.Filter(Controller.class))
public class AppConfig {
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;- 따라서 HelloService.class Bean이 등록되어 있을 것이고, 사용될 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1580645829524&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package me.json;

import org.springframework.stereotype.Service;

@Service
public class HelloService {

    public String getName(){
        return &quot;json&quot;;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.25em;&quot; data-ke-size=&quot;size18&quot;&gt;1-3. DispatcherServlet에 몰빵형&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 항상 이렇게 ApplicationContext에 다한 상속 구조 / 계층구조를 가져야만 하는 것은 아니고, 필요에따라 사용될 수 있다.(DispatcherServlet이 만드는 ApplicationContext에 모든 Bean을 등록할 수 도 있다.)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 이렇게 되면 Root WebApplicationContext가 따로 없고, DispatcherServlet이 만든 WebApplicationContext가 그냥 Root 처럼 모든 종류의 Bean 을 등록하게 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1580646077439&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package me.json;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
public class WebConfig {
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1580646020975&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE web-app PUBLIC
 &quot;-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN&quot;
 &quot;http://java.sun.com/dtd/web-app_2_3.dtd&quot; &amp;gt;

&amp;lt;web-app&amp;gt;
  &amp;lt;display-name&amp;gt;Web Application&amp;lt;/display-name&amp;gt;

  &amp;lt;servlet&amp;gt;
    &amp;lt;servlet-name&amp;gt;app&amp;lt;/servlet-name&amp;gt;
    &amp;lt;servlet-class&amp;gt;org.springframework.web.servlet.DispatcherServlet&amp;lt;/servlet-class&amp;gt;
    &amp;lt;init-param&amp;gt;
      &amp;lt;param-name&amp;gt;contextClass&amp;lt;/param-name&amp;gt;
      &amp;lt;param-value&amp;gt;org.springframework.web.context.support.AnnotationConfigWebApplicationContext&amp;lt;/param-value&amp;gt;
    &amp;lt;/init-param&amp;gt;
    &amp;lt;init-param&amp;gt;
      &amp;lt;param-name&amp;gt;contextConfigLocation&amp;lt;/param-name&amp;gt;
      &amp;lt;param-value&amp;gt;me.json.WebConfig&amp;lt;/param-value&amp;gt;
    &amp;lt;/init-param&amp;gt;
  &amp;lt;/servlet&amp;gt;

  &amp;lt;!-- Request that stars with /app/* will come in through DispatcherServlet--&amp;gt;
  &amp;lt;servlet-mapping&amp;gt;
    &amp;lt;servlet-name&amp;gt;app&amp;lt;/servlet-name&amp;gt;
    &amp;lt;url-pattern&amp;gt;/app/*&amp;lt;/url-pattern&amp;gt;
  &amp;lt;/servlet-mapping&amp;gt;


&amp;lt;/web-app&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;1-4. web.xml 없이 만들어보자!!(web.xml 없이 DispatcherServlet을 등록하는 방법)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- web.xml 지우기&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- WebApplicationInitializer 구현&lt;/p&gt;
&lt;pre id=&quot;code_1580651810342&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package me.json;

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

public class WebApplication implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
        context.register(WebConfig.class);
        context.refresh();

        DispatcherServlet dispatcherServlet = new DispatcherServlet(context);
        ServletRegistration.Dynamic app = servletContext.addServlet(&quot;app&quot;, dispatcherServlet);
        app.addMapping(&quot;/app/*&quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.25em;&quot; data-ke-size=&quot;size18&quot;&gt;2. 마치며&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 위의 구조는 SpringBoot와는 완전히 다른 구조이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 위의 구조는 Servlet Container가 먼저 뜨고, ServletContainer 안에 등록되는 Servlet Application에다가 (ContextLoaderListener를 등록한다던가 DispatcherServlet을 등록한다던가 해서)Spring을 연동하는 방식이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- SpringBoot의 경우에는 Spring Boot Application 이 Java Application으로 먼저 뜨고, 그 안에 tomcat이 내장 서버로 뜬다. (DispatcherServlet 같은)Servlet을 내장 톰켓 안에다가 코드로 등록한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #666666;&quot;&gt;[참고] Inflearn 백기선의 스프링 웹 MVC 기반으로 저같은 초보들이 알기 쉽도록 재구성 해보았습니다., (매우 유용하고 친절한 강의라고 생각합니다. 들으시면 기본적인 구조나 원래를 익히는데 도움이 되실 것 같습니다!! 20% 할인하는 기간도 간간히 있으니 잘 활용하세용~)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>#Spring</category>
      <author>뚱보리루</author>
      <guid isPermaLink="true">https://jsonsang2.tistory.com/52</guid>
      <comments>https://jsonsang2.tistory.com/52#entry52comment</comments>
      <pubDate>Sun, 2 Feb 2020 20:10:18 +0900</pubDate>
    </item>
    <item>
      <title>3. Servlet (써블릿) - 써블릿 리스터와 필터</title>
      <link>https://jsonsang2.tistory.com/51</link>
      <description>&lt;p style=&quot;font-size: 1.25em;&quot; data-ke-size=&quot;size18&quot;&gt;1. 서블릿 리스너&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 웹 애플리케이션에서 발생하는 주요 이벤트를 감지하고 각 이벤트에 특별한 작업이 필요한 경우에 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 서블릿 컨테이너에서 발생하는 이벤트(서블릿 라이크사이클의 변화, 애트리뷰트의 변화, 세션의 변화)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 여러개의 서블릿이 공톡적으로 사용할 객체들을 넣어놓는 등의 목적으로 사용할 수 있다.(DB 연결 등)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.25em;&quot; data-ke-size=&quot;size18&quot;&gt;2. 서블릿 필터&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 요청이 서블릿의 doGet으로 바로가기 전에 전처리 및 응답에 처리를 하기위해서 사용.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 들어온 요청을 서블릿으로 보내고 또 서블릿이 작성한 응답을 클라이언트로 보내기 전에 특별한 처리가 필요한 경우에 사용된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 체인 형태의 구조를 갖는다.(순차적으로 적용된다, 반드시 다음 체인으로 넘어가도록 코드를 작성해줘야 한다.)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.25em;&quot; data-ke-size=&quot;size18&quot;&gt;3. 서블릿 리스너 실습&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- Servlet Listener 생성&lt;/p&gt;
&lt;pre id=&quot;code_1580625151807&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package me.json;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class MyListener implements ServletContextListener {

    // Servlet Context 의 Lifecycle 을 감지할 수 있는 interface 구현
    // Override interfaces those can detect lifecycle of Servlet Context
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println(&quot;Context Listener Initialized&quot;);
        sce.getServletContext().setAttribute(&quot;name&quot;, &quot;json&quot;);
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println(&quot;Context Destroyed&quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- web.xml에 Servlet listener 등록&lt;/p&gt;
&lt;pre id=&quot;code_1580625174591&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE web-app PUBLIC
 &quot;-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN&quot;
 &quot;http://java.sun.com/dtd/web-app_2_3.dtd&quot; &amp;gt;

&amp;lt;web-app&amp;gt;
  &amp;lt;display-name&amp;gt;Archetype Created Web Application&amp;lt;/display-name&amp;gt;

  &amp;lt;!-- Register Servlet Listener--&amp;gt;
  &amp;lt;listener&amp;gt;
    &amp;lt;listener-class&amp;gt;me.json.MyListener&amp;lt;/listener-class&amp;gt;
  &amp;lt;/listener&amp;gt;


  &amp;lt;!-- Register servlet --&amp;gt;
  &amp;lt;servlet&amp;gt;
    &amp;lt;servlet-name&amp;gt;hello&amp;lt;/servlet-name&amp;gt;
    &amp;lt;servlet-class&amp;gt;me.json.HelloServlet&amp;lt;/servlet-class&amp;gt;
  &amp;lt;/servlet&amp;gt;


  &amp;lt;!-- Mapping Servlet with url pattern --&amp;gt;
  &amp;lt;servlet-mapping&amp;gt;
    &amp;lt;servlet-name&amp;gt;hello&amp;lt;/servlet-name&amp;gt;
    &amp;lt;url-pattern&amp;gt;/hello&amp;lt;/url-pattern&amp;gt;
  &amp;lt;/servlet-mapping&amp;gt;

&amp;lt;/web-app&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- Servlet에서 listener 활용&lt;/p&gt;
&lt;pre id=&quot;code_1580625268553&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package me.json;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class HelloServlet extends HttpServlet {

    @Override
    public void init() throws ServletException {
        System.out.println(&quot;init&quot;);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println(&quot;doGet&quot;);
        resp.getWriter().print(&quot;&amp;lt;html&amp;gt;&quot;);
        resp.getWriter().print(&quot;&amp;lt;head&amp;gt;&quot;);
        resp.getWriter().print(&quot;&amp;lt;body&amp;gt;&quot;);
        resp.getWriter().print(&quot;&amp;lt;h1&amp;gt;Hello Servlet&amp;lt;/h1&amp;gt;&quot;);
        resp.getWriter().print(&quot;&amp;lt;h1&amp;gt;Hello&quot; + getName() + &quot;&amp;lt;/h1&amp;gt;&quot;);
        resp.getWriter().print(&quot;&amp;lt;/body&amp;gt;&quot;);
        resp.getWriter().print(&quot;&amp;lt;/head&amp;gt;&quot;);
        resp.getWriter().print(&quot;&amp;lt;/html&amp;gt;&quot;);
    }
    
    private Object getName() {
        // Get attribute value that is set in the Servlet listener
        return getServletContext().getAttribute(&quot;name&quot;);
    }

    @Override
    public void destroy() {
        System.out.println(&quot;destroy&quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.25em;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;4. 서블릿 필터 실습&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 서블릿 필터 생성&lt;/p&gt;
&lt;pre id=&quot;code_1580626136067&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package me.json;

import javax.servlet.*;
import java.io.IOException;

public class MyFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println(&quot;Filter Initialized&quot;);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println(&quot;doFilter : MyFilter&quot;);

        // Have to connect to next filter(if this is last filter this will be connected to servlet) : Chaining
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {
        System.out.println(&quot;Filter Destroyed&quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;font-size: 1.12em;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- web.xml에 서블릿 필터 등록&lt;/p&gt;
&lt;pre id=&quot;code_1580626151957&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE web-app PUBLIC
 &quot;-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN&quot;
 &quot;http://java.sun.com/dtd/web-app_2_3.dtd&quot; &amp;gt;

&amp;lt;web-app&amp;gt;
  &amp;lt;display-name&amp;gt;Archetype Created Web Application&amp;lt;/display-name&amp;gt;

  &amp;lt;!-- Register a filter --&amp;gt;
  &amp;lt;filter&amp;gt;
    &amp;lt;filter-name&amp;gt;myFilter&amp;lt;/filter-name&amp;gt;
    &amp;lt;filter-class&amp;gt;me.json.MyFilter&amp;lt;/filter-class&amp;gt;
  &amp;lt;/filter&amp;gt;


  &amp;lt;!-- Mapping filter to servlet--&amp;gt;
  &amp;lt;filter-mapping&amp;gt;
    &amp;lt;filter-name&amp;gt;myFilter&amp;lt;/filter-name&amp;gt;
    &amp;lt;servlet-name&amp;gt;hello&amp;lt;/servlet-name&amp;gt;
  &amp;lt;/filter-mapping&amp;gt;

  &amp;lt;!-- Register Servlet Listener--&amp;gt;
  &amp;lt;listener&amp;gt;
    &amp;lt;listener-class&amp;gt;me.json.MyListener&amp;lt;/listener-class&amp;gt;
  &amp;lt;/listener&amp;gt;


  &amp;lt;!-- Register servlet --&amp;gt;
  &amp;lt;servlet&amp;gt;
    &amp;lt;servlet-name&amp;gt;hello&amp;lt;/servlet-name&amp;gt;
    &amp;lt;servlet-class&amp;gt;me.json.HelloServlet&amp;lt;/servlet-class&amp;gt;
  &amp;lt;/servlet&amp;gt;


  &amp;lt;!-- Mapping Servlet with url pattern --&amp;gt;
  &amp;lt;servlet-mapping&amp;gt;
    &amp;lt;servlet-name&amp;gt;hello&amp;lt;/servlet-name&amp;gt;
    &amp;lt;url-pattern&amp;gt;/hello&amp;lt;/url-pattern&amp;gt;
  &amp;lt;/servlet-mapping&amp;gt;

&amp;lt;/web-app&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.25em;&quot; data-ke-size=&quot;size18&quot;&gt;5. 결과&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 아래와 같이 , Context Listener Init과 Filter Init은 호출이 없어도 먼저 호출된다. 해당 이유는 Init 할때 오래 걸릴 수 있는 시간을 미리 1회 호출해 둠으로써 Init 과정을 완료시켜버린다. 이를 '웜업' 이라고 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b087ke/btqBEA6TK59/hhhhXj9JuybzUWObhzXrv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b087ke/btqBEA6TK59/hhhhXj9JuybzUWObhzXrv0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b087ke/btqBEA6TK59/hhhhXj9JuybzUWObhzXrv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb087ke%2FbtqBEA6TK59%2FhhhhXj9JuybzUWObhzXrv0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #666666;&quot;&gt;[참고] Infrean 백기선의 스프링 웹 MVC 기반으로 저같은 초보들이 알기 쉽도록 재구성 해보았습니다., (매우 유용하고 친절한 강의라고 생각합니다. 들으시면 기본적인 구조나 원래를 익히는데 도움이 되실 것 같습니다!! 20% 할인하는 기간도 간간히 있으니 잘 활용하세용~)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>#Spring</category>
      <author>뚱보리루</author>
      <guid isPermaLink="true">https://jsonsang2.tistory.com/51</guid>
      <comments>https://jsonsang2.tistory.com/51#entry51comment</comments>
      <pubDate>Sun, 2 Feb 2020 15:49:29 +0900</pubDate>
    </item>
    <item>
      <title>2. Servlet (써블릿) - 원시적인 코드로 확인</title>
      <link>https://jsonsang2.tistory.com/50</link>
      <description>&lt;p style=&quot;font-size: 1.25em;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. 준비&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- Maven : maven-archetype-webapp&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;664&quot; height=&quot;572&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHRdfE/btqBD1XVVE1/aO1j58hkRpp2gJsYsxBPAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHRdfE/btqBD1XVVE1/aO1j58hkRpp2gJsYsxBPAk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHRdfE/btqBD1XVVE1/aO1j58hkRpp2gJsYsxBPAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcHRdfE%2FbtqBD1XVVE1%2FaO1j58hkRpp2gJsYsxBPAk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;664&quot; height=&quot;572&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 톰켓&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- Servlet dependency&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api/4.0.1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api/4.0.1&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1580620996217&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Maven Repository: javax.servlet &amp;raquo; javax.servlet-api &amp;raquo; 4.0.1&quot; data-og-description=&quot;Professional Java Data: RDBMS, JDBC, SQLJ, OODBMS, JNDI, LDAP, Servlets, JSP, WAP, XML, EJBs, CMP2.0, JDO, Transactions, Performance, Scalability, Object and Data Modeling (2001)by Carl Calvert Bettis, Michael Bogovich, Sean Rhody, Mark Wilcox, Kelly Lin P&quot; data-og-host=&quot;mvnrepository.com&quot; data-og-source-url=&quot;https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api/4.0.1&quot; data-og-url=&quot;https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api/4.0.1&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api/4.0.1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api/4.0.1&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;Maven Repository: javax.servlet &amp;raquo; javax.servlet-api &amp;raquo; 4.0.1&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;Professional Java Data: RDBMS, JDBC, SQLJ, OODBMS, JNDI, LDAP, Servlets, JSP, WAP, XML, EJBs, CMP2.0, JDO, Transactions, Performance, Scalability, Object and Data Modeling (2001)by Carl Calvert Bettis, Michael Bogovich, Sean Rhody, Mark Wilcox, Kelly Lin P&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;mvnrepository.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;span&gt;&amp;lt;dependency&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt; &amp;lt;groupId&amp;gt;&lt;/span&gt;javax.servlet&lt;span&gt;&amp;lt;/groupId&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt; &amp;lt;artifactId&amp;gt;&lt;/span&gt;javax.servlet-api&lt;span&gt;&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt; &amp;lt;version&amp;gt;&lt;/span&gt;4.0.1&lt;span&gt;&amp;lt;/version&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt; &amp;lt;scope&amp;gt;&lt;/span&gt;provided&lt;span&gt;&amp;lt;/scope&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;* privided scope : 코딩하는 시점에는 사용할 수 있지만 프로젝트 패키징 할때는 프로젝트에서 빠짐(해당 의존성은 어디선가에서 제공됨---&amp;gt; 톰켓 컨테이너에서 제공됨)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.25em;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;2. 서블릿 생성&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&amp;nbsp;- Servelt 생성&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1580623532758&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package me.json;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class HelloServlet extends HttpServlet {

    @Override
    public void init() throws ServletException {
        System.out.println(&quot;init&quot;);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println(&quot;doGet&quot;);
        resp.getWriter().print(&quot;&amp;lt;html&amp;gt;&quot;);
        resp.getWriter().print(&quot;&amp;lt;head&amp;gt;&quot;);
        resp.getWriter().print(&quot;&amp;lt;body&amp;gt;&quot;);
        resp.getWriter().print(&quot;&amp;lt;h1&amp;gt;Hello Servlet&amp;lt;/h1&amp;gt;&quot;);
        resp.getWriter().print(&quot;&amp;lt;/body&amp;gt;&quot;);
        resp.getWriter().print(&quot;&amp;lt;/head&amp;gt;&quot;);
        resp.getWriter().print(&quot;&amp;lt;/html&amp;gt;&quot;);
    }

    @Override
    public void destroy() {
        System.out.println(&quot;destroy&quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span&gt;&amp;nbsp;- webapp/WEB-INF/web.xml 설정&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1580623560118&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE web-app PUBLIC
 &quot;-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN&quot;
 &quot;http://java.sun.com/dtd/web-app_2_3.dtd&quot; &amp;gt;

&amp;lt;web-app&amp;gt;
  &amp;lt;display-name&amp;gt;Archetype Created Web Application&amp;lt;/display-name&amp;gt;


  &amp;lt;!-- Register servlet --&amp;gt;
  &amp;lt;servlet&amp;gt;
    &amp;lt;servlet-name&amp;gt;hello&amp;lt;/servlet-name&amp;gt;
    &amp;lt;servlet-class&amp;gt;me.json.HelloServlet&amp;lt;/servlet-class&amp;gt;
  &amp;lt;/servlet&amp;gt;


  &amp;lt;!-- Mapping Servlet with url pattern --&amp;gt;
  &amp;lt;servlet-mapping&amp;gt;
    &amp;lt;servlet-name&amp;gt;hello&amp;lt;/servlet-name&amp;gt;
    &amp;lt;url-pattern&amp;gt;/hello&amp;lt;/url-pattern&amp;gt;
  &amp;lt;/servlet-mapping&amp;gt;

&amp;lt;/web-app&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.25em;&quot; data-ke-size=&quot;size18&quot;&gt;3. 서블릿 실행&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 서블릿 독자적으로 실행할 수 있는 방법은 없다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 서블릿 컨테이너(톰켓)에 배포하는 식으로 실행을 해야한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1411&quot; data-filename=&quot;blob&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eghSEZ/btqBEA6Sg3f/pYEbzLM8p51zKJkbPvnZe1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eghSEZ/btqBEA6Sg3f/pYEbzLM8p51zKJkbPvnZe1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eghSEZ/btqBEA6Sg3f/pYEbzLM8p51zKJkbPvnZe1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeghSEZ%2FbtqBEA6Sg3f%2FpYEbzLM8p51zKJkbPvnZe1%2Fimg.png&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1411&quot; data-filename=&quot;blob&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 우측 상단 Add confituration... -&amp;gt; Tomcet Server -&amp;gt; Local 선택&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- Tomcat 설치 및 설치 폴더 내 *.sh 파일에 실행권한 부여(chmod +x ./bin/*.sh)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mY56g/btqBFv47cYW/OjwTbyjlkNxfUusAUfj4t0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mY56g/btqBFv47cYW/OjwTbyjlkNxfUusAUfj4t0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mY56g/btqBFv47cYW/OjwTbyjlkNxfUusAUfj4t0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmY56g%2FbtqBFv47cYW%2FOjwTbyjlkNxfUusAUfj4t0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;- Tomcat Delpoyment 설정에 war:exploded 추가&lt;/p&gt;
&lt;p&gt;&amp;nbsp;: 배포를 하는데 톰켓을 띄울 때 해당 애플리케이션을 war로 묶어서 배포하는 방법(:war)이 있고, war를 압축을 풀어버린 상태로 톰켓에 배포(:war:exploded)하는 방식이 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cloPr1/btqBEBLyO5l/49H9gn7EBkF1Brb1dnWyBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cloPr1/btqBEBLyO5l/49H9gn7EBkF1Brb1dnWyBK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cloPr1/btqBEBLyO5l/49H9gn7EBkF1Brb1dnWyBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcloPr1%2FbtqBEBLyO5l%2F49H9gn7EBkF1Brb1dnWyBK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3XNE4/btqBFNErVIr/J3FBmYwYaIKFTvlrGBhZ30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3XNE4/btqBFNErVIr/J3FBmYwYaIKFTvlrGBhZ30/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3XNE4/btqBFNErVIr/J3FBmYwYaIKFTvlrGBhZ30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3XNE4%2FbtqBFNErVIr%2FJ3FBmYwYaIKFTvlrGBhZ30%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;- 해당 설정을 하면 application context가 설정이 되고, Server 탭에 앱이 떴을때의 기본 url로 설정된다.&lt;/p&gt;
&lt;p&gt;- url 이 굉장히 길어서, Deployment/Application Context를 root(/)로 설정하기도 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGuetr/btqBG0iNBAZ/HkkovQCLotAB6AUJYTOEQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGuetr/btqBG0iNBAZ/HkkovQCLotAB6AUJYTOEQk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGuetr/btqBG0iNBAZ/HkkovQCLotAB6AUJYTOEQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGuetr%2FbtqBG0iNBAZ%2FHkkovQCLotAB6AUJYTOEQk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;font-size: 1.25em;&quot; data-ke-size=&quot;size18&quot;&gt;4. 마치며..&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- Spring MVC가 이 httpServlet 기반으로 만들어 졌는데,&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 어떻게 애노테이션(@Controller, @RequestMapping)을 사용해서 요청을 처리 할 수 있나?&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 어떻게 뷰를 println으로 찍는게 아니라 thymeleaf 사용할 수 있나?&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 어떻게 web.xml 없이 Servlet Application을 띄울 수 있었나?&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #666666;&quot;&gt;[참고] Infrean 백기선의 스프링 웹 MVC 기반으로 저같은 초보들이 알기 쉽도록 재구성 해보았습니다., (매우 유용하고 친절한 강의라고 생각합니다. 들으시면 기본적인 구조나 원래를 익히는데 도움이 되실 것 같습니다!! 20% 할인하는 기간도 간간히 있으니 잘 활용하세용~)&lt;/span&gt;&lt;/p&gt;</description>
      <category>#Spring</category>
      <author>뚱보리루</author>
      <guid isPermaLink="true">https://jsonsang2.tistory.com/50</guid>
      <comments>https://jsonsang2.tistory.com/50#entry50comment</comments>
      <pubDate>Sun, 2 Feb 2020 15:10:24 +0900</pubDate>
    </item>
    <item>
      <title>1. Servlet (써블릿) - 기본 설명</title>
      <link>https://jsonsang2.tistory.com/49</link>
      <description>&lt;p&gt;스프링 웹 엠브씨는 서블릿 기반의 웹 애플리케이션을 쉽게 만들게 도와주는 프레임워크이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그렇담 서블릿은?&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 자바 엔터프라이즈 에디션은 웹 애플리케이션 개발용 스펙과 API를 제공한다.(ex, HttpServlet)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 하나의 요청을 받을 때마다 쌔로운 쓰레드를 만들어서(혹은 풀에서 가져다가) 요청을 처리(CGI같은 기술에 비해 훨씬 빠르고, OS에 플랫폼 독립적인 JAVA 본연의 기능을 지원받을 수 있다.).&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;그렇담 서블릿 컨테이너(서블릿 엔진)은?&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 톰켓, 제티, 언더토우&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 서블릿 스펙을 준수, 구현하는 컨테이너들&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 서블릿을 어떻게 초기화하고, 실행하고, 사용하는지의 서블릿의 라이프사이클을 관리.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 세션, 네트워크 관리&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 서블릿 애플리케이션은 우리가 직접 실행할 수 없고, 서블릿 컨테이너가 실행할 수 있기 때문에 반드시 서블릿 컨테이너를 사용해야한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;서블릿 생명주기&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 서블릿 컨테이너가 최초 요청을 받고,&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 해당 요청을 처리 할 서블릿을 찾아 서블릿 인스턴스를 만든다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 최초로 서블릿을 호출(init, 추후 동일한 요청에서 부터는 호출이 안된다.(웜업))&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- doGet, doPost 등이 호출&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 서블릿 컨테이너가 종료할 때 destroy() 호출&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;서블릿 애플리케이션을 만들어서 톰켓에 띄워보자&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #666666;&quot;&gt;[참고] Infrean 백기선의 스프링 웹 MVC 기반으로 저같은 초보들이 알기 쉽도록 재구성 해보았습니다., (매우 유용하고 친절한 강의라고 생각합니다. 들으시면 기본적인 구조나 원래를 익히는데 도움이 되실 것 같습니다!! 20% 할인하는 기간도 간간히 있으니 잘 활용하세용~)&lt;/span&gt;&lt;/p&gt;</description>
      <category>#Spring</category>
      <author>뚱보리루</author>
      <guid isPermaLink="true">https://jsonsang2.tistory.com/49</guid>
      <comments>https://jsonsang2.tistory.com/49#entry49comment</comments>
      <pubDate>Sun, 2 Feb 2020 14:14:44 +0900</pubDate>
    </item>
    <item>
      <title>Dispatcher Servlet의 동작원리</title>
      <link>https://jsonsang2.tistory.com/48</link>
      <description>&lt;p&gt;&lt;b&gt;- 용어&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- HandlerMapper : Handler를 찾아주는 인터페이스&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- HandlerAdaptor : Handler를 수행해주는 인터페이스&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- View Resolver : View 이름(String 값)을 갖고 실제 매핑되는 View 파일(리소스)을 찾아 변환하는 인터페이스.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- 구성&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&amp;nbsp;1. &amp;nbsp;MultipartResolver interface &lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;: 파일 업로드 요청 처리에 필요한 인터페이스(http 요청에서 content-type : multipart 은 경우, 바이너리로 쪼개져서 날아오는 파일들을 받기위한 처리 작업을 한 것으로 예상, HttpServletRequest -&amp;gt; MultipartHttpServletRequest로 변환)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;: DispatcherServlet에는 DefaultStratage로 등록된 Bean은 없고, SpringBoot에서는 StandardServletMultipartResolver가 기본으로 등록된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;2. LocaleResolver&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;: Client 위치 정보, 지역정보를 확인하는데 사용됨. --&amp;gt; 지역에 따라 적절한 지역언어의 메시지로 화면을 전달하기 위함&lt;/p&gt;
&lt;p&gt;&amp;nbsp;: DispatcherServlet 기준으로 기본등록되는 구현체는 AcceptHeaderLocaleResolver이다(요청에 들어있는 accept-language header 값으로 파악).&lt;/p&gt;
&lt;p&gt;&amp;nbsp;: MultipartResolver, LocaleResolver는 요청이 Dispatcher servlet에 들어왔을때, 요청을 분석하는데 사용됨.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;3. ThemeResolver&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;: 애플리케이션에서 설정 테마를 파악하고 변경할 수 있는 인터페이스&lt;/p&gt;
&lt;p&gt;&amp;nbsp;: Theme이라는 키값을 view에 전달하고, view에서 key 값에 맞는 css 등을 불러와서 적용시키는 기능.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;4. HandlerMapping&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;: 어떤 요청이 들어왔을 때, 그 요청을 처리할 Handler를 찾는 인터페이스.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;: 기본 구현체 1) RequestMappingHandlerMapping은 애노테이션 기반으로 핸들러를 찾아준다. 이 경우에는 method 자체가 핸들러가 된다.(&lt;span style=&quot;color: #ee2323;&quot;&gt;* @Controller 같은 애노테이션을 이용해 핸들러를 만들 수 있는 이유는 기본적으로 해당 HandlerMapping이 등록되어 있기 때문이다.)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;: 기본 구현체 2) BeanNameUrlHandlerMapping은 빈 이름 기반으로 이 요청에 해당하는 Bean이 있는가를 찾는다. 이 경우에는 Class가 핸들러가 된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;5. HandlerAdaptor&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;: HandlerMaaping이 찾아낸 (마음대로, 제멋대로 생긴) 핸들러를 처리하는 인터페이스&lt;/p&gt;
&lt;p&gt;&amp;nbsp;: Spring MVC 확장력의 핵심 : 핸들러를 원하는대로 커스텀 해서 만들 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;: 기본 구현체 1) RequestMappingHandlerAdaptor 가 등록됨(&lt;span style=&quot;color: #333333;&quot;&gt;RequestMappingHandlerMapping 와 세트를 이루면 작동)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;: 2) HttpRequestHandlerAdaptor, 3) SimpleControllerHandlerAdaptor&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;6. HandlerExceptionResolver&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;: DispatcherServlet 실행 중에 전반적으로 일어나는 예외들에 대해서 해당 예외에 따라 맞는 예외처리를 해준다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;: 기본으로 ExceptionHandlerExceptionResolver를 주로 사용할 것 : @ExceptionHandler 애노테이션에 따른 동작을 한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;* &lt;span style=&quot;color: #333333;&quot;&gt;HandlerMapping, &lt;span style=&quot;color: #333333;&quot;&gt;HandlerAdaptor, &lt;span style=&quot;color: #333333;&quot;&gt;HandlerExceptionResolver 는 Collection으로 복수개의 구현체를 갖고 있으며 이를 순회하며 작동한다. 또한 @Order 를 사용한 순회 순서도 정해질 수 있다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;7. &lt;span style=&quot;color: #333333;&quot;&gt;RequestToViewNameTranslator&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;: 핸들러에서 뷰 이름을 명시적으로 리턴하지 않는 경우(핸들러 매서드 반환타입이 void인 경우 등), 요청 기반으로 뷰 이름을 판단하는 인터페이스&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;: 기본 구현체는 Defualt&lt;span style=&quot;color: #333333;&quot;&gt;RequestToViewNameTranslator 하나이고, url과 동일하게 view 네임으로 사용하는 것으로 예상.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;8. ViewResolver&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;: 명시적으로 view 이름을 가져오든, &lt;span style=&quot;color: #333333;&quot;&gt;RequestToViewNameTranslator를 통해서 view 이름을 추측하든 View 이름을 가져온 후, 이름을 갖고 실제 View를 찾아내는 인터페이스.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;: DispatcherServlet 기준으로 기본적으로 InternalResourceViewResolver가 등록되어있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;: SpringBoot에는 더 많은 구현체가 기본적으로 등록되어 있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;9. FlashMapResolver&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;: 어떤 데이터를 받고, 저장한 후 그 다음에 보통 리다이렉트를 하는데, &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;: 왜? 화면에서 refresh 했을 때 같은 요청을 반복하면 동일한 데이터가 반복해서 넘어온다. 이를 방지하기 위한 패턴&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;: 사실 뭔지 잘 모르겠다. 중복 from submission을 방지하기 위한 패턴.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- 응용&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- Spring MVC가 기본적으로 갖고있는 Handler Mapping에는 &lt;b&gt;1.&amp;nbsp;&lt;/b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;BeanNameUrlHandlerMapping&lt;/b&gt;(&lt;span style=&quot;color: #000000;&quot;&gt;요청한 url과 빈의 이름이 일치하는 빈을 찾아준다.)&lt;/span&gt;&lt;b&gt;, 2. &lt;b&gt;RequestMappingHandlerMapping&lt;/b&gt;&lt;/b&gt;(&lt;span style=&quot;color: #000000;&quot;&gt;@RequestMapping이라는 애노테이션을 컨트롤러 클래스나 메서드에 선언하여 사용)&lt;/span&gt;가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;- View Resolver 동작 원리&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;: org.springframework.web.servlet.DispatcherServlet Class 에 servlet을 초기화하는 protected void initStrategies(ApplicationContext context) 내 initViewResolver(context); 수행.(이는 매 요청마다 수행되는 것이 아니라 최초 dispatcher servlet을 초기화 하기위해 한번만 호출된다.)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;: 등록된 Bean에서 ViewResolver.class 타입의 Bean을 모두 찾아와서 veiwResolvers List에 넣어둔다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;: 만약 개발자가 등록한 ViewResolver.class 타입의 Bean이 없다면, getDefaultStrategies(context, ViewResolver.class) 수행을 통해서 기본 전략을 가져온다. 이 기본 전략에 internalResourceViewResolver가 들어있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;: 이는 DispatcherServlet.properties 라는 파일에서 기본전략으로 가져올 내용들을 관리한다. HandlerMapper의 경우에도 이와 마찬가지로 해당 파일에 BeanNameUrlHandlerMapping과 RequestMappingHandlerMapping 값을 갖고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- DispatcherServlet.properties&lt;/p&gt;
&lt;pre id=&quot;code_1580652000764&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.

org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver

org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\
	org.springframework.web.servlet.function.support.RouterFunctionMapping

org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
	org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\
	org.springframework.web.servlet.function.support.HandlerFunctionAdapter


org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
	org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
	org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver

org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator

org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #000000;&quot;&gt;[참고] Infrean 백기선의 스프링 웹 MVC, (매우 유용하고 친절한 강의라고 생각합니다. 들으시면 기본적인 구조나 원래를 익히는데 도움이 되실 것 같습니다!! 20% 할인하는 기간도 간간히 있으니 잘 활용하세용~)&lt;/span&gt;&lt;/p&gt;</description>
      <category>#Spring</category>
      <author>뚱보리루</author>
      <guid isPermaLink="true">https://jsonsang2.tistory.com/48</guid>
      <comments>https://jsonsang2.tistory.com/48#entry48comment</comments>
      <pubDate>Sun, 2 Feb 2020 13:38:59 +0900</pubDate>
    </item>
  </channel>
</rss>