<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>구찌의 나도한번 해블로그</title>
    <link>https://koocci-dev.tistory.com/</link>
    <description>개발 노트 및 학습 블로그입니다.</description>
    <language>ko</language>
    <pubDate>Sun, 31 May 2026 14:43:25 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>KOOCCI</managingEditor>
    <image>
      <title>구찌의 나도한번 해블로그</title>
      <url>https://tistory1.daumcdn.net/tistory/3125665/attach/5a6ed6d6ee3341cba9ef6d7abab8befe</url>
      <link>https://koocci-dev.tistory.com</link>
    </image>
    <item>
      <title>서버 이중화의 종류는 무엇이 있을까?</title>
      <link>https://koocci-dev.tistory.com/82</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 :&amp;nbsp; 서버 이중화 종류에 대해 설명할 수 있다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VM 환경에서는 상용 서버에 대해 이중화 이상을 적용하는 것이 바람직하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 서버가 죽더라도 다른 서버가 적절히 실행되어 서비스가 중단이 없어야 하기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 종류는 사실 다양하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;API 서버의 경우, 부하 분산 등을 생각해 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Active-Active&lt;/b&gt;&lt;/span&gt; 구조로 설정될 수 있지만, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Active-standby&lt;/b&gt;&lt;/span&gt;나, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;master-slave&lt;/b&gt;&lt;/span&gt; 구조를 가지는 것도 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이런 종류들에 대해 정리해 보도록하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Active-Active 구조&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Active 서버&lt;/b&gt;&lt;/span&gt;의 기준은 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;현재 정상 동작하고 있는가?&lt;/b&gt;&lt;/span&gt; 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부하를 분산시켜 줄 수 있는 L4 스위치 등 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;LoadBalancer&lt;/b&gt;&lt;/span&gt;가 있고, Active 서버에 요청을 적절히 분배한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 부하에 따라, Active 서버의 갯수를 늘리며, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Scale-Out&lt;/b&gt;&lt;/span&gt;을 시킬 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2대 이상으로 구성된 Active-Active 구조에서는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;한 서버가 장애가 나더라도, 지속 운영이 가능하고 Down되는 시간이 없다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매우 좋아보이지만, 특정 상황에서는 쉽지 않은 경우도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들면, DB 서버의 경우, 지원하는 DBMS도 적고, Active-Active 상황이다 보니, 그만큼 스토리지에 대해서 &lt;b&gt;병목 현상이 발생할 수 있다&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Active-Standby 구조&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Standby 서버&lt;/b&gt;&lt;/span&gt;의 기준은 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Active 서버를 대신할 수 있는가?&lt;/b&gt;&lt;/span&gt; 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Active 중이던 서버가 장애가 발생하는 등, 어떤 이벤트가 발생했을 때 Active 서버 대신해서 Request를 받아 낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통, Application의 HeartBeat를 측정하는 솔루션이 있어서, 이벤트 발생 시, Active서버를 전환시키거나 수동으로 처리하는 경우가 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들면 DB 서버가 있다고 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용하고자 하는 DBMS가 Active-Active를 지원하지 않아서, Storage를 공유하는 2대의 DB 서버는 Active-Standby로 구성되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;특정 솔루션에서는 Active 서버의 상태를 확인하다가 장애가 났을 때(failover), Standby 서버로 전환해준다.&lt;/b&gt;&lt;/span&gt; (수초에서 수분 소요될 수 있음)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전환되는 시간이 소요되어, 그 시간동안은 이슈인 상황이지만 그래도 에러 상황을 빠르게 복구시킬 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 standby 서버에는 실제로 요청이 들어오는 경우가 거의 없으므로, Active 서버만 동작하기 때문에 동기화에 큰 무리가 따르지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Master-Slave 구조&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이번엔 조금 다른 개념으로 넘어왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Master 서버&lt;/b&gt;&lt;/span&gt;의 기준은 CUD가 가능하다는 것이다. 그에 비해, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Slave 서버&lt;/b&gt;&lt;/span&gt;는 Read가 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역할이 달라지는 것이며, 그에 따라 트래픽이 분산될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Master는 데이터 동시성이 아주 높은 트랜잭션을 담당하고, Slave는 데이터 동시성이 꼭 필요없는 경우에 읽기 전용으로 데이터를 가져온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;Master가 Slave에게 데이터를 알려주는 구조는 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Master DB에 Data가 변경될 시, Master DB에 반영&lt;/li&gt;
&lt;li&gt;변경 이력을 Binary Log로 저장&lt;/li&gt;
&lt;li&gt;Slave DB에게 이벤트 전송&lt;/li&gt;
&lt;li&gt;Slave IO Thread에서 이벤트를 받고, Binary Log를 Slave DB 각각의 Relay Log에 저장&lt;/li&gt;
&lt;li&gt;Slave SQL Thread에서 Relay Log를 읽어 Slave DB 업데이트&lt;/li&gt;
&lt;li&gt;읽기 처리 시, Slave DB를 사용&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, 데이터가 들어오는 양이 많아진다면, Master가 Slave에게 알려주기 전에 SELECT 요청이 들어올 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;복제 지연&lt;/b&gt;&lt;/span&gt;이라고 하며, 이럴 때는 임시로 Master에게도 Select Query가 가능하도록 만들어 주기도 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Wrap Up&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 서버의 역할을 용어를 통해 분리한 것이였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 개념을 잘알아두고, 서버 세팅 시에 잘 이해할 수 있도록 하자.&lt;/p&gt;</description>
      <category>Knowledge</category>
      <category>active</category>
      <category>infra</category>
      <category>MASTER</category>
      <category>server</category>
      <category>Slave</category>
      <category>Standby</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/82</guid>
      <comments>https://koocci-dev.tistory.com/82#entry82comment</comments>
      <pubDate>Sun, 21 Aug 2022 12:45:32 +0900</pubDate>
    </item>
    <item>
      <title>@Transactional은 어떻게 쓰는것일까?</title>
      <link>https://koocci-dev.tistory.com/81</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : @Transactional의 사용법을 설명할 수 있다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Transaction을 유지하는 방법 정도로 알고 있는 Annotation에서 벗어나서, 조금 더 자세히 알아보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;그동안은 어떻게 써왔는가?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 로직이 길 수 밖에 없는 상황에 써왔다. 다시 말해 쓸 수 밖에 없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Transactional을 통해 묶어주어야, 2개 이상의 쿼리에 대해 DB Commit 과 Rolback이 가능하도록 관리된다고 알고 있었고, 연동 구간이 길 수 밖에 없는 로직, 예를 들면 기기제어, 각종 로그인, UI를 통한 컨텐츠 변경 등의 작업이 필요할 때마다 Service에서 사용하는 Method에 @Transactional를 설정하여 처리했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;과연 난 잘 써왔을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Transaction&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Transaction을 모르고 사용하는 사람은 없을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 한번 정도는 정리하고 가보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Transaction&lt;/b&gt;&lt;/span&gt;은 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;상호작용의 단위&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스 관리 시스팀 혹은 그와 유사한 시스템에서 사용하는 상호작용의 단위라고 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;ACID&lt;/b&gt;&lt;/span&gt;라고 하는 특징을 가진 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;변화에 있어서의 한 단위&lt;/b&gt;&lt;/span&gt;로 다시 말할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Transaction이라는 한 묶음은 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;ACID(Atomic, Consistency, Isolation, Durability)&lt;/b&gt;&lt;/span&gt;를 보장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 말해, Transaction이라는 단위는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;독립적이고, 원자성을 가지며, 일관성있게 영구적인 상태&lt;/b&gt;&lt;/span&gt;를 가지게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터는 변화에 민감해야 하며, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;서로에게 영향을 행사할 수 없는&lt;/b&gt;&lt;/span&gt; &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;독립성(Isolation)&lt;/b&gt;&lt;/span&gt;을 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 중간에 흐트러지지 않는, 어줍잖게 되고 있는 그 중간같은 값이 없이, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;되거나 안되거나&lt;/b&gt;&lt;/span&gt;, 0 or 1 영역의 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;원자성(Atomic)&lt;/b&gt;&lt;/span&gt;을 가져야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;행위 전후에는 데이터베이스가 가지고 있는 제약이나 규칙에 위배되지 않고&lt;/span&gt;&lt;/b&gt; &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;일관성(Consistency)&lt;/b&gt;&lt;/span&gt;을 지켜야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로,&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt; 성공적인 수행 이후에는 계속 유지&lt;/b&gt;&lt;/span&gt;되는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;지속성(Durability)&lt;/b&gt;&lt;/span&gt;이 있어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Spring에서의 Transaction 설명&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 내부를 살펴보기 전에,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#transaction&quot;&gt;Spring에서는 어떻게 설명하고 있는지&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;확인해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;transaction&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Transaction Management&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저, Spring에서의 Transaction 관리의 이점은 다음과 같다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;A consistent programming model across different transaction APIs, such as Java Transaction API (JTA), JDBC, Hibernate, and the Java Persistence API (JPA).&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;JTA(Java Transaction API), JDBC, Hibernate 및 JPA(Java Persistence API)와 같은 다양한 트랜잭션 API에서 일관된 프로그래밍 모델.&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Support for&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;declarative transaction management&lt;/b&gt;&lt;/span&gt;.&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;선언적 트랜잭션 관리를 지원&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;A simpler API for&amp;nbsp;programmatic&amp;nbsp;transaction management than complex transaction APIs, such as JTA.&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;JTA와 같은 복잡한 트랜잭션 API보다 프로그래밍 방식의 트랜잭션 관리를 위한 더 간단한 API&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Excellent integration with Spring&amp;rsquo;s data access abstractions.&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Spring의 데이터 접근 추상화와의 탁월한 통합.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;transaction-motivation&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Advantages of the Spring Framework&amp;rsquo;s Transaction Support Model&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;java EE 개발자는 Global Transaction이나 Local Transaction을 활용해 Transcation을 관리했다. 그러나, 둘 다 한계가 있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Local Transaction&lt;br /&gt;&lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;쉽게 표현하면, 하나의 DB와의 연결이다. JDBC Connection 등 전용 리소스를 사용한다.&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;단점은, 여러 Transaction Resource인 상황에선 유효하지 못하다. Global Transaction 에서는 실행할 수 없다는 것이다.&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;br /&gt;&lt;br /&gt;Global Transaction&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;여러 개의 DB 작업을 하나의 트랜잭션으로 묶는다. Java는 이를 위해 JTA(Java Transaction API)를 제공한다.&lt;br /&gt;&lt;b&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Local Transaction이냐, Global Transaction이냐에 따라 코드도 다르고, 어떤 DB에 접근하냐에 따라 사용하는 트랜잭션 코드가 달라진다. 즉, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Data Access 기술에 종속이 되어 버린다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;스프링은 트랜잭션 기술의 공통점을 모아, &lt;span style=&quot;color: #ee2323;&quot;&gt;추상화&lt;/span&gt;를 제공한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;transaction-programming-model&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Spring Framework&amp;rsquo;s Consistent Programming Model&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링은 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;일관성 있는 프로그래밍 모델&lt;/b&gt;&lt;/span&gt;을 지원한다. 즉, Global Transaction과 Local Transaction의 단점들을 해소해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과적으로 각기 다른 환경에서 다른 트랜잭션 관리 전략을 쓰더라도, 코드는 한 번만 작성하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링에서는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Declarative &amp;amp; programmatic transaction management&lt;/b&gt;&lt;/span&gt;를 둘다 지원한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Declarative transaction management&lt;/b&gt;&lt;/span&gt;를 선호하며 권장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 추상화된 상태라면, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;트랜잭션 관리와 관련된 코드를 아예 작성하지 않거나 매우 조금만 참여하며, 어플리케이션 개발에 집중할 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;transaction-strategies&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Understanding the Spring Framework Transaction Abstraction&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 스프링에서 어떻게 추상화 했는지 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링에서는 &lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;the notion of a transaction strategy, 트랜잭션 전략&lt;/b&gt;&lt;/span&gt;이라는 개념이 들어간다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;트랜잭션 전략은 TransactionManager, 그 중에서도 &lt;span style=&quot;color: #252525;&quot;&gt;imperative(명령형)&lt;/span&gt; TransactionManager인 &lt;/span&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/transaction/PlatformTransactionManager.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;PlatformTransactionManager&lt;/a&gt; 와 reactive(반응형) transaction management인 &lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/transaction/ReactiveTransactionManager.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ReactiveTransactionManager&lt;/a&gt;가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public interface PlatformTransactionManager {
   TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;
   void commit(TransactionStatus status) throws TransactionException;
   void rollback(TransactionStatus status) throws TransactionException;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;TransactionException&lt;/b&gt;&lt;/span&gt;은 모두 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Unchecked Exception (RuntimeException을 상속)&lt;/b&gt;&lt;/span&gt;한 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션 인프라의 장애는 거의 예외없이 치명적이고, 드물게 트랜잭션 실패를 App에서 복구한다면, TransactionException을 잡아서 처리할수도 있다. 즉, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;개발자가 예외를 처리하도록 강요하지 않는다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 말해, Spring에서는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Checked Exception&lt;/b&gt;&lt;/span&gt;에 대해서는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Rollback이 되지 않도록 Default로 설정&lt;/b&gt;&lt;/span&gt;되었다. (rollbackFor로 수정할 수 있다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Checked Exception&lt;/b&gt;&lt;/span&gt;은 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;복구가 가능하다는 매커니즘&lt;/b&gt;&lt;/span&gt;을 갖고 있기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들면, 파일이 없을 때는 Default이미지를 catch에서 선택하는 등의 복구전략이 있다는 것이 전재이므로, Rollback을 처리하지 않는게 Default이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;getTransaction()&lt;/b&gt;&lt;/span&gt; 메서드는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;TransactionDefinition 파라미터&lt;/b&gt;&lt;/span&gt;에 따라, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;TransactionStatus&lt;/b&gt;&lt;/span&gt;를 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;TransactionDefinition&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public interface TransactionDefinition {
   int PROPAGATION_REQUIRED = 0;
   int PROPAGATION_SUPPORTS = 1;
   int PROPAGATION_MANDATORY = 2;
   int PROPAGATION_REQUIRES_NEW = 3;
   int PROPAGATION_NOT_SUPPORTED = 4;
   int PROPAGATION_NEVER = 5;
   int PROPAGATION_NESTED = 6;
   int ISOLATION_DEFAULT = -1;
   int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;
   int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;
   int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;
   int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;
   int TIMEOUT_DEFAULT = -1;
   int getPropagationBehavior();
   int getIsolationLevel();
   int getTimeout();
   boolean isReadOnly();
   @Nullable
   String getName();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많은 사항들이 있고, 주석으로 설명이 있지만, 간략하게 특수한 용어들만 먼저 정리해보자&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Propagation(전파)&lt;/b&gt;&lt;/span&gt; : &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;동작 도중 다른 트랜잭션을 호출할 때, 어떻게 할 것인지를 지정&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;기본적으로 트랜잭션 범위 내에 있는 모든 코드는 해당 트랜잭션에서 실행된다. 단, 트랜잭션 컨텍스트가 이미 있는 상태에서 트랜잭션 메소드를 실행하는 경우엔 동작 방식을 지정할 수 있다. 예를 들어 기존 트랜잭션에서 코드를 계속 실행하거나 (일반적), 기존 트랜잭션을 일시 중단하고 새 트랜잭션을 만들 수 있다.&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Isolation(고립)&lt;/b&gt; &lt;/span&gt;: &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;이 트랜잭션 작업과 얼마나 격리할 것인지를 나타내는 척도, 일관성없는 데이터 허용 수준 (격리 수준)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;예를 들어, 현재 트랜잭션은 다른 트랜잭션에서 커밋하지 않는 쓰기를 볼 수 있는가?&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;TimeOut(타임 아웃)&lt;/b&gt;&lt;/span&gt; : &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;트&lt;span style=&quot;color: #006dd7;&quot;&gt;랜&lt;/span&gt; 잭션의 실행 시간으로, 타임 아웃 시, Rollback&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Read-Only(읽기 전용)&lt;/b&gt;&lt;/span&gt; : 데이터를 수정하지 않고, 읽기만 하는 상태&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;TransactionStatus&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public interface TransactionStatus extends TransactionExecution, SavepointManager, Flushable {
    @Override
    boolean isNewTransaction(); // 새로운 트랜잭션 존재 여부
    boolean hasSavepoint(); // 현재 일치하는 트랜잭션이 존재하는가
    @Override
    void setRollbackOnly(); // rolbakc이 가능한가?
    @Override
    boolean isRollbackOnly(); //rollback이 되었는가?
    void flush(); // 실제 DB에 동기화
    @Override
    boolean isCompleted(); // 트랜잭션 완료 여부
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;TransactionStatus&lt;/b&gt;&lt;/span&gt;를 통해,&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt; 간단한 코드로 트랜잭션 실행을 제어하고, 상태를 확인할 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;transaction-declarative&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Declarative Transaction Management&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 프레임워크 사용자 대부분이 &lt;b&gt;Declarative Transaction Management(선언적 트랜잭션 관리)&lt;/b&gt;를 선택한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Application 코드에 미치는 영향이 가장 적기 때문에, 이상에 알맞다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링에서 Declarative Transaction management는 &lt;a href=&quot;https://koocci-dev.tistory.com/71?category=1012333&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AOP&lt;/a&gt;덕분에 가능한 방법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션 지원은 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;AOP Proxy&lt;/b&gt;&lt;/span&gt;를 통해 활성화되며, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;트랜잭션 advice&lt;/b&gt;&lt;/span&gt;는 메타데이터(XML 혹은 Annotation)로 구동된다는 점이다. 트랜잭션 메타데이터를 가지고 만든 AOP Proxy는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;TransactionInterceptor&lt;/b&gt;&lt;/span&gt;와 적당한 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;TransactionManager 구현체&lt;/b&gt;&lt;/span&gt;를 사용해 메소드 호출을 둘러싸고 트랜잭션을 실행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;362&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Lbc2H/btrJ7sMLtUn/NQgTfC6LsQe3ednl75stJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Lbc2H/btrJ7sMLtUn/NQgTfC6LsQe3ednl75stJ1/img.png&quot; data-alt=&quot;Transactional Proxy&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Lbc2H/btrJ7sMLtUn/NQgTfC6LsQe3ednl75stJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLbc2H%2FbtrJ7sMLtUn%2FNQgTfC6LsQe3ednl75stJ1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;362&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;362&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Transactional Proxy&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Using @Transactional&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;// the service class that we want to make transactional
@Transactional
public class DefaultFooService implements FooService {

    Foo getFoo(String fooName) {
        // ...
    }

    Foo getFoo(String fooName, String barName) {
        // ...
    }

    void insertFoo(Foo foo) {
        // ...
    }

    void updateFoo(Foo foo) {
        // ...
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스 레벨에 사용하는 Annotation은, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;선언하는 클래스(하위 클래스도)의 모든 메소드에 적용할 기본값을 나타낸다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 메소드마다 개별로 Annotation을 달아도 된다. 다만, 클래스 계층 구조 상 위에 있는 클래스엔 적용되지 않으며, 상속된 메서드는 subclass 레벨의 Anntation에도 포함되려면 재정의(redeclared)되어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 큰 &lt;b&gt;2가지 사항&lt;/b&gt;에 대해 확인해볼 것이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;public 메서드에만 적용해야 한다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;같은 객체에 있는 다른 Method를 호출하면, 트랜잭션이 적용이 되지 않는다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Transactional Proxy를 사용할 때는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;public 메서드에만 적용&lt;/b&gt;&lt;/span&gt;해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;protected, private에 선언해도 에러는 아니지만, 정상적인 동작을 하지 않는다. (내부 메서드 호출과 동일한 이유)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 필요하다면, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;AspectJ&lt;/b&gt;&lt;/span&gt;를 사용하는 것이 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;@Transactional Annotation&lt;/b&gt;&lt;/span&gt;은 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;인터페이스 정의나 인터페이스의 메서드, 클래스 정의, 클래스 public 메서드&lt;/b&gt;&lt;/span&gt;에 적용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, 인터페이스 대신 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;구체적인 클래스(구체적인 클래스의 메서드)&lt;/b&gt;&lt;/span&gt;에 선언하기를 권장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터페이스에 적용할 경우, Interface-based Proxy를 사용할 때만 의도대로 동작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약, class-based Proxy를 사용하거나 weaving-based aspect를 사용한다면, 트랜잭션 세팅은 proxy와 weaving infrastructure에게 인지되지 않고, 객체는 transactional proxy에 감싸지지 않을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 설명을 다시 정리해보면, Spring AOP는 Proxy 기반으로 만들어져, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Target Method가 호출되는 시점에 부가기능을 추가할 메소드를 자체적으로 판단하여, 부가기능을 주입&lt;/b&gt;&lt;/span&gt;한다. 즉, Runtime에 Weaving한다고 하여, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Runtime Weaving&lt;/b&gt;&lt;/span&gt;이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 Runtime Weaving 기능을 Spring 에서는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;CGLib Proxy&lt;/b&gt;&lt;/span&gt;와 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;JDK Proxy&lt;/b&gt;&lt;/span&gt;를 상황에 따라 번갈아가며 사용한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;931&quot; data-origin-height=&quot;452&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wZ2Rf/btrJ8HvnxcW/H1GvYv11jozyZJIQAiSUfk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wZ2Rf/btrJ8HvnxcW/H1GvYv11jozyZJIQAiSUfk/img.png&quot; data-alt=&quot;SPring AOP Proxy&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wZ2Rf/btrJ8HvnxcW/H1GvYv11jozyZJIQAiSUfk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwZ2Rf%2FbtrJ8HvnxcW%2FH1GvYv11jozyZJIQAiSUfk%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;931&quot; height=&quot;452&quot; data-origin-width=&quot;931&quot; data-origin-height=&quot;452&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;SPring AOP Proxy&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;JDK Dynamic Proxy&lt;/b&gt;&lt;/span&gt;는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;인터페이스&lt;/b&gt;&lt;/span&gt;를 구현하여 Proxy를 생성해주고, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;CGLib(Code Generator Library) Proxy&lt;/b&gt;&lt;/span&gt;는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;클래스&lt;/b&gt;&lt;/span&gt;를 상속받아 Proxy를 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, Spring은 CGLib Proxy 를 기본으로 권장하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 다른 한가지, &lt;b&gt;같은 객체에 있는 다른 Method를 호출하면, 트랜잭션이 적용이 되지 않는다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 Proxy의 특징으로, Transaction에 의한 AOP Proxy를 예로 들면, Target Object 메서드 호출 전에, Transaction이 시작하고 호출 후에 commit or rollback된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Proxy는 Client가 Target Object를 호출하는 과정에만 동작&lt;/b&gt;&lt;/span&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 말은, &lt;b&gt;Target Object에서, 자신의 다른 Method를 호출하면 프록시는 정상적으로 동작하지 않는다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프록시를 통하지 않고 다른 Method가 호출이 되며, @Transactional Annotation이 있더라도 동작하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 예시를 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;출처:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://springsource.tistory.com/135&quot;&gt;https://springsource.tistory.com/135&lt;/a&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;[Rednics Blog:티스토리]&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1660999464720&quot; class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Transactional
public class MemberService {
  
  @Transactional(propagation=Propagation.REQUIRES_NEW)
  public void add(Member m) {...}
  
  public void complex() {
    ...
    this.add(new Member(...));
  }
  ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스 전체에 Transactional이 걸려있고, 내부에 method에도 걸려있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때, Client로부터 complex()라는 게 호출된다면, 그전에 Proxy를 먼저 타게 될 것이고, Class에 적용된 Annotation에 따라&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&amp;nbsp;Proxy에서 트랜잭션이 시작된다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;그 안에 있는 this.add 메서드의 실행이다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;이미 Proxy를 통과해서 들어온 상황이라, add 메서드는 트랜잭션 속성이 반영되지 못한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, add 메서드는 호출이 되었지만, 새로운 트랜잭션이 생성되는 것이 아니고, &lt;b&gt;complex() 에서 시작된 트랜잭션에 그냥 참여될 뿐이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이에 대한 해결방법은 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;모드를 Proxy가 아닌&lt;/b&gt; &lt;b&gt;AspectJ 모드&lt;/b&gt;&lt;/span&gt;를 사용하는 방법이 있다. 이 방법은 프록시 없이 Weaving을 통해(바이트 코드를 수정해서) @Transactional 을 Target Class에 있는 모든 메소드의 런타임 동작으로 전환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;transactional-settings&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;@Transactional Settings&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 68px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.2868%; text-align: center;&quot;&gt;&lt;b&gt;Property&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 19.7286%; text-align: center;&quot;&gt;&lt;b&gt;Type&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 57.9845%; text-align: center;&quot;&gt;&lt;span style=&quot;color: #252525;&quot;&gt;&lt;b&gt;Description&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.2868%;&quot;&gt;value&lt;/td&gt;
&lt;td style=&quot;width: 19.7286%;&quot;&gt;String&lt;/td&gt;
&lt;td style=&quot;width: 57.9845%;&quot;&gt;&lt;span style=&quot;color: #252525;&quot;&gt;사용할 트랜잭션을 지정하는 생략 가능한 한정자 (qualifier)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.2868%;&quot;&gt;transactionManager&lt;/td&gt;
&lt;td style=&quot;width: 19.7286%;&quot;&gt;String&lt;/td&gt;
&lt;td style=&quot;width: 57.9845%;&quot;&gt;&lt;span style=&quot;color: #252525;&quot;&gt;value의 Alias&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.2868%;&quot;&gt;label&lt;/td&gt;
&lt;td style=&quot;width: 19.7286%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 57.9845%;&quot;&gt;&lt;span style=&quot;color: #252525;&quot;&gt;Transaction에 표현적인 설명을 추가하기 위한 문자열 라벨의 배열&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.2868%;&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#tx-propagation&quot;&gt;propagation&lt;/a&gt;&lt;/td&gt;
&lt;td style=&quot;width: 19.7286%;&quot;&gt;enum:&amp;nbsp;Propagation&lt;/td&gt;
&lt;td style=&quot;width: 57.9845%;&quot;&gt;생략 가능한 전파 설정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.2868%;&quot;&gt;isolation&lt;/td&gt;
&lt;td style=&quot;width: 19.7286%;&quot;&gt;enum:&amp;nbsp;Isolation&lt;/td&gt;
&lt;td style=&quot;width: 57.9845%;&quot;&gt;생략 가능한 고립 수준.&lt;br /&gt;propagation이 REQUIRED나 REQUIRES_NEW일 때만 적용할 것.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.2868%;&quot;&gt;timeout&lt;/td&gt;
&lt;td style=&quot;width: 19.7286%;&quot;&gt;int&amp;nbsp;(in seconds of granularity)&lt;/td&gt;
&lt;td style=&quot;width: 57.9845%;&quot;&gt;생략 가능한 트랜잭션 타임 아웃.&lt;br /&gt;propagation이 REQUIRED나 REQUIRES_NEW일 때만 적용할 것.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.2868%;&quot;&gt;timeoutString&lt;/td&gt;
&lt;td style=&quot;width: 19.7286%;&quot;&gt;String&amp;nbsp;(in seconds of granularity)&lt;/td&gt;
&lt;td style=&quot;width: 57.9845%;&quot;&gt;타임 아웃을 String 값(EX&amp;gt; placeholder)으로 대신 사용할 수 있음.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.2868%;&quot;&gt;readOnly&lt;/td&gt;
&lt;td style=&quot;width: 19.7286%;&quot;&gt;boolean&lt;/td&gt;
&lt;td style=&quot;width: 57.9845%;&quot;&gt;읽기/쓰기 versus 읽기 전용 트랜잭션.&lt;br /&gt;propagation이 REQUIRED나 REQUIRES_NEW일 때만 적용할 것.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 22.2868%; height: 17px;&quot;&gt;rollbackFor&lt;/td&gt;
&lt;td style=&quot;width: 19.7286%; height: 17px;&quot;&gt;Array of&amp;nbsp;Class&amp;nbsp;objects, which must be derived from&amp;nbsp;Throwable.&lt;/td&gt;
&lt;td style=&quot;width: 57.9845%; height: 17px;&quot;&gt;롤백을 유발해야 하는 exception 클래스 배열.&lt;br /&gt;생략 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 22.2868%; height: 17px;&quot;&gt;rollbackForClassName&lt;/td&gt;
&lt;td style=&quot;width: 19.7286%; height: 17px;&quot;&gt;Array of exception name patterns.&lt;/td&gt;
&lt;td style=&quot;width: 57.9845%; height: 17px;&quot;&gt;롤백을 유발해야 하는 exception 클래스 이름의 배열.&lt;br /&gt;생략 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 22.2868%; height: 17px;&quot;&gt;noRollbackFor&lt;/td&gt;
&lt;td style=&quot;width: 19.7286%; height: 17px;&quot;&gt;Array of&amp;nbsp;Class&amp;nbsp;objects, which must be derived from&amp;nbsp;Throwable.&lt;/td&gt;
&lt;td style=&quot;width: 57.9845%; height: 17px;&quot;&gt;롤백을 유발하지 않을 exception 클래스 배열.&lt;br /&gt;생략 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 22.2868%; height: 17px;&quot;&gt;noRollbackForClassName&lt;/td&gt;
&lt;td style=&quot;width: 19.7286%; height: 17px;&quot;&gt;Array of exception name patterns.&lt;/td&gt;
&lt;td style=&quot;width: 57.9845%; height: 17px;&quot;&gt;롤백을 유발하지 않을 exception 클래스 이름의 배열.&lt;br /&gt;생략 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;propagation&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;앞서,&lt;/span&gt;&lt;b&gt; Propagation(전파)&lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;은&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;동작 도중 다른 트랜잭션을 호출할 때, 어떻게 할 것인지를 지정&lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이라고 정리했다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 설정값들을 정리해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;REQUIRED&lt;/b&gt;&lt;/span&gt; : default 값. 현재 활성화된 트랜잭션이 존재하면, 해당 트랜잭션에 비즈니스 로직을 Append, 없다면 새로운 트랜잭션 생성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;SUPPORTS&lt;/b&gt;&lt;/span&gt; : 활성화된 트랜잭션이 있으면 해당 트랜잭션을 사용, 없다면 트랜잭션 없이 실행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;MANDATORY&lt;/b&gt;&lt;/span&gt; : 활성화된 트랜잭션이 있으면 해당 트랜잭션을 사용, 없다면 예외 발생&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;NEVER&lt;/b&gt; &lt;/span&gt;: 활성화된 트랜잭션이 존재하면 예외 발생, 없다면 트랜잭션을 사용하지 않음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;NOT_SUPPORTED&lt;/b&gt;&lt;/span&gt; : 활성화된 트랜잭션이 존재하면 보류, 비즈니스 로직을 트랜잭션 없이 실행.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;REQUIRES_NEW&lt;/b&gt;&lt;/span&gt; : 항상 새로운 트랜잭션을 시작. 이미 진행중인 트랜잭션이 존재하면, 해당 트랜잭션을 잠시 보류.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;NESTED&lt;/b&gt;&lt;/span&gt; : 활성화된 트랜잭션이 존재하면, 해당 트랜잭션의 세이브 포인트를 기록. 중첩 트랜잭션을 만들어 진행하는데, 비즈니스 로직에 예외가 발생하면 세이브 포인트로 롤백.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;isolation&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;isolation(고립)&lt;/b&gt;&lt;/span&gt;은 ACID의 한 요소로, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;이 트랜잭션 작업과 얼마나 격리할 것인지를 나타내는 척도, 일관성없는 데이터 허용 수준 (격리 수준)&lt;/b&gt;&lt;/span&gt;이라고 정리했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때, 그 정도에 따라 발생할 수 있는 동시성의(concurrency) side effects로, 3가지가 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Dirty Read&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;A 트랜잭션에서 &lt;span style=&quot;color: #666666;&quot;&gt;완전히 반영되지 않은 데이터를 B 트랜잭션이 읽을 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;만약, A 트랜잭션이 롤백되면, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;데이터 불일치&lt;/b&gt;&lt;/span&gt;가 나온다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;Non-repeatable Read&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;A 트랜잭션이 조회중인 정보를 트랜잭션 B에서 수정하고 커밋하면, A 트랜잭션 내에서 재조회했을 때, 수정된 데이터가 조회된다 (이전 데이터는 다시 조회할 수 없다). 즉, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;반&lt;/b&gt;&lt;b&gt;복해서 같은 데이터를 읽을 수 없는 경우 (트랜잭션 내에서 결과가 일관성을 가지지 못한다)&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #666666;&quot;&gt;Phantom Read&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;외부에서 수행되는 삽입/삭제로 인해, 트랜잭션 내에서의 동일한 쿼리가 다른 값을 반환&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 Side Effect로 인해, 격리 수준을 4단계로 제공하고, 그 설정값이 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;DEFAULT&lt;/b&gt;&lt;/span&gt; : 기본 격리 수준 (DB 설정에 종속한다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;READ_UNCOMMITED(Level 0)&lt;/b&gt;&lt;/span&gt; : 커밋되지 않는 데이터에 대한 읽기를 허용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Dirty Read가 발생&lt;/b&gt;&lt;/span&gt;할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;READ_COMMITED(Level 1)&lt;/b&gt;&lt;/span&gt; : 커밋된 데이터에 대해서만 읽기 허용한다. (데이터 변경 중에는 접근 불가)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Dirty Read 방지&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;REPEATEABLE_READ(Level 2)&lt;/b&gt;&lt;/span&gt; : 동일 필드에 대해 다중 접근 시 모두 동일한 결과를 보장&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 트랜잭션이 완료될 때까지 SELECT 문장이 사용하는 모든 데이터에 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Shared Lock&lt;/b&gt;&lt;/span&gt;이 걸리므로 다른 사용자는 그 영역에 해당하는 데이터에 대한 수정이 불가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 선행 트랜잭션이 읽은 데이터는 트랜잭션이 종료될 때까지 후행 트랜잭션이 갱신하거나 삭제가 불가능하기 때문에 같은 데이터를 두번 쿼리했을 때, 일관성을 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Non-Repeatable Read 방지&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;SERIALIZABLE(Level 3)&lt;/b&gt;&lt;/span&gt; : 가장 높은 격리, 성능 저하의 우려가 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 데이터의 일관성 및 동시성을 위해 &lt;b&gt;MVCC(Multi Version Concurrency Control)&lt;/b&gt;을 사용하지 않음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 트랜잭션이 완료될 때까지 SELECT 문장이 사용하는 모든 데이터에 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;shared lock&lt;/b&gt;&lt;/span&gt;이 걸리므로 다른 사용자는 그 영역에 해당되는 데이터에 대한 수정 및 입력이 불가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Phantom Read 방지&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;MVCC&lt;/b&gt;&lt;/span&gt; : 다중 사용자 데이터베이스 성능을 위한 기술로 데이터 조회 시, LOCK을 사용하지 않고 데이터의 버전을 관리해 데이터의 일관성 및 동시성을 높이는 기술)&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, 격리 수준에 따라 문제점 발생 도표는 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;Isolation Level&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;Dirty Read&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;Non-Repeabtable Read&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;Phantom Read&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Read Uncommitted&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Read Committed&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Repeatable Read&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Serializable&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;이제 Annotation을 보자.&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {

   @AliasFor(&quot;transactionManager&quot;)
   String value() default &quot;&quot;;

   @AliasFor(&quot;value&quot;)
   String transactionManager() default &quot;&quot;;

   Propagation propagation() default Propagation.REQUIRED;

   Isolation isolation() default Isolation.DEFAULT;

   int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;

   boolean readOnly() default false;

   Class&amp;lt;? extends Throwable&amp;gt;[] rollbackFor() default {};

   String[] rollbackForClassName() default {};

   Class&amp;lt;? extends Throwable&amp;gt;[] noRollbackFor() default {};

   String[] noRollbackForClassName() default {};

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분의 설정값을 이해할 수 있을 것이며, 이제 최종적으로 정리해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Wrap Up&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아주 길게 Transactional에 대해 정리해보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생각보다 양이 굉장히 많아서 놀랬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 하나씩 다시 정리해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Transaction&lt;/b&gt;&lt;/span&gt;은 &lt;b&gt;상호작용의 단위&lt;/b&gt;이며,&lt;b&gt; ACID를 보장하는 한 변화의 단위&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;ACID&lt;/b&gt;&lt;/span&gt;는 Atomic, Consistency, Isolation, Durability 이며, 원자성, 일관성, 격리, 지속성을 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring에서 Transaction은 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;추상화&lt;/b&gt;&lt;/span&gt;를 통해, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Global Transaction과 Local Transaction으로 나누어 처리하던 로직을 간소화&lt;/b&gt;&lt;/span&gt;하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;선언적 Transaction Management&lt;/b&gt;&lt;/span&gt;에서 &lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/transaction/PlatformTransactionManager.html&quot;&gt;PlatformTransactionManager&lt;/a&gt;&lt;span&gt;&lt;span&gt; 이라는 인터페이스를 Transaction 전략으로 사용하였다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;이 때, &lt;b&gt;getTransaction, commit, rollback&lt;/b&gt; 3개의 메서드를 가지고 있으며, Exception은 TransactionException으로 unchecked Exception을 관리한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;getTransaction()&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;메서드는 트랜잭션을 시작하는 것과 동일하고,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;TransactionDefinition 파라미터&lt;/b&gt;&lt;/span&gt;&lt;span&gt;에 따라, &lt;b&gt;간단한 코드로 트랜잭션 실행을 제어하고, 상태를 확인할 수 있도록&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;TransactionStatus&lt;/b&gt;&lt;/span&gt;를 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring에서 Declarative Transaction management는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;AOP Proxy&lt;/b&gt;&lt;/span&gt;로 관리된다. Proxy 패턴으로 Target 전에 Transaction이 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;@Transactional &lt;/b&gt;&lt;/span&gt;Annotation은&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt; 클래스나 인터페이스 혹은 그 메서드&lt;/b&gt;&lt;/span&gt;에 선언될 수 있으나, 인터페이스보다는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;클래스나 그 메서드에 선언되는 것을 권장&lt;/b&gt;&lt;/span&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;JDK Dynamic Proxy의 경우, Interface 기반의 Transaction 설정으로 되었을 때 동작하지만, 클래스나 그 메서드에 선언되어 있을 때는 동작하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, CGLib Proxy를 통해, Runtime Weaving 될 때, 바이트 코드를 만들어 버리는 형태로 진행해야 클래스나 그 메서드에서 정상적으로 동작할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;@Transactional&lt;/b&gt;&lt;/span&gt;는 &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;public 메서드에만 적용&lt;/span&gt;&lt;/b&gt;해야 하며, 같은&lt;b&gt;&amp;nbsp;&lt;span style=&quot;color: #006dd7;&quot;&gt;객체에 있는 다른 Method를 호출하면, 트랜잭션이 적용이 되지 않는다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Proxy로 적용되는 흐름 상, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;내부 메서드 호출은 Proxy를 타지 않기 때문&lt;/b&gt;&lt;/span&gt;이며, 외&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;부 노출이 안되면 실행이 안되기 떄문&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@Transactional에는 여러 설정이 있고, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;propagation, Isolation, timeout, RollbackFor&lt;/b&gt; &lt;/span&gt;등이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;propagation&lt;/b&gt;&lt;/span&gt;은 한 트랜잭션에서 다른 트랜잭션이 실행될 때, 어떻게 전파되는지를 설정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Default로 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;REQUIRED&lt;/b&gt;&lt;/span&gt; 이며 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;이미 진행되는 트랜잭션이 있으면, 해당 트랜잭션에 소속되며 아니면 새롭게 생성&lt;/b&gt;&lt;/span&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;isolation&lt;/b&gt;&lt;/span&gt;은 ACID에도 포함되는 격리성이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;격리 레벨에 따라 Side Effect로 3가지, Dirty Read, Non-repeatable Read, phantom Read 가 나올 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;격리 레벨은 총 4개 (default 포함 5개)로 구분되며 각각 Side Effect가 나올 수 있는지 여부가 판단된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;DEFAULT, READ_UNCOMMITED, READ_COMMITED, REPEATABLE_READ, SEARIALIZABLE&lt;/b&gt;&lt;/span&gt; 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 나는 @Transactional을 잘 쓰고 있었을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;용도는 맞았을 지도 모르겠다. 그러나 그냥 남들 쓰는 걸 보고 썼다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Transactional(value=&quot;transactionManager&quot;, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거의 대부분의 코드에 쓰인 내용이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;rollbackFor 정도를 제외하면 설정이 없어도 될 정도다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;rollbackFor에 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Exception.class&lt;/b&gt;&lt;/span&gt;를 적용한 이유는 아마, 반드시 처리되어야 할 Checked Exception이 발생했을 때, 이를 unChecked Exception으로 바꾸어 던지기보다, 간편했기 때문일 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉽지 않은 작업이지만, 구체적으로 Throw를 날릴 수 있도록 연습해야할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Framework/Spring</category>
      <category>spring</category>
      <category>Transactional</category>
      <category>스프링</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/81</guid>
      <comments>https://koocci-dev.tistory.com/81#entry81comment</comments>
      <pubDate>Sun, 21 Aug 2022 00:02:42 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] @SpringBootApplication은 무엇이 다를까?</title>
      <link>https://koocci-dev.tistory.com/80</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : @SpringBootApplication의 Annotation에 대해 설명할 수 있다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서, &lt;a href=&quot;https://koocci-dev.tistory.com/57?category=1012333&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Spring 자체가 EJB로 서버개발이 너무 어려워, 그에 대한 대체/보완으로 나온 프레임워크&lt;/a&gt;라는 것을 배웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼에도 점차 발전한 Spring은 SpringBoot를 내놓으며, 더 간소화된 내용으로 제공하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, SpringBoot에는 @SpringBootApplication이 main 실행의 Annotation으로 존재하며, SpringBoot와 Spring을 비교했을 때, 그 차이점에 포함된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 무엇이 다른지 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;@SpringBootApplication은 어떻게 생겼을까?&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
      @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

   @AliasFor(annotation = EnableAutoConfiguration.class)
   Class&amp;lt;?&amp;gt;[] exclude() default {};

   @AliasFor(annotation = EnableAutoConfiguration.class)
   String[] excludeName() default {};

   @AliasFor(annotation = ComponentScan.class, attribute = &quot;basePackages&quot;)
   String[] scanBasePackages() default {};

   @AliasFor(annotation = ComponentScan.class, attribute = &quot;basePackageClasses&quot;)
   Class&amp;lt;?&amp;gt;[] scanBasePackageClasses() default {};

   @AliasFor(annotation = ComponentScan.class, attribute = &quot;nameGenerator&quot;)
   Class&amp;lt;? extends BeanNameGenerator&amp;gt; nameGenerator() default BeanNameGenerator.class;

   @AliasFor(annotation = Configuration.class)
   boolean proxyBeanMethods() default true;
}&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Indicates a configuration class that declares one or more @Bean methods and also triggers auto-configuration and component scanning. This is a convenience annotation that is equivalent to declaring @Configuration, @EnableAutoConfiguration and @ComponentScan&lt;/span&gt;&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;하나 이상의 @Bean 메서드를 선언하고 AutoConfiguration 및 ComponentScan을 트리거하는 구성 클래스를 나타냅니다. @Configuration, @EnableAutoConfiguration 및 @ComponentScan을 선언하는 것과 동일한 편리한 주석입니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@SpringBootApplication 의 주석을 지운 소스코드와 제일 상단에 있는 주석 내용이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Annotation들을 하나씩 파헤쳐 보면서, 그 의미를 찾아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@Target(ElementType.TYPE)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;@Target&lt;/b&gt;&lt;/span&gt;은 어디에 &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;이 Annotation을 어디에 쓸 수 있는가?&lt;/span&gt;&lt;/b&gt; 에 대한 내용이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;TYPE : Class, interface (including annotation type), or enum declaration&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Enum인 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;ElementType&lt;/b&gt;&lt;/span&gt;으로 정의되어 있으며,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;TYPE&lt;/b&gt;&lt;/span&gt;&lt;span&gt;의 경우,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Class, Interface, Enum&lt;/b&gt;&lt;/span&gt;에 사용할 수 있다는 뜻이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Java_annotation&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Wiki에 따르면&lt;/a&gt;, Built-in Annotation 중, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Meta-Annotation&lt;/b&gt;&lt;/span&gt; 중 하나로, &lt;span style=&quot;color: #252525;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;다른 Annotation에 적용된 Annotation&lt;/b&gt;&lt;/span&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;TYPE 외에도&amp;nbsp; &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;FIELD&lt;/b&gt;&lt;/span&gt; &lt;i&gt;(Bean이 ANNOTATION_TYPE과 함께 대표적인 FIELD가 적용되는 Annotation이다.)&lt;/i&gt;, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;METHOD&lt;/b&gt;&lt;/span&gt;&lt;i&gt;(@Autowired에는 FIELD, CONSTRUCTOR, PARAMETER, METHOD, ANNOTATION_TYPE이 들어간다) &lt;/i&gt;등 다양하니 &lt;a href=&quot;https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/annotation/ElementType.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;다음 링크&lt;/a&gt;를 보면 그 리스트를 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@Retention(RetentionPolicy.RUNTIME)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;@Retention&lt;/b&gt; &lt;/span&gt;이라는 Annotation이며 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;언제까지 살아있는가?(LifeCycle)&lt;/b&gt;&lt;/span&gt;&amp;nbsp;를 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;@SpringBootApplication 의 경우, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;RUNTIME시에 유지&lt;/b&gt;&lt;/span&gt;된다는 것을 알 수 있다. &lt;i&gt;(@Retention도 @Retention이 걸려있는 걸 보면 재미있는 요소다(재귀?))&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RetentionPolicy의 경우, 3개로 구성되어 있는데, 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SOURCE&lt;/li&gt;
&lt;li&gt;CLASS&lt;/li&gt;
&lt;li&gt;RUNTIME&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;SOURCE&lt;/b&gt;&lt;/span&gt;의 경우, 이 Annotation은 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;.java 파일(소스코드 파일)&lt;/b&gt;&lt;/span&gt; 까지만 남아있게 된다. (컴파일시 사라짐)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Lombok의 @Getter&lt;/b&gt;&lt;/span&gt;를 보자.&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public @interface Getter {&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;SOURCE&lt;/b&gt;&lt;/span&gt;로 선언이 되어 있다. 즉, 컴파일 시, 사라진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 이유는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Lombok에서 바이트 코드를 생성해서 넣어주기 때문에, 컴파일 시 사라져도 상관없기 때문&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서, Lombok을 Gradle에 Dependency로 넣어줄 때, 컴파일 때만 적용해두면 되기 때문에 아래처럼 CompileOnly로 적용한다.&lt;/p&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;compileOnly 'org.projectlombok:lombok'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;RUNTIME&lt;/b&gt;&lt;/span&gt;의 경우, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;실행되어 메모리에 올라왔을 때도, 남아있게 된다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 실행중인 도중에도, 어노테이션 정보가 필요한 상황에 사용한다. (Controller, Service 모두 실행중에 ComponentScan이 가능해야 한다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;CLASS&lt;/b&gt;&lt;/span&gt;의 경우, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;.class 파일(컴파일 후 생성코드)까지 남아있게 된다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이에 대해서는 잘 모르던 부분인데, &lt;a href=&quot;https://jeong-pro.tistory.com/234&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;다음 글의 댓글&lt;/a&gt;에 적혀있어 남겨둔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.java 뿐 아니라 .class로 만들어진 파일(라이브러리 등)에 대해서도 어노테이션 정보를 가지고 와서 보여주기 위함이다. (IDE에서 자주 사용한다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@Documented&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;@Documented&lt;/span&gt;는&lt;/span&gt; JavaDoc 생성 시, Anntation에 대한 정보도 보여줄 수 있도록 설정하는 것&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@Inherited&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Annotation이 상속되도록 설정하는 것&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@SpringBootConfiguration&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Indicates&amp;nbsp;that&amp;nbsp;a&amp;nbsp;class&amp;nbsp;provides&amp;nbsp;Spring&amp;nbsp;Boot&amp;nbsp;application&amp;nbsp;@Configuration.&amp;nbsp;Can&amp;nbsp;be&amp;nbsp;used&amp;nbsp;as&amp;nbsp;an&amp;nbsp;alternative&amp;nbsp;to&amp;nbsp;the&amp;nbsp;Spring's&amp;nbsp;standard&amp;nbsp;@Configuration&amp;nbsp;annotation&amp;nbsp;so&amp;nbsp;that&amp;nbsp;configuration&amp;nbsp;can&amp;nbsp;be&amp;nbsp;found&amp;nbsp;automatically&amp;nbsp;(for&amp;nbsp;example&amp;nbsp;in&amp;nbsp;tests). &lt;br /&gt;Application&amp;nbsp;should&amp;nbsp;only&amp;nbsp;ever&amp;nbsp;include&amp;nbsp;one&amp;nbsp;@SpringBootConfiguration&amp;nbsp;and&amp;nbsp;most&amp;nbsp;idiomatic&amp;nbsp;Spring&amp;nbsp;Boot&amp;nbsp;applications&amp;nbsp;will&amp;nbsp;inherit&amp;nbsp;it&amp;nbsp;from&amp;nbsp;@SpringBootApplication.&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;클래스가 Spring Boot 애플리케이션 @Configuration을 제공함을 나타냅니다. 구성을 자동으로 찾을 수 있도록(예: 테스트에서) Spring의 표준 @Configuration 주석에 대한 대안으로 사용할 수 있습니다. 애플리케이션에는 @SpringBootConfiguration이 하나만 포함되어야 하며 대부분의 관용적인 Spring Boot 애플리케이션은 @SpringBootApplication에서 이를 상속합니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 설명에 따르면, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;@Configuration과 동일한 기능을 하지만, 단 한 개만 쓸 수 있는 Annotation이라고 한다&lt;/b&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, 내부적으로 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;@Configuration&lt;/b&gt;&lt;/span&gt;을 가지고 있다는 것을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, SpringBootTest 시, 그 정보를 자동으로 찾을 수 있다는 장점이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@EnableAutoConfiguration&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 기존 Spring에서 Spring Boot로 바뀔 때, 가장 간편해지는 요소 중 하나가 Configuration의 자동화다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;@EnableAutoConfiguration&lt;/b&gt;&lt;/span&gt;은 &lt;span style=&quot;background-color: #ffffff; color: #212529;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;spring.factories에 있는 자동 설정들을 실행 시에 적용시키는 것&lt;/b&gt;&lt;/span&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;a href=&quot;https://github.com/spring-projects/spring-boot/blob/v1.5.11.RELEASE/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;다음과 같은&lt;/a&gt; 설정 파일들이 있고, 이를 별도의 작업없이 자동으로 적용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 클래스패스에 Configuration관련 사항이 존재할 때만 실행되며, 만약 쓰고 싶지 않다면 exclude도 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@ComponentScan&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
      @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체를 다 긁어보면 위와 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 말했지만, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;@ComponentScan&lt;/b&gt;&lt;/span&gt;&lt;b&gt;은 &lt;span style=&quot;color: #006dd7;&quot;&gt;@Configuration과 @Bean 및 @Component의 하위 어노테이션&lt;/span&gt;(@Repository, @Service, @Controller, @RestController, @ControllerAdvice, @RestControllerAdvice)이 있는 클래스 및 메소드를 찾아,&lt;/b&gt;&lt;b&gt; Spring Container에 등록한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;그런데 옆이 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;@Filter&lt;/b&gt;&lt;/span&gt;를 포함해 많은 내용이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;한번 보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;먼저 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;excludeFilters&lt;/b&gt;&lt;/span&gt;를 통해, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;자동 등록에 포함시키지 않을 내용을 적용&lt;/b&gt;&lt;/span&gt;하고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;그 내용은 &lt;b&gt;TypeExcludeFilter&lt;/b&gt;와 &lt;b&gt;AutoConfigurationExcludeFilter&lt;/b&gt;를 제외하고 자동 등록을 하겠다는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;여러 FilterType 중, CUSTOM으로 만들어진 두 Filter를 사용한다는 것이며, &lt;b&gt;TypeExcludeFilter&lt;/b&gt; 는 SpringApplicationTest에서 사용하는 부분이라 제외를 하며(Hashcode, Equals 구현관련), &lt;b&gt;AutoConfigurationExcludeFilter&lt;/b&gt;는 Auto-configuration 부분을 제외하는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;WrapUp&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;SpringBoot가 달라진점은 보통 다음을 꼽는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Dependency 간소화 (spring-boot-starter-*)&lt;/li&gt;
&lt;li&gt;Configuration 간소화 (application.yml 설정)&lt;/li&gt;
&lt;li&gt;Auto-Configuration&lt;/li&gt;
&lt;li&gt;Embedded-timcat&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 중 Auto-Configuration 설정이 어디에 들어간 것인지, 확인해 볼 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Framework/Spring</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/80</guid>
      <comments>https://koocci-dev.tistory.com/80#entry80comment</comments>
      <pubDate>Fri, 19 Aug 2022 03:12:04 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] Filter와 Intercepter의 차이는 무엇일까?</title>
      <link>https://koocci-dev.tistory.com/79</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : 스프링의 Filter와 Intercepter의 차이를 설명할 수 있다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아마 가장 많은 비교와 사용에 대한 질문을 받는 영역 중 하나일 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Filter와 Interceptor는 대체 무엇이길래 이렇게 헤깔리게 하는것일까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;784&quot; data-origin-height=&quot;693&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dxRpRk/btrJZJaiZ0K/lsVwq5nBcdbPIfSgG2eYR1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dxRpRk/btrJZJaiZ0K/lsVwq5nBcdbPIfSgG2eYR1/img.jpg&quot; data-alt=&quot;Filter &amp;amp;amp; Interceptor&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dxRpRk/btrJZJaiZ0K/lsVwq5nBcdbPIfSgG2eYR1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdxRpRk%2FbtrJZJaiZ0K%2FlsVwq5nBcdbPIfSgG2eYR1%2Fimg.jpg&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; loading=&quot;lazy&quot; width=&quot;784&quot; height=&quot;693&quot; data-origin-width=&quot;784&quot; data-origin-height=&quot;693&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Filter &amp;amp; Interceptor&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;나는 어디에 써보았나?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Filter&lt;/b&gt;&lt;/span&gt;의 경우, &lt;b&gt;전체 Req/Res 로그를 남기길 원할 때, XSS 를 막을 때,&lt;/b&gt; 사용하였고, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Interceptor&lt;/b&gt;&lt;/span&gt;의 경우는 &lt;b&gt;AccessToken에 대한 확인을 요할 때나, 권한에 따라 다른 Menu 정보를 가져오고 싶을 때&lt;/b&gt;&amp;nbsp;사용하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;과연 나는 적절한 방법으로 설정하였을까? AOP를 사용해야 하진 않았을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나씩 개념부터 정리하며, 적절했는지를 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Filter&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;개념부터 정리&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Web Application&lt;/b&gt;&lt;/span&gt;에서 관리되는 영역으로써 Spring Boot Framework 에서 &lt;b&gt;Client로 부터 오는 요청/응답에 대해서 최초/최종 단계에 존재&lt;/b&gt;하며, 이를 통해 &lt;b&gt;요청/응답의 정보를 변경하거나&lt;/b&gt;, Spring에 의해서 데이터가 변환되기 전의&lt;b&gt; 순수한 Client의 요청/응답 값을 확인&lt;/b&gt;할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666;&quot;&gt;정리하면 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Web Application에서 관리되는 영역&lt;/li&gt;
&lt;li&gt;Client로부터 오는 요청/응답에 대해, 최초/최종 단계에 존재 (DispatcherServlet 외부)&lt;/li&gt;
&lt;li&gt;요청/응답의 정보를 변경하거나 Client의 요청/응답 값을 확인&lt;/li&gt;
&lt;li&gt;유일하게 ServletRequest, ServletResponse의 객체를 변환할 수 있음&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Web Application 영역&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Web Application에서 관리되는 영역&lt;/b&gt;&lt;/span&gt;이라고 하였다. 이게 무슨 의미일까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 요청을 처리하는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;DispatcherServlet의 앞단&lt;/b&gt;&lt;/span&gt;에서 실행된다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;DistpatcherServlet도 하나의 Servlet이고 Servlet Container가 관리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Servlet Container에 의해 관리되는 영역&lt;/b&gt;&lt;/span&gt;이라는 뜻이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;245&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7MkKX/btrJ2pn0ljp/EjA3JJCXEunCZnkr20UhU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7MkKX/btrJ2pn0ljp/EjA3JJCXEunCZnkr20UhU1/img.png&quot; data-alt=&quot;필터의 실행&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7MkKX/btrJ2pn0ljp/EjA3JJCXEunCZnkr20UhU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7MkKX%2FbtrJ2pn0ljp%2FEjA3JJCXEunCZnkr20UhU1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;245&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;245&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;필터의 실행&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한가지 의문인 것은 Filter도 @Component 로 등록해서 사용했다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 새롭게 알게된 부분인데, 아무렇지 않게 Filter를 적용하여 썼으나 사실 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;이전에는 서블릿 컨테이너가 관리하는 영역이다 보니, Bean으로 등록이나 주입이 불가능했다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;DelegatingFilterProxy&lt;/b&gt;&lt;/span&gt;라는 것을 지원하기 시작하면서부터, 스프링에서 관리가 가능해졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;DelegatingFilterProxy는 Servlet Filter와 Spring Bean Filter를 서로 연결해주는 매개체 역할을 하는 proxy다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Client로부터 오는 요청/응답에 대해, 최초/최종 단계에 존재&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 설명했지만, DispatcherServlet의 앞에 존재한다는 내용으로 보면 될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;요청/응답의 정보를 변경하거나 Client의 요청/응답 값을 확인&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pure한 Client의 요청/응답(객체로 매핑되지 않은 상태)을 알 수 있고, 그에 따라 요청/응답의 정보를 임의로 변경할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니, XSS나 CORS, Encoding, Logging 혹은 인증과 관련된 로직을 한번에 처리하는 역할을 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;유일하게 ServletRequest, ServletResponse의 객체를 변환할 수 있음&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래, 실습으로 확인하겠지만, ServletRequest와 ServletResponse의 객체를 변환할 수 있는 유일한 곳이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Filter 실습&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;java&quot; data-role=&quot;codeBlock&quot; data-info=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
  private String name;
  private int age;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;java&quot; data-role=&quot;codeBlock&quot; data-info=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Slf4j
@RestController
@RequestMapping(&quot;/api&quot;)
public class ApiController {

  @PostMapping(&quot;&quot;)
  public User user(@RequestBody User user) {
    log.info(&quot;User : {}, {}&quot;, user, user); // {} 안에 toString 값 들어감
    return user;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;java&quot; data-role=&quot;codeBlock&quot; data-info=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Slf4j
@Component
public class GlobalFilter implements Filter {
  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    // 전처리

    // 형변환 -&amp;gt; Filter에서는 형변환이 가능하고, HttpServletRequest는 ServletRequest를 상속받기 때문에 가능
    HttpServletRequest httpServletRequest = (HttpServletRequest) request;
    HttpServletResponse httpServletResponse = (HttpServletResponse) response;

    String url = httpServletRequest.getRequestURI();

    BufferedReader br = httpServletRequest.getReader();

    br.lines().forEach(line -&amp;gt; {
      log.info(&quot;url : {}, line : {}&quot;, url, line);
    });

    chain.doFilter(httpServletRequest, httpServletResponse);

    // 후처리
    
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 Filter에 사용하는 Override된 method들은 &lt;a href=&quot;https://docs.oracle.com/javaee/7/api/javax/servlet/Filter.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;다음 문서&lt;/a&gt;를 참고하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 내용은 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;에러(Cannot&amp;nbsp;call&amp;nbsp;getInputStream(),&amp;nbsp;getReader()&amp;nbsp;already&amp;nbsp;called)&lt;/b&gt;&lt;/span&gt;가 나온다.&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2022-08-18&amp;nbsp;23:32:04.906&amp;nbsp;&amp;nbsp;INFO&amp;nbsp;20120&amp;nbsp;---&amp;nbsp;[&amp;nbsp;&amp;nbsp;XNIO-1&amp;nbsp;task-1]&amp;nbsp;TestFilter&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;url&amp;nbsp;:&amp;nbsp;/api,&amp;nbsp;line&amp;nbsp;:&amp;nbsp;{ &lt;br /&gt;2022-08-18&amp;nbsp;23:32:04.908&amp;nbsp;&amp;nbsp;INFO&amp;nbsp;20120&amp;nbsp;---&amp;nbsp;[&amp;nbsp;&amp;nbsp;XNIO-1&amp;nbsp;task-1]&amp;nbsp;TestFilter&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;url&amp;nbsp;:&amp;nbsp;/api,&amp;nbsp;line&amp;nbsp;:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;name&quot;:&amp;nbsp;&quot;name&quot;, &lt;br /&gt;2022-08-18&amp;nbsp;23:32:04.908&amp;nbsp;&amp;nbsp;INFO&amp;nbsp;20120&amp;nbsp;---&amp;nbsp;[&amp;nbsp;&amp;nbsp;XNIO-1&amp;nbsp;task-1]&amp;nbsp;TestFilter&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;url&amp;nbsp;:&amp;nbsp;/api,&amp;nbsp;line&amp;nbsp;:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;age&quot;:&amp;nbsp;1 &lt;br /&gt;2022-08-18&amp;nbsp;23:32:04.908&amp;nbsp;&amp;nbsp;INFO&amp;nbsp;20120&amp;nbsp;---&amp;nbsp;[&amp;nbsp;&amp;nbsp;XNIO-1&amp;nbsp;task-1]&amp;nbsp;TestFilter&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;url&amp;nbsp;:&amp;nbsp;/api,&amp;nbsp;line&amp;nbsp;:&amp;nbsp;} &lt;br /&gt;2022-08-18&amp;nbsp;23:32:04.960&amp;nbsp;ERROR&amp;nbsp;20120&amp;nbsp;---&amp;nbsp;[&amp;nbsp;&amp;nbsp;XNIO-1&amp;nbsp;task-1]&amp;nbsp;io.undertow.request&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;:&amp;nbsp;UT005023:&amp;nbsp;Exception&amp;nbsp;handling&amp;nbsp;request&amp;nbsp;to&amp;nbsp;/api &lt;br /&gt;&lt;br /&gt;org.springframework.web.util.NestedServletException:&amp;nbsp;Request&amp;nbsp;processing&amp;nbsp;failed;&amp;nbsp;nested&amp;nbsp;exception&amp;nbsp;is&amp;nbsp;java.lang.IllegalStateException:&amp;nbsp;UT010003:&amp;nbsp;Cannot&amp;nbsp;call&amp;nbsp;getInputStream(),&amp;nbsp;getReader()&amp;nbsp;already&amp;nbsp;called &lt;br /&gt;at&amp;nbsp;org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)&amp;nbsp;~[spring-webmvc-5.3.22.jar:5.3.22] &lt;br /&gt;at&amp;nbsp;org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)&amp;nbsp;~[spring-webmvc-5.3.22.jar:5.3.22]&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주석에 나온 것처럼, BufferdReader는 Stream으로 데이터를 처리하고 소비하는 역할이지, 저장하지 못한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 해결하기 위해, SpringBoot에서는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;ContentCachingRequestWrapper, &lt;b&gt;ContentCachingResponseWrapper&lt;/b&gt;&lt;/b&gt;&lt;/span&gt; 를 제공한다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {
    LOG.debug(&quot;doFilter&quot;);
    // 전처리

    ContentCachingRequestWrapper httpServletRequest = new ContentCachingRequestWrapper((HttpServletRequest) request);
    ContentCachingResponseWrapper httpServletResponse = new ContentCachingResponseWrapper((HttpServletResponse) response);

    String url = httpServletRequest.getRequestURI();

    BufferedReader br = httpServletRequest.getReader();

    br.lines().forEach(line -&amp;gt; {
        log.info(&quot;url : {}, line : {}&quot;, url, line);
    });

    chain.doFilter(httpServletRequest, httpServletResponse);
    // 후처리
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 또다른 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;에러(&lt;span style=&quot;background-color: #fafafa;&quot;&gt;Required&amp;nbsp;request&amp;nbsp;body&amp;nbsp;is&amp;nbsp;missing&lt;/span&gt;)&lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;가 나온다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2022-08-18&amp;nbsp;23:30:12.314&amp;nbsp;&amp;nbsp;INFO&amp;nbsp;15352&amp;nbsp;---&amp;nbsp;[&amp;nbsp;&amp;nbsp;XNIO-1&amp;nbsp;task-2]&amp;nbsp;TestFilter&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;url&amp;nbsp;:&amp;nbsp;/api,&amp;nbsp;line&amp;nbsp;:&amp;nbsp;{ &lt;br /&gt;2022-08-18&amp;nbsp;23:30:12.314&amp;nbsp;&amp;nbsp;INFO&amp;nbsp;15352&amp;nbsp;---&amp;nbsp;[&amp;nbsp;&amp;nbsp;XNIO-1&amp;nbsp;task-2]&amp;nbsp;TestFilter&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;url&amp;nbsp;:&amp;nbsp;/api,&amp;nbsp;line&amp;nbsp;:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;name&quot;:&amp;nbsp;&quot;name&quot;, &lt;br /&gt;2022-08-18&amp;nbsp;23:30:12.314&amp;nbsp;&amp;nbsp;INFO&amp;nbsp;15352&amp;nbsp;---&amp;nbsp;[&amp;nbsp;&amp;nbsp;XNIO-1&amp;nbsp;task-2]&amp;nbsp;TestFilter&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;url&amp;nbsp;:&amp;nbsp;/api,&amp;nbsp;line&amp;nbsp;:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;age&quot;:&amp;nbsp;1 &lt;br /&gt;2022-08-18&amp;nbsp;23:30:12.314&amp;nbsp;&amp;nbsp;INFO&amp;nbsp;15352&amp;nbsp;---&amp;nbsp;[&amp;nbsp;&amp;nbsp;XNIO-1&amp;nbsp;task-2]&amp;nbsp;TestFilter&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;url&amp;nbsp;:&amp;nbsp;/api,&amp;nbsp;line&amp;nbsp;:&amp;nbsp;} &lt;br /&gt;2022-08-18&amp;nbsp;23:30:12.314&amp;nbsp;&amp;nbsp;WARN&amp;nbsp;15352&amp;nbsp;---&amp;nbsp;[&amp;nbsp;&amp;nbsp;XNIO-1&amp;nbsp;task-2]&amp;nbsp;.w.s.m.s.DefaultHandlerExceptionResolver&amp;nbsp;:&amp;nbsp;Resolved&amp;nbsp;[org.springframework.http.converter.HttpMessageNotReadableException:&amp;nbsp;Required&amp;nbsp;request&amp;nbsp;body&amp;nbsp;is&amp;nbsp;missing:&amp;nbsp;public&amp;nbsp;co&lt;a href=&quot;http://m.example.demo.cli.dto.User&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;m.example.demo.cli.dto.User&lt;/a&gt;&amp;nbsp;com.example.demo.cli.Controller.ApiController.user(com.example.demo.cli.dto.User)]&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;그 생성자를 한번 보자.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public ContentCachingRequestWrapper(HttpServletRequest request) {
   super(request);
   int contentLength = request.getContentLength();
   this.cachedContent = new ByteArrayOutputStream(contentLength &amp;gt;= 0 ? contentLength : 1024);
   this.contentCacheLimit = null;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;request의 길이를 저장해두고, 실제로 내용은 나중에 넣어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;후처리&lt;/b&gt;&lt;/span&gt; 때 적용된다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        LOG.debug(&quot;doFilter&quot;);
        // 전처리
        ContentCachingRequestWrapper httpServletRequest = new ContentCachingRequestWrapper((HttpServletRequest) request);
        ContentCachingResponseWrapper httpServletResponse = new ContentCachingResponseWrapper((HttpServletResponse) response);

        chain.doFilter(httpServletRequest, httpServletResponse);
        // 후처리
        String url = httpServletRequest.getRequestURI();
        String reqContent = new String(httpServletRequest.getContentAsByteArray());
        LOG.info(&quot;request url : {}, request body : {}&quot;, url, reqContent);

        String resContent = new String(httpServletResponse.getContentAsByteArray());
        int httpStatus = httpServletResponse.getStatus();

        LOG.info(&quot;response status : {}, response body : {}&quot;, httpStatus, resContent);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그는 잘 찍혔는데, 정작 응답값은 비정상으로 나오는 것이 확인될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;getContentAsByteArray&lt;/b&gt;&lt;/span&gt; 역시, Stream이기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {
    // 전처리
    ContentCachingRequestWrapper httpServletRequest = new ContentCachingRequestWrapper((HttpServletRequest) request);
    ContentCachingResponseWrapper httpServletResponse = new ContentCachingResponseWrapper((HttpServletResponse) response);


    chain.doFilter(httpServletRequest, httpServletResponse);
    // 후처리
    String url = httpServletRequest.getRequestURI();
    // req
    String reqContent = new String(httpServletRequest.getContentAsByteArray());
    LOG.info(&quot;request url : {}, request body : {}&quot;, url, reqContent);

    String resContent = new String(httpServletResponse.getContentAsByteArray());
    int httpStatus = httpServletResponse.getStatus();

    httpServletResponse.copyBodyToResponse();
    LOG.info(&quot;response status : {}, response body : {}&quot;, httpStatus, resContent);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 정상적으로 적용되는 것을 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이, Logging 처리에 사용할 수 있고, &lt;b&gt;Session 확인 후 Response를 바로 내버리는(401, 403 등)&lt;/b&gt; 역할이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, 인증은 Interceptor에서 구현을 많이 하는 편이니 참고하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, @WebFilter를 사용하면, 특정 URL에 대해서만 적용할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-role=&quot;codeBlock&quot; data-info=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Slf4j
@WebFilter(urlPatterns = &quot;/api/user/*&quot;) // 특정 URL 지정
public class GlobalFilter implements Filter {

  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    // 전처리
    ContentCachingRequestWrapper httpServletRequest = new ContentCachingRequestWrapper((HttpServletRequest) request);
    ContentCachingResponseWrapper httpServletResponse = new ContentCachingResponseWrapper((HttpServletResponse) response);


    chain.doFilter(httpServletRequest, httpServletResponse);
    // 후처리
    String url = httpServletRequest.getRequestURI();
    // req
    String reqContent = new String(httpServletRequest.getContentAsByteArray());
    log.info(&quot;request url : {}, request body : {}&quot;, url, reqContent);

    String resContent = new String(httpServletResponse.getContentAsByteArray());
    int httpStatus = httpServletResponse.getStatus();

    httpServletResponse.copyBodyToResponse();
    log.info(&quot;response status : {}, response body : {}&quot;, httpStatus, resContent);
  }

}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Interceptor&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 Interceptor로 가보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서, Filter랑 비교해서 보는 것도 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Spring Context에서 관리&lt;/li&gt;
&lt;li&gt;어떤 메서드를 사용하는지 알 수 있다.&lt;/li&gt;
&lt;li&gt;AOP와 유사하게 사용할 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Spring Context에서 관리&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 앞에서 보았지만, Interceptor는 DispatcherServlet 뒤에 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, Spring Context에 등록된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;어떤 메서드를 사용하는지 알 수 있다.&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이미 Controller 매핑까지 끝난 상태로 전달받기 때문에, 어떤 메서드를 사용하는지도 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, &lt;b&gt;선/후처리로 Service Business Logic과 분리하여 사용할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;AOP와 유사하게 사용할 수 있다.&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하단의 예시와 이전 &lt;a href=&quot;https://koocci-dev.tistory.com/72?category=1012333&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AOP 예시&lt;/a&gt;를 비교해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Interceptor 실습&lt;/b&gt;&lt;/h4&gt;
&lt;pre data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Documented // javadoc2으로 api 문서를 만들 때 어노테이션에 대한 설명도 포함하도록 지정해주는 것
@Retention(RetentionPolicy.RUNTIME) // 어노테이션의 유지 정책을 설정
@Target({ElementType.TYPE, ElementType.METHOD}) // 어노테이션을 적용할 수 있는 위치
public @interface Auth {
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Auth
@Slf4j
@RestController
@RequestMapping(&quot;/api/private&quot;)
public class PrivateController {
    private final Logger LOG = LoggerFactory.getLogger(this.getClass().getSimpleName());

    @PostMapping(&quot;hello&quot;)
    public String user() {
        return &quot;PRIVATE HELLO&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Slf4j
@RestController
@RequestMapping(&quot;/api/public&quot;)
public class PublicController {
    private final Logger LOG = LoggerFactory.getLogger(this.getClass().getSimpleName());

    @PostMapping(&quot;hello&quot;)
    public String user() {
        return &quot;PUBLIC HELLO&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1660835207241&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Slf4j
@Component
public class AuthInterceptor implements HandlerInterceptor {

  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    String url = request.getRequestURI();
    URI uri = UriComponentsBuilder.fromUriString(request.getRequestURI())
        .query(request.getQueryString()) // Query 가져오기
        .build()
        .toUri();
    log.info(&quot;request URL : {}&quot;, url);
    // 권한 체크할 예정
    boolean hasAnnotation = checkAnnotation(handler, Auth.class);
    log.info(&quot;hasAnnotation : {}&quot;, hasAnnotation);

    // 조건 : 모두 Public으로 동작하지만, Auth 권한을 가진 요청에 대해서는 세션/쿠키/RequestParam 등을 체크하겠다.
    if(hasAnnotation) {
      // 권한 체크
      String query = uri.getQuery();
      log.info(&quot;query : {}&quot;, query);
      if(query.equals(&quot;name=steve&quot;)) {
        return true;
      }
      return false;
    }
    return true;
  }

  private boolean checkAnnotation(Object handler, Class clazz) {
    // resource는 통과 시켜야 함
    if(handler instanceof ResourceHttpRequestHandler){
      return true;
    }

    // Annotation 체크
    HandlerMethod handlerMethod = (HandlerMethod) handler;
    // 해당 클래스에 Annotation이 있는지 확인
    if(null != handlerMethod.getMethodAnnotation(clazz) || null != handlerMethod.getBeanType().getAnnotation(clazz)) {
      // Auth annotation이 있는 경우 True
      return true;
    }

    return false;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;@Configuration
@RequiredArgsConstructor
public class MvcConfig implements WebMvcConfigurer {

    private final AuthInterceptor authInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authInterceptor);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 AuthException을 적용해주면서, 최종적으로 확인해보자.&lt;/p&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;public class AuthException extends RuntimeException{
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(AuthException.class)
    public ResponseEntity authException() {
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    String url = request.getRequestURI();
    URI uri = UriComponentsBuilder.fromUriString(request.getRequestURI())
            .query(request.getQueryString()) // Query 가져오기
            .build()
            .toUri();
    log.info(&quot;request URL : {}&quot;, url);
    // 권한 체크할 예정
    boolean hasAnnotation = checkAnnotation(handler, Auth.class);
    log.info(&quot;hasAnnotation : {}&quot;, hasAnnotation);

    if(hasAnnotation) {
        // 권한 체크
        String query = uri.getQuery();
        log.info(&quot;query : {}&quot;, query);
        if(query.equals(&quot;name=steve&quot;)) {
            return true;
        }
        throw new AuthException();
    }
    return true;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Wrap Up&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 전체적으로 정리해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Filter&lt;/b&gt;&lt;/span&gt;는 Web Application 관리 영역으로, ServletRequest/ServletResponse를 변환할 수 있는 유일한 구간이자, Client의 Pure한 요청을 보고, Request/Response의 양 종단간의 데이터를 확인할 수 있다. (DispatcherServlet 외부)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통, Logging, XSS, CORS, Encoding 등에 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Interceptor&lt;/b&gt;&lt;/span&gt;는 Spring Context 영역으로, 빈으로 관리되어, 메서드 단위까지 확인이 가능하며, AOP기능과 유사하게 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통, 인증이나 Logging에 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 내가 사용한 방법은 적절했을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;전체 Req/Res 로그를 남기길 원할 때, XSS 를 막을 때에 대해 적절히 Filter를 썼으며, Auth와 관련한 로직은 Interceptor로 쓰며, 메뉴 관리까지 하였다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞으로는 더 다양한 방법을 사용해 볼 수 있도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Framework/Spring</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/79</guid>
      <comments>https://koocci-dev.tistory.com/79#entry79comment</comments>
      <pubDate>Fri, 19 Aug 2022 00:19:48 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] DispatcherServlet이 뭘까?</title>
      <link>https://koocci-dev.tistory.com/78</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : DispatcherServlet에 대해 설명할 수 있다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#spring-web&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SpringMVC에 대해 처음 설명&lt;/a&gt;하는 사항이 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;DispatcherServlet&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대체 무엇이길래 제일 처음부터 설명하는 것일까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DispatcherServlet&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;SpringMVC&lt;/b&gt;&lt;/span&gt;는 Spring Framework에 최초부터 들어있던 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Servlet API 기반의 웹 프레임워크&lt;/b&gt;&lt;/span&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 한번 &lt;a href=&quot;https://koocci-dev.tistory.com/57?category=1012333&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;복습&lt;/a&gt;해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Servlet&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Servlet&lt;/b&gt;&lt;/span&gt; : &lt;b&gt;정적인 HTML의 한계를 극복하고&lt;/b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;자바를 사용하여 웹페이지를 동적으로 생성하는 서버측 프로그램 혹은 그 사양&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;Servlet Container&lt;/span&gt; : Servlet Interface의 구현체로서, Servlet의 LifeCycle(Init, Destroy, Service)을 구현하고 있으며 구동 환경을 제공하여 Servlet을 관리. (Apache Tomcat, Jeus 등)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Servlet Container 구동 순서&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Servlet Container가 시작 시, 모든 Servlet을 가지고 있는다.&lt;/li&gt;
&lt;li&gt;Client로부터 요청이 들어왔을 때, Request(HttpServletRequest)와 Response(HttpServletResponse) Instance 를 생성한다.&lt;/li&gt;
&lt;li&gt;요청 URL을 분석하여, 어떤 Servlet이 담당인지 찾고, 해당 Servlet의 쓰레드에 Request와 Response 객체를 전달한다.
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Servlet의 Service() 메서드를 호출해, Request와 Response를 전달하고 메소드에 따라 doGet, doPost등을 호출한다.&lt;/li&gt;
&lt;li&gt;해당 메서드에서response에 응답내용을 넣는다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Servlet Container는 Response를 Client에게 전달하고, Request와 Response를 소멸시킨다.&lt;/li&gt;
&lt;li&gt;Servlet Instance 자체는 사라지지 않고, Servlet Container가 멈추기 전까지 요청에 대한 처리를 수행한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1212&quot; data-origin-height=&quot;626&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qRsCV/btrJSmdvOnj/JfXsGalG7IyFKybUcTEck0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qRsCV/btrJSmdvOnj/JfXsGalG7IyFKybUcTEck0/img.png&quot; data-alt=&quot;Servlet 상속관계&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qRsCV/btrJSmdvOnj/JfXsGalG7IyFKybUcTEck0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqRsCV%2FbtrJSmdvOnj%2FJfXsGalG7IyFKybUcTEck0%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1212&quot; height=&quot;626&quot; data-origin-width=&quot;1212&quot; data-origin-height=&quot;626&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Servlet 상속관계&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;DispatcherServlet&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 Servlet이 무엇인지 알고 있으니, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;DispatcherServlet&lt;/b&gt;&lt;/span&gt;이 어떻게 다른지 알아볼 차례다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공식 문서에서는 다음과 같이 표현하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;Spring MVC, as many other web frameworks, is designed around &lt;span style=&quot;color: #ee2323;&quot;&gt;the front controller pattern&lt;/span&gt; where a central&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;Servlet&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;, the&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;DispatcherServlet&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;, provides a shared algorithm for request processing, while &lt;span style=&quot;color: #ee2323;&quot;&gt;actual work is performed by configurable delegate components.&lt;/span&gt; This model is flexible and supports diverse workflows.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;DispatcherServlet&lt;/b&gt;&lt;/span&gt;은 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;중앙 서블릿이며,요청 처리를 위한 공유 알고리즘을 제공하는 반면 실제 작업은 구성 가능한 대리자 구성 요소에 의해 수행되는 Front Controller 패턴으로 설계되었다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;너무 번역투이니 조금 정리해보면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Front Controller 패턴&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;으로 설계되어, 모든 요청처리를 가장 먼저 받고, 실질적으로 일하는 적합한 Component(Controller)에게 위임하는 역할&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DispatcherServlet은 다른 Servlet과 마찬가지로, web.xml이나 java configuration으로 선언된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같이 설정하면, Servlet Container에서 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;자동으로 찾아서 설정&lt;/b&gt;&lt;/span&gt;하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;(SpringBootServletInitializer의 경우, 내부적으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;WebApplicationInitializer를 구현하고 있는 Abstract Class다.)&lt;/p&gt;
&lt;pre id=&quot;code_1660654481908&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class MyWebApplicationInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) {

        // Load Spring web application configuration
        AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
        context.register(AppConfig.class);

        // Create and register the DispatcherServlet
        DispatcherServlet servlet = new DispatcherServlet(context);
        ServletRegistration.Dynamic registration = servletContext.addServlet(&quot;app&quot;, servlet);
        registration.setLoadOnStartup(1);
        registration.addMapping(&quot;/app/*&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹은 Web.xml로 설정하는 방법도 제공한다.&lt;/p&gt;
&lt;pre id=&quot;code_1660654533929&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;web-app&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;context-param&amp;gt;
        &amp;lt;param-name&amp;gt;contextConfigLocation&amp;lt;/param-name&amp;gt;
        &amp;lt;param-value&amp;gt;/WEB-INF/app-context.xml&amp;lt;/param-value&amp;gt;
    &amp;lt;/context-param&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;contextConfigLocation&amp;lt;/param-name&amp;gt;
            &amp;lt;param-value&amp;gt;&amp;lt;/param-value&amp;gt;
        &amp;lt;/init-param&amp;gt;
        &amp;lt;load-on-startup&amp;gt;1&amp;lt;/load-on-startup&amp;gt;
    &amp;lt;/servlet&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 data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;왜 DispatcherServlet이 사용되었을까?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Web.xml에서 Servlet 매핑을 줄여주었다.&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 Servlet에 대해 요청URL과 매핑해주어야 했던 이전과 달리, DispatcherServlet이 Front Controller를 해주므로, Controller를 수현해두기만 하면, DispatcherServlet이 알아서 위임해주게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;공통된 처리를 할 수 있다.&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인코딩, 에러 처리, 공지 등에 대한 처리를 한번에 해결할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;DispatcherServlet의 흐름&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 전체 흐름을 한번 그려보자.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;서블릿 컨테이너는 시작 시, 모든 Servlet을 가지고 있다.&lt;/li&gt;
&lt;li&gt;Client의 요청이 들어오면, 제일 먼저 DispatcherServlet이 요청을 받는다.&lt;/li&gt;
&lt;li&gt;공통적인 작업을 먼저 DispatcherServlet이 처리한다.&lt;/li&gt;
&lt;li&gt;URL을 분석해 알맞는 Controller(Servlet)를 찾는다.&lt;/li&gt;
&lt;li&gt;요청을 컨트롤러로 위임할 Handler mapping을 찾아서 전달한다. (Controller로 전달하려면 어떤 Mapping을 가져올지 확인)&lt;/li&gt;
&lt;li&gt;Handler Adapter를 통해 요청을 위임한다. (Mapping된 Adapter로 위임)&lt;/li&gt;
&lt;li&gt;Service 로직(Business 로직) 실행&lt;/li&gt;
&lt;li&gt;응답 반환 (Controller -&amp;gt; Adapter -&amp;gt; DispatcherServlet)&lt;/li&gt;
&lt;li&gt;Client로 반환&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Wrap up&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조금 더 자세한 내용들이 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파고들면 파고들수록 까다로운 Spring이다.&lt;/p&gt;</description>
      <category>Framework/Spring</category>
      <category>DispatcherServlet</category>
      <category>spring</category>
      <category>스프링</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/78</guid>
      <comments>https://koocci-dev.tistory.com/78#entry78comment</comments>
      <pubDate>Tue, 16 Aug 2022 22:34:26 +0900</pubDate>
    </item>
    <item>
      <title>Heap 메모리 구조와 GC는 어떻게 될까?</title>
      <link>https://koocci-dev.tistory.com/77</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : Heap 메모리와 GC에 대해 설명할 수 있다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞선 포스팅으로 JVM 내부 메모리 구조를 알아보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 중, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Heap&lt;/b&gt;&lt;/span&gt; 메모리에 대한 상세한 설명을 추가하고자 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Garbage Collection&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Heap을 설명한다 했지만, GC부터 알아보려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Heap과 자연스럽게 연결될 것이며, 일단 용어를 좀 정리해야 설명하기 편할 것 같아서다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;JVM&lt;/b&gt;&lt;/span&gt;은 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;자동으로 메모리를 관리해준다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;GC&lt;/b&gt;&lt;/span&gt;는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;더이상 사용되지 않는 인스턴스(Referrer가 없는 Object)를 찾아 메모리 할당을 삭제하는 행위&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이 말은 JVM에서는 GC가 자동으로 일어난다는 것이고, 성능에 중요한 역할을 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;GC 혹은 메모리 설정이 잘못되면 금방 OOM(Out of Memory) Error가 발생할 것이다.&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이 때 말하는 메모리가 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Heap&lt;/b&gt;&lt;/span&gt;이며, Heap의 구조로 넘어가보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Heap 메모리 구조&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 그림으로 복습하면, JVM 내의 메모리 구조는 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;622&quot; data-origin-height=&quot;539&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Dl3E5/btrJO1thOtN/Jk9eWIqQM4f6iZVRAXZ2Z1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Dl3E5/btrJO1thOtN/Jk9eWIqQM4f6iZVRAXZ2Z1/img.png&quot; data-alt=&quot;JVM 메모리 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Dl3E5/btrJO1thOtN/Jk9eWIqQM4f6iZVRAXZ2Z1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDl3E5%2FbtrJO1thOtN%2FJk9eWIqQM4f6iZVRAXZ2Z1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;622&quot; height=&quot;539&quot; data-origin-width=&quot;622&quot; data-origin-height=&quot;539&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;JVM 메모리 구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 중, Heap 영역을 잘게 쪼개어 보도록 하자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;649&quot; data-origin-height=&quot;419&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yog1i/btrJFPVKs1C/iXQYgVYhc4FiiEJWV9yi30/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yog1i/btrJFPVKs1C/iXQYgVYhc4FiiEJWV9yi30/img.jpg&quot; data-alt=&quot;Heap Memory&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yog1i/btrJFPVKs1C/iXQYgVYhc4FiiEJWV9yi30/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fyog1i%2FbtrJFPVKs1C%2FiXQYgVYhc4FiiEJWV9yi30%2Fimg.jpg&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; loading=&quot;lazy&quot; width=&quot;649&quot; height=&quot;419&quot; data-origin-width=&quot;649&quot; data-origin-height=&quot;419&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Heap Memory&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 Java8부터 달라진 부분 부터 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Native Memory&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Native Memory&lt;/b&gt;&lt;/span&gt;는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;JVM에서 사용하는 메모리&lt;/b&gt;&lt;/span&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Perm 부분(PermGen)&lt;/b&gt;&lt;/span&gt;은 &lt;b&gt;Class 메타 정보나, Method의 메타 정보, static 변수와 상수 정보들이 저장되는 공간으로 흔히 메타데이터 저장 영역&lt;/b&gt;이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정의가 뭔가 중복되는 걸 알아야 하며, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Method Area&lt;/b&gt;&lt;/span&gt;에 저장되는 정보와 유사하다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공부하면서 궁금하여, 한번 찾아보았더니 유사한 내용을 궁금해한 사람이 많았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 중, &lt;a href=&quot;https://blog.naver.com/simjunbo/221080829920&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;다음 블로그&lt;/a&gt;에서 가장 얻고 싶은 정보를 얻을 수 있었는데, 결국 결론은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JVM 벤더마다 다양하게 구현할 수 있지만 HotSpot JVM 기준으로, &lt;b&gt;Method Area = PermGen으로 할 수 있으며, Non-Heap 영역이라는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하여튼, 현재는 Perm 영역은 없어지고, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Metaspace&lt;/b&gt;&lt;/span&gt;라는 영역으로 바뀌었으며, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Native Memory로 포함&lt;/b&gt;&lt;/span&gt;되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Young Generation (Eden + Survivor)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 Heap 영역으로 넘어와서, 먼저 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Young Generation&lt;/b&gt;&lt;/span&gt;에 대해 알아볼 차례다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Young Generation은 쉽게 말해 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;짧게 살아남은 메모리들이 존재하는 공간&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오래 살아남은 친구들에 비해, 작은 공간에 존재하며, 그만큼 메모리 상의 객체를 빨리 찾을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, Young Generation에서 이루어지는 GC는&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt; Minor GC&lt;/b&gt;&lt;/span&gt;라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Young Generation은&lt;span style=&quot;color: #ee2323;&quot;&gt; &lt;b&gt;Eden 영역&lt;/b&gt;&lt;/span&gt;과 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Survivor 영역&lt;/b&gt;&lt;/span&gt;으로 나누어진다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;355&quot; data-origin-height=&quot;665&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bG3Stj/btrJKtxBNrn/usMGMQAcY20X53azD2keAK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bG3Stj/btrJKtxBNrn/usMGMQAcY20X53azD2keAK/img.png&quot; data-alt=&quot;Young Generation GC&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bG3Stj/btrJKtxBNrn/usMGMQAcY20X53azD2keAK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbG3Stj%2FbtrJKtxBNrn%2FusMGMQAcY20X53azD2keAK%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;355&quot; height=&quot;665&quot; data-origin-width=&quot;355&quot; data-origin-height=&quot;665&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Young Generation GC&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;new로 생성된 객체가 있다고 하자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 객체는 처음에 이 Young Generation의 Eden 영역에 생성된다.&lt;/li&gt;
&lt;li&gt;Eden 영역이 Full이 되었을 때, 메모리 복사가 일어난다.&lt;/li&gt;
&lt;li&gt;Minor GC가 일어나게 되며, Eden 내의 객체를 검사해, 사용되지 않는(레퍼런스가 없는)객체를 해제한다.&lt;/li&gt;
&lt;li&gt;살아남은 객체들은 From Space (Survivor 영역)으로 이동된다.&lt;/li&gt;
&lt;li&gt;Eden이 또다시 Full이 되었을 때, From Space에서 살아남은 친구들은 To Space로 이동한다.&lt;/li&gt;
&lt;li&gt;특정 횟수 (&lt;span style=&quot;background-color: #ffffff;&quot;&gt;-XX:MaxTenuringThreshold=32) 를 반복하고도 살아남으면, Old Generation으로 이동된다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;Old Generation&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;Young Generation에서 살아남은 객체들은 아주 큰 공간인 Old Generation으로 이동된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;크기가 큰 만큼, GC는 적개 발생되며, 이 영역에서 발생하는 GC를 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Major GC&lt;/b&gt;&lt;/span&gt;라고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;GC 알고리즘&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333;&quot;&gt;GC에서는 크게 2가지가 발생한다.&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Stop The World(STW)&lt;/li&gt;
&lt;li&gt;Mark &amp;amp; Sweep&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Stop The World (STW)&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333;&quot;&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;STW(Stop The World)&lt;/b&gt;&lt;/span&gt;는 JVM이 Application의 실행을 멈추는 것을 말한다. 즉, GC가 실행될 때는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;GC에 대한 쓰레드를 제외하고 모든 쓰레드들의 작업이 중단&lt;/b&gt;&lt;/span&gt;된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;GC 튜닝이 STW를 줄이는 것에 목표가 있다는 것을 알면, 아주 큰 일이 발생한다고 볼 수 있다.&lt;/span&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Mark &amp;amp; Sweep (&amp;amp; Compact)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;STW는 Thread가 멈추고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Mark &amp;amp; Sweep&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;작업이 필요하다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Mark&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;: 객체가 현재 사용 중인지, 확인한다.&lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Sweep&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: Mark 처리가 된 객체를 메모리 주소 매핑을 삭제한다. (실제로 삭제한다기 보다, 정보만 지운다)&lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;*Compact&lt;/b&gt; &lt;/span&gt;: 디스크 조각모음 하듯이, 메모리 공간을 단편화시킨다. 알고리즘에 따라, 하지 않는 경우도 있다.&lt;b&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;GC 알고리즘 종류&lt;/b&gt;&lt;/h3&gt;
&lt;h4 id=&quot;3.1. Serial GC (-XX:+UseSerialGC)&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Serial GC (-XX:+UseSerialGC)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가장 단순한 GC로, 싱글 쓰레드로 동작한다.&lt;/li&gt;
&lt;li&gt;STW 시간이 그만큼 길다.&lt;/li&gt;
&lt;li&gt;Mark &amp;amp; Sweep &amp;amp; Compact 알고리즘을 사용한다.&lt;/li&gt;
&lt;li&gt;실무에선 거의 사용되지 않는다 (CPU 코어가 1개인 경우 사용)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;680&quot; data-origin-height=&quot;754&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cwH01S/btrJOZWHk9H/Mi71L7Dom9TD3kYtGQLKj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cwH01S/btrJOZWHk9H/Mi71L7Dom9TD3kYtGQLKj1/img.png&quot; data-alt=&quot;Serial GC&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cwH01S/btrJOZWHk9H/Mi71L7Dom9TD3kYtGQLKj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcwH01S%2FbtrJOZWHk9H%2FMi71L7Dom9TD3kYtGQLKj1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;680&quot; height=&quot;754&quot; data-origin-width=&quot;680&quot; data-origin-height=&quot;754&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Serial GC&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;3.2. Parallel GC (-XX:+UseParallelGC)&quot; class=&quot;head&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Parallel GC (-XX:+UseParallelGC)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;java 8의 기본 GC&lt;/li&gt;
&lt;li&gt;Young 영역의 GC를 Serial GC와 같지만, 멀티 쓰레드로 진행한다.&lt;/li&gt;
&lt;li&gt;STW는 상대적으로 Serial GC보다 짧다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;559&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DH3A8/btrJFPheYSq/XlRfXC4IkivmRyQOj2sqxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DH3A8/btrJFPheYSq/XlRfXC4IkivmRyQOj2sqxk/img.png&quot; data-alt=&quot;Parallel GC&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DH3A8/btrJFPheYSq/XlRfXC4IkivmRyQOj2sqxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDH3A8%2FbtrJFPheYSq%2FXlRfXC4IkivmRyQOj2sqxk%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;559&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;559&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Parallel GC&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 id=&quot;3.3. Parallel Old GC (-XX:+UseParallelOldGC / -XX:+ParallelGCThreads=n)&quot; class=&quot;head&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Parallel Old GC (-XX:+UseParallelOldGC / -XX:+ParallelGCThreads=n)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Old 영역에도 멀티쓰레드 방식을 적용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;3.4. CMS GC(Concurrent Mark Sweep GC)&quot; class=&quot;head&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;CMS GC(Concurrent Mark Sweep GC)&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;827&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9fjlf/btrJKt5zJVw/yDlreDLs8vtpMYS6RQl5n0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9fjlf/btrJKt5zJVw/yDlreDLs8vtpMYS6RQl5n0/img.png&quot; data-alt=&quot;Concurrent Mark Sweep GC&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9fjlf/btrJKt5zJVw/yDlreDLs8vtpMYS6RQl5n0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9fjlf%2FbtrJKt5zJVw%2FyDlreDLs8vtpMYS6RQl5n0%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;827&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;827&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Concurrent Mark Sweep GC&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;STW를 최소한으로 하기위해 만들어진 GC&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Reference가 있는 객체&lt;/b&gt;를 여러번에 나누어 찾는다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Initial Mark &lt;/b&gt;: GC Root가 참조하는 객체만 마킹 (stop-the-world 발생)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Concurrent Mark&lt;/b&gt;: 참조하는 객체를 따라가며, 지속적으로 마킹. (stop-the-world 없이 이루어짐)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Remark&lt;/b&gt; : concurrent mark 과정에서 변경된 사항이 없는지 다시 한번 마킹하며 확정하는 과정. (stop-the-world 발생)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Concurrent Sweep&lt;/b&gt; : 접근할 수 없는 객체를 제거하는 과정 (stop-the-world 없이 이루어짐)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;3.5. G1 GC (Garbage Frist GC) (-XX:+UseG1GC)&quot; class=&quot;head&quot; data-ke-size=&quot;size23&quot;&gt;G1 GC (Garbage Frist GC) (-XX:+UseG1GC)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;java 9+의 default GC&lt;/li&gt;
&lt;li&gt;현재 GC 중 stop-the-world의 시간이 제일 짧음&lt;/li&gt;
&lt;li&gt;CMS GC 를 개선하여 만든 GC로 위에서 살펴본 GC와는 다른 구조를 가진다.&lt;/li&gt;
&lt;li&gt;Heap을 Region이라는 일정한 부분으로 나눠서 메모리를 관리한다.&lt;/li&gt;
&lt;li&gt;전체 Heap에 대해서 탐색하지 않고 부분적으로 Region 단위로 탐색하여, 각각의 Region에만 GC가 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;333&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ev1ESn/btrJNjHJZJt/hUbmDUOaHgmdint1CbOJ9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ev1ESn/btrJNjHJZJt/hUbmDUOaHgmdint1CbOJ9k/img.png&quot; data-alt=&quot;G1 GC&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ev1ESn/btrJNjHJZJt/hUbmDUOaHgmdint1CbOJ9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fev1ESn%2FbtrJNjHJZJt%2FhUbmDUOaHgmdint1CbOJ9k%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;333&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;333&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;G1 GC&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Wrap Up&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JVM의 Heap 구조를 공부하고, GC에 대해서까지 알아보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GC자체를 프로젝트하면서 건들여본 적이 없기 때문에, 직접적으로 바로 알 수는 없었지만, 최소한의 개념을 알아두도록 하자.&lt;/p&gt;</description>
      <category>Programming/Java</category>
      <category>GC</category>
      <category>heap</category>
      <category>Java</category>
      <category>jvm</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/77</guid>
      <comments>https://koocci-dev.tistory.com/77#entry77comment</comments>
      <pubDate>Tue, 16 Aug 2022 01:06:41 +0900</pubDate>
    </item>
    <item>
      <title>JVM의 메모리 구조는 어떻게 될까?</title>
      <link>https://koocci-dev.tistory.com/76</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : JVM 메모리 구조를 설명할 수 있다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;JVM&lt;/b&gt;&lt;/span&gt;이 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;java Virtual Machine&lt;/b&gt; &lt;/span&gt;이라는 것은 잘 알고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, 이 구조에 대해 설명을 하려고 하면, 쉽지 않은 부분이 있어 정리하고자 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1213&quot; data-origin-height=&quot;883&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVHzA1/btrJFPVwq9n/Wx0UvuGLRnl0Il2juCYR1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVHzA1/btrJFPVwq9n/Wx0UvuGLRnl0Il2juCYR1k/img.png&quot; data-alt=&quot;JVM,JRE,JDK&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVHzA1/btrJFPVwq9n/Wx0UvuGLRnl0Il2juCYR1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVHzA1%2FbtrJFPVwq9n%2FWx0UvuGLRnl0Il2juCYR1k%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1213&quot; height=&quot;883&quot; data-origin-width=&quot;1213&quot; data-origin-height=&quot;883&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;JVM,JRE,JDK&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;왜 자바가 많이 사용되었을까?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근본적인 질문일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JVM을 설명하기 전에, Java의 특징 중 하나인 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;OS에 종속적이지 않다&lt;/b&gt;&lt;/span&gt;는 점을 설명하기 위한 질문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼, OS에 어떻게 종속받지 않은 환경을 만들었을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어디에서든 Java가 돌아갈 수 있게 감쌀 무언가가 필요했고, 그게 바로 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Java Virtual Machine&lt;/b&gt; &lt;/span&gt;이라고 하는&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt; JVM&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Java는 컴파일 언어다.&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java의 특징 중 또 다른 하나는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;컴파일 언어&lt;/b&gt;&lt;/span&gt;라는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;컴파일 언어&lt;/b&gt;&lt;/span&gt;라 함은, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;기계어로 번역하는 과정이 필요하며, 이에 따라 빌드 시간이 다소 소요되지만, 미리 컴파일 에러를 잡아낼 수 있고, 런타임 상황에서 빠른 실행이 가능하다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java는 컴파일 언어로서, 기계어로 번역하는 과정이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 처음 만든 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;.java&lt;/b&gt;&lt;/span&gt; 파일을 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;Bytecode&lt;/span&gt;로 변경하는 작업&lt;/b&gt;&lt;/span&gt;이 필요한 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;java compiler&lt;/b&gt;&lt;/span&gt;가 (&lt;b&gt;JDK(Java Development Kit) 의 javac&lt;/b&gt;) .java 파일을 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;.class라는 파일&lt;/b&gt;&lt;/span&gt;로 변환하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Java Bytecode to Binary Code&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.java 파일이 컴파일러에 의해 .class파일로 변경되며, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Java Bytecode&lt;/b&gt;&lt;/span&gt;가 된다는 사실을 알게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;J&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;ava Bytecode&lt;/b&gt;&lt;/span&gt;는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;JVM(가상 머신)이 이해할 수 있는 언어로 변환된 코드&lt;/b&gt;&lt;/span&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JVM이라는 가상환경이 Java와 OS간의 연결을 도와주는 매개체라고 생각해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 JVM은 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;OS가 이해할 수 있는 언어로 변환하는 과정&lt;/b&gt;&lt;/span&gt;이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OS가 이해하는 언어는&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt; Binary Code&lt;/b&gt;&lt;/span&gt; 즉 이진 코드이다. (CPU가 이해하는 언어)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;JIT Compiler&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Bytecode를 Binary Code로 바꾸려면, 또다시 변환과정이 필요하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전에는 RunTime시에 Interpreter로 적용되어 속도가 느렸지만, 요즘은 그 단점을 해소하기 위해 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;JIT(Just In Time) Compiler&lt;/b&gt;&lt;/span&gt;가 도입되어 있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;JIT(Just In Time) Compiler&lt;/b&gt; &lt;/span&gt;는 인터프리터 방식으로 실행하다 적절한 시점에 바이트코드 전체를 네이티브 코드(ex&amp;gt; 바이너리 코드)로 바꾼다. 그 다음부터 인터프리터는 네이티브 코드로 컴파일된 코드를 바로 사용한다. 즉, 한번 컴파일된 코드는 계속 빠르게 수행되게 된다.&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1004&quot; data-origin-height=&quot;573&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/V7sEZ/btrJGVHXRQf/yxZLSosp8Z947Xgzb41x2k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/V7sEZ/btrJGVHXRQf/yxZLSosp8Z947Xgzb41x2k/img.png&quot; data-alt=&quot;JIT Compiler&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/V7sEZ/btrJGVHXRQf/yxZLSosp8Z947Xgzb41x2k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FV7sEZ%2FbtrJGVHXRQf%2FyxZLSosp8Z947Xgzb41x2k%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1004&quot; height=&quot;573&quot; data-origin-width=&quot;1004&quot; data-origin-height=&quot;573&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;JIT Compiler&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;그림으로 이해해보자.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 우리가 만든 Java 파일이 어떻게 변환되어 OS까지 전달되는지 알수 있게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도식도를 보고 한번 더 이해해보도록 하자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;917&quot; data-origin-height=&quot;590&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cw8MBr/btrJKY4JOR6/0zAxFAQkr0U3PqKk8H06C0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cw8MBr/btrJKY4JOR6/0zAxFAQkr0U3PqKk8H06C0/img.png&quot; data-alt=&quot;JVM 구성&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cw8MBr/btrJKY4JOR6/0zAxFAQkr0U3PqKk8H06C0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcw8MBr%2FbtrJKY4JOR6%2F0zAxFAQkr0U3PqKk8H06C0%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;917&quot; height=&quot;590&quot; data-origin-width=&quot;917&quot; data-origin-height=&quot;590&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;JVM 구성&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;클래스 로더 (Class Loader)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JVM 내에 초기화, 클래스 파일(.class)을 로드하고, 링크를 통해 배치한다.&lt;/li&gt;
&lt;li&gt;.class 파일을 읽고 그 내용에 따라 바이너리 데이터를 만들어 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Method 영역&lt;/b&gt;&lt;/span&gt;에 저장한다. (메모리 구조는 다음 탭에서 보자)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;실행 엔진 (Excution Engine)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;앞서 알아본 바이너리 코드로 바꾸기 위한 Interpreter나 JIT Compiler가 존재한다.&lt;/li&gt;
&lt;li&gt;또한, GC가 있어, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;힙 메모리 영역&lt;/b&gt;&lt;/span&gt;에 생성된 객체들 중에서 참조되지 않은 객체들을 탐색하고 제거한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;JVM의 메모리는 어떻게 구성되어 있을까?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;JVM&lt;span style=&quot;color: #333333;&quot;&gt;에서는 &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #323232;&quot;&gt;프로그램을 수행하기 위해 OS로부터 메모리 공간들을 할당 받는다. &lt;span style=&quot;color: #006dd7;&quot;&gt;(즉 하나의 프로세스다)&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;그 공간들을 의미하는&lt;/span&gt;&lt;b&gt; Runtime Data Area&lt;/b&gt;&lt;/span&gt;에 대해 알아보기 위해 구체화된 다음 이미지를 보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;236&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o7z3c/btrJD3te4HI/ZRQv2osp8oOvWV6IfdhJjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o7z3c/btrJD3te4HI/ZRQv2osp8oOvWV6IfdhJjk/img.png&quot; data-alt=&quot;Runtime Data Area 1&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o7z3c/btrJD3te4HI/ZRQv2osp8oOvWV6IfdhJjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo7z3c%2FbtrJD3te4HI%2FZRQv2osp8oOvWV6IfdhJjk%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;236&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;236&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Runtime Data Area 1&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;645&quot; data-origin-height=&quot;545&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpZWF1/btrJEKNE7yC/m6gZLX10YmspMzpk7D0SKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpZWF1/btrJEKNE7yC/m6gZLX10YmspMzpk7D0SKk/img.png&quot; data-alt=&quot;Runtime Data Area 2&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpZWF1/btrJEKNE7yC/m6gZLX10YmspMzpk7D0SKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpZWF1%2FbtrJEKNE7yC%2Fm6gZLX10YmspMzpk7D0SKk%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;645&quot; height=&quot;545&quot; data-origin-width=&quot;645&quot; data-origin-height=&quot;545&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Runtime Data Area 2&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;622&quot; data-origin-height=&quot;539&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYrZT3/btrJBU3DSs7/pJDYN9fZeYQrYeTKZsO37K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYrZT3/btrJBU3DSs7/pJDYN9fZeYQrYeTKZsO37K/img.png&quot; data-alt=&quot;Runtime Data Area 3&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYrZT3/btrJBU3DSs7/pJDYN9fZeYQrYeTKZsO37K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYrZT3%2FbtrJBU3DSs7%2FpJDYN9fZeYQrYeTKZsO37K%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;622&quot; height=&quot;539&quot; data-origin-width=&quot;622&quot; data-origin-height=&quot;539&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Runtime Data Area 3&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;JVM이라는 프로세스&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;339&quot; data-origin-height=&quot;573&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cQSUvW/btrJGUvvMwC/6MWk9HelOdoX7sJ06yDH61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cQSUvW/btrJGUvvMwC/6MWk9HelOdoX7sJ06yDH61/img.png&quot; data-alt=&quot;Runtime Data Area 4&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cQSUvW/btrJGUvvMwC/6MWk9HelOdoX7sJ06yDH61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcQSUvW%2FbtrJGUvvMwC%2F6MWk9HelOdoX7sJ06yDH61%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;339&quot; height=&quot;573&quot; data-origin-width=&quot;339&quot; data-origin-height=&quot;573&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Runtime Data Area 4&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저, 앞서 JVM이 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;하나의 프로세스&lt;/b&gt;&lt;/span&gt;라고 하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Main Thread&lt;/b&gt;&lt;/span&gt;를 가진 독립된 메모리 공간을 가지며,&amp;nbsp;&lt;span style=&quot;color: #777777;&quot;&gt;Runtime Data Area 3 이미지 처럼 구성된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JVM 내에 쓰레드가 구성될 때는 크게 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Main Thread(비데몬 스레드)와 Main이 아닌 Thread(데몬 쓰레드)로 구분&lt;/b&gt;&lt;/span&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;static void main(String[] args) 가 프로그램 실행의 진입점인 것을 알고 있다. 즉, 이 진입점이 &lt;b&gt;비데몬 쓰레드, Main Thread로 실행되며 Main Thread가 종료되면, 다른 데몬 쓰레드도 모두 종료&lt;/b&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;PC(Program Counter) Register&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OS에서 Context Switching에 대해 학습했다면, PC라는 용어를 알 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행중인 프로세스(쓰레드)에서 다른 프로세스(쓰레드)로 넘어가 실행되기 원할 때, Context Switching이 발생하며, 이때 그 위치에 대한 정보를 포인터하는 역할을 PC가 하게된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;현재 쓰레드의 명령 흐름을 추적하거나, 연산하는 과정에서 필요한 데이터를 저장하는 역할&lt;/b&gt;&lt;/span&gt;을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Native Method Stack&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Java가 아닌 다른 언어를 &lt;span style=&quot;color: #ee2323;&quot;&gt;JNI(Java Native Interface)&lt;/span&gt;를 통해 실행하기 위한 코드 공간&lt;/b&gt;이다. (C, C++)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;JVM Stack&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 흔히 말하는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Stack&lt;/b&gt; &lt;/span&gt;공간이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;지역 변수, 파라미터, 리턴 값, 연산에 사용되는 임시 값&lt;/b&gt;&lt;/span&gt;등이 생성되는 영역으로, 프로그램 실행과정에서 임시로 할당되었다가 메소드를 빠져나가면 바로 소멸되는 특성을 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 이미지에서 보듯, Thread에서도 자신만의 고유 공간이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Method Area&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Method Area&lt;/b&gt;&lt;/span&gt;, 메소드 영역은, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Class Area, Static Area, Code Area&lt;/b&gt;&lt;/span&gt;라고도 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림과 같이, 모든 쓰레드가 공유하는 메모리 영역이기도 하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스 로더의 설명에서도 나왔지만, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;바이너리 코드로 변환된 클래스 파일들을 저장하는 공간&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;클래스 변수(Static 변수), 인터페이스, 필드, 메소드 등 클래스 정보&lt;/b&gt;들이 저장된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Runtime Constant Pool &lt;/b&gt;&lt;/span&gt;이라는 중요한 저장 공간이 내부에 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;이는 상수 자료형을 저장하여 참조하고 중복을 막는 역할을 수행한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;int a = 1;
int b = 1;
if(a == b) {
    System.out.println(&quot;a == b&quot;);
} else {
    System.out.println(&quot;a != b&quot;);
}

// a == b&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단한 소스를 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 a와 b 변수에 할당된 1이라는 값은 Constant pool에 저장된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, 위 두 값은 같다라는 수식에서 같다라는 걸 알 수 있다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;Integer a = new Integer(1);
Integer b = new Integer(1);
if(a == b) {
    System.out.println(&quot;a == b&quot;);
} else {
    System.out.println(&quot;a != b&quot;);
}

// a != b&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;new로 생성한 값은 Constant pool에 저장되지 않아, 같다라는 조건이 성립되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Heap&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #575757;&quot;&gt;힙(heap) 영역은 자바 프로그램에서 사용되는 모든 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;인스턴스 변수가 저장되는 영역&lt;/b&gt;&lt;/span&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #575757;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;new 연산자로 생성되는 객체와 배열을 저장하는 공간으로 보면 되며, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Method Area(Class Area)에 올라온 클래스들만&lt;/b&gt;&lt;/span&gt; 객체로 생성할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #575757;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;Heap은 또 다시 내부 구조를 가진다.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #575757;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;이는 GC와 연결되므로, GC를 따로 공부하면서 정리하도록 하자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #575757;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;Wrap Up&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;span style=&quot;color: #575757;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;위와 같이 JVM의 구조에 대해 알아보았다.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #575757;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;정리하면 다음과 같다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JVM은 Java가 OS에 종속적이지 않도록 만들어 준다.&lt;/li&gt;
&lt;li&gt;Java는 컴파일 언어로, Javac를 통해 .class 파일로 변경된다 (바이트 코드)&lt;/li&gt;
&lt;li&gt;.class 파일은 JVM 내부에서 Interpreter와 JIT Compiler를 통해 바이너리 코드로 변환되어 실행된다.&lt;/li&gt;
&lt;li&gt;JVM 내부에는 크게, 클래스 로더, 실행 엔진, Runtime Data Area(메모리)로 나누어진다.&lt;/li&gt;
&lt;li&gt;클래스 로더는 .class 파일을 로드하고, 메모리(Method Area)에 저장하는 역할을 한다.&lt;/li&gt;
&lt;li&gt;실행 엔진에는 바이너리 코드로 변경하기 위한 Interpreter, JIT Compiler, 그리고 Heap 메모리의 GC 가 포함되어 있다.&lt;/li&gt;
&lt;li&gt;Runtime Data Area에는 JVM Stack, PC Register, Native Method Stack과 Method Area, Heap Area이 존재한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;JVM Stack 은 Thread 고유 저장 영역으로 지역 변수, 파라미터, 리턴 값들이 저장되었다가, 메소드가 끝나면 해소되는 휘발성 영역이다.&lt;/li&gt;
&lt;li&gt;Method Area는 모든 Thread이 공유하는 영역으로, 바이너리 코드로 변환된 .class 내용이 저장된다. 즉, 클래스 변수, 필드, 메서드 등 클래스 정보가 저장되는 공간이다.&lt;/li&gt;
&lt;li&gt;Runtime Constant Pool도 가지고 있어, Primitive Type의 변수들에게 할당되는 값들이 저장되는 공간도 존재한다.&lt;/li&gt;
&lt;li&gt;Heap 영역은 new 로 생성된 인스턴스 변수가 할당된다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;참고자료&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://steady-coding.tistory.com/305&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://steady-coding.tistory.com/305&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1660551867074&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;JVM 메모리 구조란? (JAVA)&quot; data-og-description=&quot;안녕하세요? 코딩 중독입니다. 오늘은 JVM 메모리 구조에 대해 알아보겠습니다. JVM이란? JVM 메모리 구조를 설명하기 전에 JVM이 무엇인지 알아야 합니다. JVM은 Java Virtual Machine의 약자로, 자바 가상&quot; data-og-host=&quot;steady-coding.tistory.com&quot; data-og-source-url=&quot;https://steady-coding.tistory.com/305&quot; data-og-url=&quot;https://steady-coding.tistory.com/305&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/UsB12/hyPsK6uiei/DHdZYGlhJQ8bKsvEhYHke0/img.png?width=549&amp;amp;height=507&amp;amp;face=0_0_549_507,https://scrap.kakaocdn.net/dn/2O545/hyPsUH1VGJ/QvPYOc7tD0OodRnr6nrqWK/img.png?width=549&amp;amp;height=507&amp;amp;face=0_0_549_507,https://scrap.kakaocdn.net/dn/t8XSv/hyPsXdGtq8/zicFyA2dE3ltqq3fdDknk1/img.png?width=820&amp;amp;height=614&amp;amp;face=0_0_820_614&quot;&gt;&lt;a href=&quot;https://steady-coding.tistory.com/305&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://steady-coding.tistory.com/305&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/UsB12/hyPsK6uiei/DHdZYGlhJQ8bKsvEhYHke0/img.png?width=549&amp;amp;height=507&amp;amp;face=0_0_549_507,https://scrap.kakaocdn.net/dn/2O545/hyPsUH1VGJ/QvPYOc7tD0OodRnr6nrqWK/img.png?width=549&amp;amp;height=507&amp;amp;face=0_0_549_507,https://scrap.kakaocdn.net/dn/t8XSv/hyPsXdGtq8/zicFyA2dE3ltqq3fdDknk1/img.png?width=820&amp;amp;height=614&amp;amp;face=0_0_820_614');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;JVM 메모리 구조란? (JAVA)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요? 코딩 중독입니다. 오늘은 JVM 메모리 구조에 대해 알아보겠습니다. JVM이란? JVM 메모리 구조를 설명하기 전에 JVM이 무엇인지 알아야 합니다. JVM은 Java Virtual Machine의 약자로, 자바 가상&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;steady-coding.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://catsbi.oopy.io/df0df290-9188-45c1-b056-b8fe032d88ca&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://catsbi.oopy.io/df0df290-9188-45c1-b056-b8fe032d88ca&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1660551874252&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;[1주차] JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가.&quot; data-og-description=&quot;목표&quot; data-og-host=&quot;catsbi.oopy.io&quot; data-og-source-url=&quot;https://catsbi.oopy.io/df0df290-9188-45c1-b056-b8fe032d88ca&quot; data-og-url=&quot;https://catsbi.oopy.io/df0df290-9188-45c1-b056-b8fe032d88ca&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/uVejJ/hyPq2AT4yB/tYtPwd42cCjkk20iUKY7b0/img.png?width=1464&amp;amp;height=556&amp;amp;face=0_0_1464_556,https://scrap.kakaocdn.net/dn/YITML/hyPq2HGdFx/0YD779pb4sBVOOMaBwoYP0/img.png?width=1464&amp;amp;height=556&amp;amp;face=0_0_1464_556,https://scrap.kakaocdn.net/dn/blsoBN/hyPq4FvywU/kRYtQayKnNsbnH812kAQ4k/img.png?width=1464&amp;amp;height=556&amp;amp;face=0_0_1464_556&quot;&gt;&lt;a href=&quot;https://catsbi.oopy.io/df0df290-9188-45c1-b056-b8fe032d88ca&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://catsbi.oopy.io/df0df290-9188-45c1-b056-b8fe032d88ca&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/uVejJ/hyPq2AT4yB/tYtPwd42cCjkk20iUKY7b0/img.png?width=1464&amp;amp;height=556&amp;amp;face=0_0_1464_556,https://scrap.kakaocdn.net/dn/YITML/hyPq2HGdFx/0YD779pb4sBVOOMaBwoYP0/img.png?width=1464&amp;amp;height=556&amp;amp;face=0_0_1464_556,https://scrap.kakaocdn.net/dn/blsoBN/hyPq4FvywU/kRYtQayKnNsbnH812kAQ4k/img.png?width=1464&amp;amp;height=556&amp;amp;face=0_0_1464_556');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[1주차] JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가.&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;목표&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;catsbi.oopy.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://doozi0316.tistory.com/entry/1%EC%A3%BC%EC%B0%A8-JVM%EC%9D%80-%EB%AC%B4%EC%97%87%EC%9D%B4%EB%A9%B0-%EC%9E%90%EB%B0%94-%EC%BD%94%EB%93%9C%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%8B%A4%ED%96%89%ED%95%98%EB%8A%94-%EA%B2%83%EC%9D%B8%EA%B0%80&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://doozi0316.tistory.com/entry/1%EC%A3%BC%EC%B0%A8-JVM%EC%9D%80-%EB%AC%B4%EC%97%87%EC%9D%B4%EB%A9%B0-%EC%9E%90%EB%B0%94-%EC%BD%94%EB%93%9C%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%8B%A4%ED%96%89%ED%95%98%EB%8A%94-%EA%B2%83%EC%9D%B8%EA%B0%80&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1660551878406&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[JAVA] JVM이란? 개념 및 구조 (JDK, JRE, JIT, 가비지 콜렉터...)&quot; data-og-description=&quot;JVM이란 무엇인가 Java Virtual Machine의 줄임말. 직역하면 '자바를 실행하기 위한 가상 기계(컴퓨터)'라고 할 수 있다. Java 는 OS에 종속적이지 않다는 특징을 가지고 있다. OS에 종속받지 않고 실행되&quot; data-og-host=&quot;doozi0316.tistory.com&quot; data-og-source-url=&quot;https://doozi0316.tistory.com/entry/1%EC%A3%BC%EC%B0%A8-JVM%EC%9D%80-%EB%AC%B4%EC%97%87%EC%9D%B4%EB%A9%B0-%EC%9E%90%EB%B0%94-%EC%BD%94%EB%93%9C%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%8B%A4%ED%96%89%ED%95%98%EB%8A%94-%EA%B2%83%EC%9D%B8%EA%B0%80&quot; data-og-url=&quot;https://doozi0316.tistory.com/entry/1%EC%A3%BC%EC%B0%A8-JVM%EC%9D%80-%EB%AC%B4%EC%97%87%EC%9D%B4%EB%A9%B0-%EC%9E%90%EB%B0%94-%EC%BD%94%EB%93%9C%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%8B%A4%ED%96%89%ED%95%98%EB%8A%94-%EA%B2%83%EC%9D%B8%EA%B0%80&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/CpsTf/hyPqX7s0gN/0fcFudgnZgt6YpyUEP9xe0/img.png?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/ew6YQ/hyPqWOd0aM/8mHzHQB4fnYKJiUKeo0vc0/img.png?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/bg3WKS/hyPqZjTDIP/aVFFwlsOxNWY80oo7wIid1/img.png?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720&quot;&gt;&lt;a href=&quot;https://doozi0316.tistory.com/entry/1%EC%A3%BC%EC%B0%A8-JVM%EC%9D%80-%EB%AC%B4%EC%97%87%EC%9D%B4%EB%A9%B0-%EC%9E%90%EB%B0%94-%EC%BD%94%EB%93%9C%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%8B%A4%ED%96%89%ED%95%98%EB%8A%94-%EA%B2%83%EC%9D%B8%EA%B0%80&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://doozi0316.tistory.com/entry/1%EC%A3%BC%EC%B0%A8-JVM%EC%9D%80-%EB%AC%B4%EC%97%87%EC%9D%B4%EB%A9%B0-%EC%9E%90%EB%B0%94-%EC%BD%94%EB%93%9C%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%8B%A4%ED%96%89%ED%95%98%EB%8A%94-%EA%B2%83%EC%9D%B8%EA%B0%80&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/CpsTf/hyPqX7s0gN/0fcFudgnZgt6YpyUEP9xe0/img.png?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/ew6YQ/hyPqWOd0aM/8mHzHQB4fnYKJiUKeo0vc0/img.png?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/bg3WKS/hyPqZjTDIP/aVFFwlsOxNWY80oo7wIid1/img.png?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[JAVA] JVM이란? 개념 및 구조 (JDK, JRE, JIT, 가비지 콜렉터...)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;JVM이란 무엇인가 Java Virtual Machine의 줄임말. 직역하면 '자바를 실행하기 위한 가상 기계(컴퓨터)'라고 할 수 있다. Java 는 OS에 종속적이지 않다는 특징을 가지고 있다. OS에 종속받지 않고 실행되&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;doozi0316.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/Java</category>
      <category>Java</category>
      <category>jvm</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/76</guid>
      <comments>https://koocci-dev.tistory.com/76#entry76comment</comments>
      <pubDate>Mon, 15 Aug 2022 21:42:25 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] Bean의 주입은 어떻게 하는게 좋을까?</title>
      <link>https://koocci-dev.tistory.com/74</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : Spring Bean 생성자 주입이 많은 이유를 설명할 수 있다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://koocci-dev.tistory.com/60&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이전 포스팅&lt;/a&gt;으로 Bean 주입에 대해 설명한 적이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잠깐 다시 정리해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Bean의 주입 방법&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Bean의 주입 방법은 크게 3가지가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;생성자 주입&lt;/b&gt;&lt;/span&gt;, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Setter를 통한 주입&lt;/b&gt;&lt;/span&gt;은 앞선 포스팅으로 보았고,&amp;nbsp; &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;필드를 통한 주입&lt;/b&gt;&lt;/span&gt;까지 3가지가 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Setter를 통한 주입&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;package com.example.demo.di;

import lombok.Data;

@Data
public class MyBean {
    private int msg;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;package com.example.demo.di;

import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;

@Data
public class AnotherBean {
    private MyBean myBean;

    public void setMyBean(MyBean myBean) {
        this.myBean = myBean;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;package com.example.demo.di;

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

@Configuration
public class AppConfig {

    @Bean
    public MyBean myBean() {
        return new MyBean();
    }

    @Bean
    public AnotherBean anotherBean() {
        return new AnotherBean();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;package com.example.demo.di;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        AnotherBean aBean = context.getBean(AnotherBean.class);
        MyBean myBean = context.getBean(MyBean.class);
        myBean.setMsg(123);
        aBean.setMyBean(myBean);

        System.out.println(aBean.getMyBean().getMsg());
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Setter를 통한 주입은 잘 사용하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 이유는 Setter 자체에 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Setter를 사용하는 것이 자유롭다보니, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;나중에 누군가에 의해 변경이 일어날 수 있다는 것&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;객체의 불변성&lt;/b&gt;&lt;/span&gt;을 보장하지 못한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;순환 참조&lt;/b&gt;&lt;/span&gt;에 대한 문제도 가지고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A도 B를 가지고 있고, B도 A를 가지고 있으면 순환 참조로 인해 에러가 날 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Setter 로 인해, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Bean을 생성한 후에 주입하기 때문&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;필드를 통한 주입&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예시에서 AnotherBean만 바꾸어 주자.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Data
public class AnotherBean {
    @Autowired
    private MyBean myBean;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단히, @Autowired를 통해 주입해줄 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 프로젝트가 아니라면, 이런 방식이 정말 많이 쓰였고, 또 자주 보일 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용하기 편리하지만 이 역시 Setter와 동일하게 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;순환참조&lt;/b&gt;&lt;/span&gt;와 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;객체의&lt;/b&gt; &lt;b&gt;불변성&lt;/b&gt;&lt;/span&gt;에 대한 보장이 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;생성자를 통한 주입&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글의 목적이기도 하다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;package com.example.demo.di;

import lombok.Data;
import lombok.RequiredArgsConstructor;

@Data
@RequiredArgsConstructor
public class AnotherBean {
    final private MyBean myBean;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;package com.example.demo.di;

import lombok.Data;

@Data
public class MyBean {
    private int msg;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;package com.example.demo.di;

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

@Configuration
public class AppConfig {

    @Bean
    public MyBean myBean() {
        return new MyBean();
    }

    @Bean
    public AnotherBean anotherBean() {
        return new AnotherBean(this.myBean());
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;package com.example.demo.di;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        AnotherBean aBean = context.getBean(AnotherBean.class);
        aBean.getMyBean().setMsg(123);

        System.out.println(aBean.getMyBean().getMsg());
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;달라진 점은 크게 2가지다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;@RequiredArgsConstructor&lt;/b&gt; &lt;/span&gt;를 통해, 생성자를 만들어준 점, 그리고, 필드에&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt; final&lt;/b&gt;&lt;/span&gt;을 설정한 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성자를 통한 주입을 Spring에서도 추천하는 이유는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;순환참조 방지&lt;/b&gt;&lt;/span&gt;와 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;객체의 불변성&lt;/b&gt;&lt;/span&gt;을 보장해주기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서, 필드나 Setter를 통한 주입과 달리, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;주입하고자 하는 Bean이 있는지 확인하면서 주입이 되므로&lt;/b&gt;&lt;/span&gt; 순환참조가 생길 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;final 키워드&lt;/b&gt;&lt;/span&gt;를 유일하게 쓸 수 있기 때문에, &lt;b&gt;런타임에 객체가 변환되는 것에 대한 걱정을 없앨 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Wrap Up&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Bean의 주입 시, 생성자를 많이 사용하는 이유에 대해 알아보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성자 주입의 장점인 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;순환참조 방지&lt;/b&gt;&lt;/span&gt;, 그리고 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;객체의 불변성을 보장&lt;/b&gt;&lt;/span&gt;한다는 것으로 마무리하자.&lt;/p&gt;</description>
      <category>Framework/Spring</category>
      <category>Bean</category>
      <category>spring</category>
      <category>생성자</category>
      <category>스프링</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/74</guid>
      <comments>https://koocci-dev.tistory.com/74#entry74comment</comments>
      <pubDate>Sun, 14 Aug 2022 02:53:26 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] Spring에서 AOP는 어떻게 사용할까?</title>
      <link>https://koocci-dev.tistory.com/72</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : Spring에서 AOP를 사용할 수 있다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서, &lt;a href=&quot;https://koocci-dev.tistory.com/71?category=1012333&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AOP가 무엇인지&lt;/a&gt;에 대해 알아보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 Spring에서 AOP를 어떻게 쓸 수 있을지 알아보자.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Aspect Oriented Programming with Spring&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop&quot;&gt;다음 링크&lt;/a&gt;에서 Spring에서 AOP에 대한 적용은 다음과 같이 할 수 있다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #ebf2f2; color: #000000;&quot;&gt;Spring provides simple and powerful ways of writing custom aspects by using either a&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop-schema&quot;&gt;schema-based approach&lt;/a&gt;&lt;span style=&quot;background-color: #ebf2f2; color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;or the&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop-ataspectj&quot;&gt;@AspectJ annotation style&lt;/a&gt;&lt;span style=&quot;background-color: #ebf2f2; color: #000000;&quot;&gt;. Both of these styles offer fully typed advice and use of the AspectJ pointcut language while still using Spring AOP for weaving.&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;schema-based approach&lt;/b&gt;&lt;/span&gt;를 사용할 수도 있고,&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;@AspectJ라는 Annotation&lt;/b&gt;&lt;/span&gt;을 사용할수도 있다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;aop-schema&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Schema-based AOP Support&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Annotation은 소스가 분산되어, 이해를 돕기위해 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Schema-based&lt;/b&gt;&lt;/span&gt; 방식을 먼저 보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저, XML로 AOP를 설정하려면 &lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#xsd-schemas-aop&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;aop Schema&lt;/a&gt;를 설정해주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Declaring an Aspect&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Aspect&lt;/b&gt;&lt;/span&gt;부터 설정해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
       xmlns:aop=&quot;http://www.springframework.org/schema/aop&quot;
       xmlns:context=&quot;http://www.springframework.org/schema/context&quot;
       xsi:schemaLocation=&quot;
        http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd&quot;&amp;gt;

    &amp;lt;!-- bean definitions here --&amp;gt;
    &amp;lt;aop:config&amp;gt;
        &amp;lt;aop:aspect id=&quot;myAspect&quot; ref=&quot;aBean&quot;&amp;gt;
        &amp;lt;/aop:aspect&amp;gt;
    &amp;lt;/aop:config&amp;gt;

    &amp;lt;bean id=&quot;aBean&quot; class=&quot;com.example.demo.aop.AopBean&quot;&amp;gt;
    &amp;lt;/bean&amp;gt;

&amp;lt;/beans&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시에 따라 구성하였고, AopBean 클래스를 만들어, Bean 설정에 추가해주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;aop-schema-pointcuts&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Declaring a Pointcut&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pointcut도 마찬가지로 설정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pointcut은 aspect 안에 존재한다.&lt;/p&gt;
&lt;pre id=&quot;code_1660330832275&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;aop:config&amp;gt;

    &amp;lt;aop:pointcut id=&quot;businessService&quot;
        expression=&quot;execution(* com.xyz.myapp.service.*.*(..))&quot;/&amp;gt;

&amp;lt;/aop:config&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 작성하기 전에, 위 예시를 보면, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;expression&lt;/b&gt;&lt;/span&gt;이 존재한다.&lt;/p&gt;
&lt;pre id=&quot;code_1660331336350&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;execution(* com.xyz.myapp.service.*.*(..))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;excution 할 때 (Runtime 때) 특정 패키지(com.xyz...service)의 모든 클래스(service.*), 모든 메서드(service.*.*), 그리고 모든 Argument(*.*.(..))에 해당한다는 표현식&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 실제로 적용해보자.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;package com.example.demo.aop;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class AopBean {
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
       xmlns:aop=&quot;http://www.springframework.org/schema/aop&quot;
       xmlns:context=&quot;http://www.springframework.org/schema/context&quot;
       xsi:schemaLocation=&quot;
        http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd&quot;&amp;gt;

    &amp;lt;!-- bean definitions here --&amp;gt;
    &amp;lt;aop:config&amp;gt;
        &amp;lt;aop:aspect id=&quot;myAspect&quot; ref=&quot;aBean&quot;&amp;gt;
                &amp;lt;aop:pointcut id=&quot;businessService&quot; expression=&quot;execution(* com.example.demo.aop.AopBean.*.*(..))&quot;/&amp;gt;
        &amp;lt;/aop:aspect&amp;gt;
    &amp;lt;/aop:config&amp;gt;

    &amp;lt;bean id=&quot;aBean&quot; class=&quot;com.example.demo.aop.AopBean&quot;&amp;gt;
    &amp;lt;/bean&amp;gt;

&amp;lt;/beans&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 id=&quot;aop-schema-advice&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Declaring Advice&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 Advice를 적용해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;package com.example.demo.aop;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class AopBean {
    public void beforeLog() {
        log.error(&quot;&amp;gt;&amp;gt;&amp;gt; before aop log&quot;);
    }

    public void afterLog() {
        log.error(&quot;&amp;gt;&amp;gt;&amp;gt; after aop log&quot;);
    }

    public void afterReturningLog() {
        log.error(&quot;&amp;gt;&amp;gt;&amp;gt; afterReturningLog aop log&quot;);
    }

    public void afterThrowingLog() {
        log.error(&quot;&amp;gt;&amp;gt;&amp;gt; afterThrowingLog aop log&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;cpp&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;package com.example.demo.aop;

import lombok.extern.slf4j.Slf4j;


@Slf4j
public class Service {
    public void log() {
        log.error(&quot;&amp;gt;&amp;gt;&amp;gt; aop log&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
       xmlns:aop=&quot;http://www.springframework.org/schema/aop&quot;
       xmlns:context=&quot;http://www.springframework.org/schema/context&quot;
       xsi:schemaLocation=&quot;
        http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd&quot;&amp;gt;

    &amp;lt;!-- bean definitions here --&amp;gt;
    &amp;lt;aop:config&amp;gt;
        &amp;lt;aop:aspect id=&quot;myAspect&quot; ref=&quot;aBean&quot;&amp;gt;
            &amp;lt;aop:pointcut id=&quot;businessService&quot; expression=&quot;execution(* com.example.demo.aop.Service.*(..))&quot;/&amp;gt;
            &amp;lt;aop:before pointcut-ref=&quot;businessService&quot; method=&quot;beforeLog&quot;/&amp;gt;
            &amp;lt;aop:after pointcut-ref=&quot;businessService&quot; method=&quot;afterLog&quot;/&amp;gt;
            &amp;lt;aop:after-returning pointcut-ref=&quot;businessService&quot; method=&quot;afterReturningLog&quot;/&amp;gt;
            &amp;lt;aop:after-throwing pointcut-ref=&quot;businessService&quot; method=&quot;afterThrowingLog&quot;/&amp;gt;
        &amp;lt;/aop:aspect&amp;gt;
    &amp;lt;/aop:config&amp;gt;

    &amp;lt;bean id=&quot;aBean&quot; class=&quot;com.example.demo.aop.AopBean&quot;&amp;gt;
    &amp;lt;/bean&amp;gt;

    &amp;lt;bean id=&quot;service&quot; class=&quot;com.example.demo.aop.Service&quot;&amp;gt;
    &amp;lt;/bean&amp;gt;

&amp;lt;/beans&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;package com.example.demo.aop;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(&quot;application.xml&quot;);
        Service service = context.getBean(Service.class);
        service.log();
        context.close();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹시, Class Not Found 에러가 난다면, 아래 2개 Dependency를 추가해주자. (Springboot는 starter-aop 가 따로 있다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://mvnrepository.com/artifact/org.aspectj/aspectjrt/1.9.9.1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Aspectj Runtime&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://mvnrepository.com/artifact/org.aspectj/aspectjweaver/1.9.9.1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;aspectJ Weaver&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;04:39:29.454&amp;nbsp;[main]&amp;nbsp;ERROR&amp;nbsp;co&lt;a href=&quot;http://m.example.demo.aop.AopBean&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;m.example.demo.aop.AopBean&lt;/a&gt;&amp;nbsp;-&amp;nbsp;&amp;gt;&amp;gt;&amp;gt;&amp;nbsp;before&amp;nbsp;aop&amp;nbsp;log &lt;br /&gt;04:39:29.466&amp;nbsp;[main]&amp;nbsp;ERROR&amp;nbsp;co&lt;a href=&quot;http://m.example.demo.aop.Service&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;m.example.demo.aop.Service&lt;/a&gt;&amp;nbsp;-&amp;nbsp;&amp;gt;&amp;gt;&amp;gt;&amp;nbsp;aop&amp;nbsp;log &lt;br /&gt;04:39:29.466&amp;nbsp;[main]&amp;nbsp;ERROR&amp;nbsp;co&lt;a href=&quot;http://m.example.demo.aop.AopBean&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;m.example.demo.aop.AopBean&lt;/a&gt;&amp;nbsp;-&amp;nbsp;&amp;gt;&amp;gt;&amp;gt;&amp;nbsp;after&amp;nbsp;aop&amp;nbsp;log &lt;br /&gt;04:39:29.466&amp;nbsp;[main]&amp;nbsp;ERROR&amp;nbsp;co&lt;a href=&quot;http://m.example.demo.aop.AopBean&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;m.example.demo.aop.AopBean&lt;/a&gt;&amp;nbsp;-&amp;nbsp;&amp;gt;&amp;gt;&amp;gt;&amp;nbsp;afterReturningLog&amp;nbsp;aop&amp;nbsp;log&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 결과를 위와 같이 확인해 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Around Advice&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼, 위에서 했던 것들을 한번에 해주는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Around Advice&lt;/b&gt;&lt;/span&gt;를 보자.&lt;/p&gt;
&lt;pre id=&quot;code_1660333433982&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;aop:aspect id=&quot;aroundExample&quot; ref=&quot;aBean&quot;&amp;gt;

    &amp;lt;aop:around
        pointcut-ref=&quot;businessService&quot;
        method=&quot;doBasicProfiling&quot;/&amp;gt;

    ...
&amp;lt;/aop:aspect&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1660333475868&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
    // start stopwatch
    Object retVal = pjp.proceed();
    // stop stopwatch
    return retVal;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Around에서는&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt; method에서&lt;span style=&quot;color: #ee2323;&quot;&gt; Argument&lt;/span&gt;를 받는다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://koocci-dev.tistory.com/71?category=1012333&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;앞선 포스팅&lt;/a&gt;에서 확인해 보았듯이, Proxy로 Sample 예제를 보았을 때와 동일하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;package com.example.demo.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;

@Slf4j
public class AopBean {
    public void aroundLog(ProceedingJoinPoint pjp) {
        log.error(&quot;&amp;gt;&amp;gt;&amp;gt; before aop log&quot;);
        try {
            Object proceed = pjp.proceed();
            log.error(&quot;&amp;gt;&amp;gt;&amp;gt; returning aop log&quot;);
        } catch (Throwable throwable) {
            log.error(&quot;&amp;gt;&amp;gt;&amp;gt; throwing aop log&quot;);
        }
        log.error(&quot;&amp;gt;&amp;gt;&amp;gt; after aop log&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
       xmlns:aop=&quot;http://www.springframework.org/schema/aop&quot;
       xmlns:context=&quot;http://www.springframework.org/schema/context&quot;
       xsi:schemaLocation=&quot;
        http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd&quot;&amp;gt;

    &amp;lt;!-- bean definitions here --&amp;gt;
    &amp;lt;aop:config&amp;gt;
        &amp;lt;aop:aspect id=&quot;myAspect&quot; ref=&quot;aBean&quot;&amp;gt;
            &amp;lt;aop:pointcut id=&quot;businessService&quot; expression=&quot;execution(* com.example.demo.aop.Service.*(..))&quot;/&amp;gt;
            &amp;lt;aop:around pointcut-ref=&quot;businessService&quot; method=&quot;aroundLog&quot;/&amp;gt;
        &amp;lt;/aop:aspect&amp;gt;
    &amp;lt;/aop:config&amp;gt;

    &amp;lt;bean id=&quot;aBean&quot; class=&quot;com.example.demo.aop.AopBean&quot;&amp;gt;
    &amp;lt;/bean&amp;gt;

    &amp;lt;bean id=&quot;service&quot; class=&quot;com.example.demo.aop.Service&quot;&amp;gt;
    &amp;lt;/bean&amp;gt;

&amp;lt;/beans&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;@AspectJ&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이제, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Annotation&lt;/b&gt;&lt;/span&gt;을 통해, 처리하는 것으로 변경해보도록 하자.&lt;/p&gt;
&lt;pre id=&quot;code_1660341300372&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class AppConfig {
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저, AspectJ는 외부 라이브러리이므로, Configuration에 위와 같이 넣어줄 필요가 있다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Slf4j
@Component
public class Service {
    public void log() {
        log.error(&quot;&amp;gt;&amp;gt;&amp;gt; aop log&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;
@Slf4j
@Aspect
@Component
public class AopBean {

    @Pointcut(&quot;execution(* com.example.demo.aop.Service.*(..))&quot;)
    public void aopPointcut(){}

    @Around(&quot;aopPointcut()&quot;)
    public Object aroundLog(ProceedingJoinPoint pjp) {
        log.error(&quot;&amp;gt;&amp;gt;&amp;gt; before aop log&quot;);
        try {
            Object proceed = pjp.proceed();
            log.error(&quot;&amp;gt;&amp;gt;&amp;gt; returning aop log&quot;);
            return proceed;
        } catch (Throwable throwable) {
            log.error(&quot;&amp;gt;&amp;gt;&amp;gt; throwing aop log&quot;);
        }
        log.error(&quot;&amp;gt;&amp;gt;&amp;gt; after aop log&quot;);
        return null;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;package com.example.demo.aop;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(AppConfig.class);
        context.refresh();

        Service service = context.getBean(Service.class);
        service.log();
        context.close();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;XML 파일을 없애더라도, 정상 동작하는 것을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@Aspect 안에, Pointcut을 설정하였고, @Around로 Advice도 적용되었다는 것을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상황에 따라, Pointcut을 별도로 정리하고, Advice에는 여러 Pointcut을 적용하는 등의 동작도 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Wrap Up&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 배운 지식과 합쳐서, AOP를 Spring에서 어떻게 사용하는지에 대해 알아볼 수 있었다.&lt;/p&gt;</description>
      <category>Framework/Spring</category>
      <category>AOP</category>
      <category>spring</category>
      <category>스프링</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/72</guid>
      <comments>https://koocci-dev.tistory.com/72#entry72comment</comments>
      <pubDate>Sat, 13 Aug 2022 07:51:36 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] AOP는 뭘까?</title>
      <link>https://koocci-dev.tistory.com/71</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : AOP에 대해 설명 할 수 있다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring에서는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;IoC Container&lt;/b&gt;&lt;/span&gt; 기능과 더불어, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;AOP&lt;/b&gt;&lt;/span&gt;를 아주 중요하게 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼, AOP가 무엇인지부터 알아가보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Aspect Oriented Programming (AOP)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EA%B4%80%EC%A0%90_%EC%A7%80%ED%96%A5_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;다음 링크&lt;/a&gt;를 보면, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;AOP&lt;/b&gt;&lt;/span&gt;에 대해 다음과 같이 설명하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%BB%B4%ED%93%A8%ED%8C%85&quot;&gt;컴퓨팅&lt;/a&gt;&lt;span style=&quot;background-color: #ffffff; color: #202122;&quot;&gt;에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;관점 지향 프로그래밍&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #202122;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #202122;&quot;&gt;aspect-oriented programming&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #202122;&quot;&gt;, AOP)은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%ED%9A%A1%EB%8B%A8_%EA%B4%80%EC%8B%AC%EC%82%AC&quot;&gt;횡단 관심사&lt;/a&gt;&lt;span style=&quot;background-color: #ffffff; color: #202122;&quot;&gt;(cross-cutting concern)의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EA%B4%80%EC%8B%AC%EC%82%AC%EC%9D%98_%EB%B6%84%EB%A6%AC&quot;&gt;분리&lt;/a&gt;&lt;span style=&quot;background-color: #ffffff; color: #202122;&quot;&gt;를 허용함으로써&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EB%AA%A8%EB%93%88%EC%84%B1&quot;&gt;모듈성&lt;/a&gt;&lt;span style=&quot;background-color: #ffffff; color: #202122;&quot;&gt;을 증가시키는 것이 목적인&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D_%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84&quot;&gt;프로그래밍 패러다임&lt;/a&gt;&lt;span style=&quot;background-color: #ffffff; color: #202122;&quot;&gt;이다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떠한 language가 만들어 지기 전에, OOP, Functional Programming 같은 패러다임이 먼저 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 패러다임을 기반으로 특정 Language가 만들어진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Java&lt;/b&gt;&lt;/span&gt;는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;OOP 패러다임&lt;/b&gt;&lt;/span&gt;으로 만들어졌고, 이후에 AOP의 요구사항에 의해 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;AOP 패러다임도 수용&lt;/b&gt;&lt;/span&gt;한 언어다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 위 설명의 용어를 알아보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;횡단 관심사(Cross-cutting concern)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그램을 개발하다보면, 공통 기능이 생기기 마련이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 Controller 혹은 특정 목적에 따라 만들어진 Service 들 등, Log와 같이 목적에 따라, 공통적으로 적용되어야 할 소스들이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 예시 이미지를 보도록 하자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1672&quot; data-origin-height=&quot;775&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bO8akp/btrJABi8Zcz/89iBDT7G4qa3ApC9ubfHsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bO8akp/btrJABi8Zcz/89iBDT7G4qa3ApC9ubfHsK/img.png&quot; data-alt=&quot;AOP 설명1&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bO8akp/btrJABi8Zcz/89iBDT7G4qa3ApC9ubfHsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbO8akp%2FbtrJABi8Zcz%2F89iBDT7G4qa3ApC9ubfHsK%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1672&quot; height=&quot;775&quot; data-origin-width=&quot;1672&quot; data-origin-height=&quot;775&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;AOP 설명1&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1660319917429&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Slf4j
public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(AppConfig.class);
        context.refresh();
        MyService service = context.getBean(MyService.class);
        service.check();
        context.close();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java에 Main 메서드가 있을 것이고, Spring boot를 만들어도 Main 메서드가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드에서는 context, service같은 객체들을 선언/할당하고, 메서드들을 실행하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 위 이미지에서 A~D Class Method가 이에 해당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;공통 기능&lt;/b&gt;&lt;/span&gt;을 넣어주려고 한다고 해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 트랜젝션 기능을 넣어주려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 우리는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;각 Class마다,&lt;/b&gt;&lt;/span&gt; Transaction Start와 Auto Commit = false를 상위에 넣어주고, Try Catch 문으로 감싸준 다음에, Rollback 혹은 Commit 처리를 마지막에 해야할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 다음 이미지 같이 될 것이다. (보기 좋게 만들다보니, Commit/Rollback 실행 위치는 모순이 있을 수 있다. 이후에 예시로 정확히 알아보자.)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1672&quot; data-origin-height=&quot;775&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxu51N/btrJAIoDR99/HKFSq37U5vlVyP0dFChQPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxu51N/btrJAIoDR99/HKFSq37U5vlVyP0dFChQPK/img.png&quot; data-alt=&quot;AOP 설명 2&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxu51N/btrJAIoDR99/HKFSq37U5vlVyP0dFChQPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbxu51N%2FbtrJAIoDR99%2FHKFSq37U5vlVyP0dFChQPK%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1672&quot; height=&quot;775&quot; data-origin-width=&quot;1672&quot; data-origin-height=&quot;775&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;AOP 설명 2&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 바로 발견되는 문제점이 있을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;동일한 작업의 반복&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 함수를 사용하는 이유 중 하나는 반복을 최소화 하기 위함이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 위 상황에서, 각 박스들을 함수로 만든다고 하더라도, 각 클래스에서 호출해서 써야 하다보니, 그 함수 실행 자체가 반복된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;관점&lt;/b&gt;&lt;/span&gt;을 바꾸어서 바라보도록 노력 해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;위 박스들을 각 Class에서 실행하지 않으면 된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;공통된 부분이 실행되는 함수에 각 클래스에서 독립적으로 실행시키고 싶은 부분을 Argment로 넘겨주어, 실행하도록 만들면 된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 여기서 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;공통된 부분&lt;/b&gt;&lt;/span&gt;들과 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;독립적&lt;/b&gt;&lt;/span&gt;으로 실행되어야 할 부분을 나누어 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1672&quot; data-origin-height=&quot;790&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kSq5C/btrJAoj7xdT/Pr5rwfFDIhnyZoZ7S6k4CK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kSq5C/btrJAoj7xdT/Pr5rwfFDIhnyZoZ7S6k4CK/img.png&quot; data-alt=&quot;AOP 설명 3&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kSq5C/btrJAoj7xdT/Pr5rwfFDIhnyZoZ7S6k4CK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkSq5C%2FbtrJAoj7xdT%2FPr5rwfFDIhnyZoZ7S6k4CK%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1672&quot; height=&quot;790&quot; data-origin-width=&quot;1672&quot; data-origin-height=&quot;790&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;AOP 설명 3&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 원하는 건, 각 클래스의 성격에 따라, 독립적으로 실행될 것은 실행되고, 공통된 부분은 따로 관리되어, 실행되는 것을 원한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;즉, &lt;span&gt;공통된 부분에 해당하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;횡단 관심사(Cross Cutting)&lt;/b&gt;&lt;/span&gt;를 찾아내어 따로 관리되었으면 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1672&quot; data-origin-height=&quot;848&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lt921/btrJC4cON3f/XhGnmFtgmS27Vpw3ScHXI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lt921/btrJC4cON3f/XhGnmFtgmS27Vpw3ScHXI1/img.png&quot; data-alt=&quot;AOP 설명 4&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lt921/btrJC4cON3f/XhGnmFtgmS27Vpw3ScHXI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flt921%2FbtrJC4cON3f%2FXhGnmFtgmS27Vpw3ScHXI1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1672&quot; height=&quot;848&quot; data-origin-width=&quot;1672&quot; data-origin-height=&quot;848&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;AOP 설명 4&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 최종적으로, 위 그림처럼 &lt;b&gt;횡단 관심사를 분리해내어 관리하고, 각 클래스에서 독립적으로 실행된 로직을 따로 관리하는 걸 원한다. 다시 말하면,&lt;span style=&quot;color: #006dd7;&quot;&gt; 횡단 관심사를 비즈니스 로직에서 감추는 것을 원한다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이에 대한 해결책이 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;AOP, 관점 지향 프로그래밍&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;AOP Concepts&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 &lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop-introduction-defn&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AOP Concepts&lt;/a&gt;를 보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 Spring에서만 사용하는 용어는 아니고, 직관적이진 않기 때문에 개념과 용어의 정의가 먼저 선행될 필요가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Join point&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;A point during the execution of a program, such as the execution of a method or the handling of an exception. In Spring AOP, a join point always represents a method execution.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;메서드 실행 또는 예외 처리와 같은 프로그램 실행 중 한 지점&lt;/b&gt;&lt;/span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Spring에서는 항상 메서드 실행을 말한다. (AOP라는 것에 초점을 맞추면, 메서드가 아니라 클래스나 여러 방면에서 활용될 수 있지만, Spring에서는 메서드만 가능하다)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;즉, 앞서 보았던 이미지에서 각 클래스의&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;&amp;nbsp;독립&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span&gt;부분에 대한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;후보지&lt;/b&gt;&lt;/span&gt;로 볼 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그램이 실행되면, 여러 join point가 있을 수 있고, 어떤 클래스에서는 위 횡단 관심사가 필요없어, Join point가 없을 수 있다.&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Pointcut&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;A predicate that matches join points. Advice is associated with a pointcut expression and runs at any join point matched by the pointcut (for example, the execution of a method with a certain name). The concept of join points as matched by pointcut expressions is central to AOP, and Spring uses the AspectJ pointcut expression language by default.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Join point에 대해서 판단할 수 있는 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 Join point에 대해서, 모든 클래스들 중에 AOP를 적용해야 할 부분에 대해서 정의한다.&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1개 이상 Joint point를 묶어서 Pointcut이 될 수 있고,&amp;nbsp; 1개 이상의 횡단 관심사가 실행될 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Join point (독립 부분의 후보지) 중에서 실제로 횡단 관심사(Advice)가 적용되는 독립 부분&lt;/b&gt;&lt;/span&gt;을 나타낸다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Advice&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Action taken by an aspect at a particular join point. Different types of advice include &amp;ldquo;around&amp;rdquo;, &amp;ldquo;before&amp;rdquo; and &amp;ldquo;after&amp;rdquo; advice. (Advice types are discussed later.) Many AOP frameworks, including Spring, model an advice as an interceptor and maintain a chain of interceptors around the join point.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;특정 Join point에서 aspect에 의해 취해진 행위.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 말해, Join point가 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;언제 동작할지에 대해 설정&lt;/b&gt;&lt;/span&gt;하며,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;JoinPoint에서 실행되어야 하는 코드&lt;/b&gt;&lt;/span&gt;를 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 이미지의 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;횡단 관심사&lt;/b&gt;&lt;/span&gt; 부분에 실제적으로 적용되는 코드다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 독립 부분의 앞, 뒤 등 언제 적용될 지를 설정하고, 어떤 코드가 실행될지에 대해 정의한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;advice의 타입은 아래를 참고하자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Before advice: Advice that runs before a join point but that does not have the ability to prevent execution flow proceeding to the join point (unless it throws an exception).&lt;/li&gt;
&lt;li&gt;After returning advice: Advice to be run after a join point completes normally (for example, if a method returns without throwing an exception).&lt;/li&gt;
&lt;li&gt;After throwing advice: Advice to be run if a method exits by throwing an exception.&lt;/li&gt;
&lt;li&gt;After (finally) advice: Advice to be run regardless of the means by which a join point exits (normal or exceptional return).&lt;/li&gt;
&lt;li&gt;Around advice: Advice that surrounds a join point such as a method invocation. This is the most powerful kind of advice. Around advice can perform custom behavior before and after the method invocation. It is also responsible for choosing whether to proceed to the join point or to shortcut the advised method execution by returning its own return value or throwing an exception.&lt;/li&gt;
&lt;li&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Aspect&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;A modularization of a concern that cuts across multiple classes. Transaction management is a good example of a crosscutting concern in enterprise Java applications. In Spring AOP, aspects are implemented by using regular classes (the schema-based approach) or regular classes annotated with the @Aspect annotation (the @AspectJ style).&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;여러 클래스를 가로지르는 관심사의 모듈화&lt;/b&gt;&lt;/span&gt;라고 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 앞서 보았던 이미지의 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;횡단 관심사&lt;/b&gt;&lt;/span&gt; 부분이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좀 더 거시적인 관점의 용어라고 할 수 있다. Advice와 Pointcut을 합친 것.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;Target object&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;An object being advised by one or more aspects. Also referred to as the &amp;ldquo;advised object&amp;rdquo;. Since Spring AOP is implemented by using runtime proxies, this object is always a proxied object.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나 이상의 aspect에 의해 동작하게될 객체.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 이미지의 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;독립&lt;/b&gt;&lt;/span&gt; 부분이 구현되는 객체다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;AOP Proxy&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;An object created by the AOP framework in order to implement the aspect contracts (advise method executions and so on). In the Spring Framework, an AOP proxy is a JDK dynamic proxy or a CGLIB proxy.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AOP는 Proxy 방식으로 동작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래에 별도로 설명을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Weaving&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;linking aspects with other application types or objects to create an advised object. This can be done at compile time (using the AspectJ compiler, for example), load time, or at runtime. Spring AOP, like other pure Java AOP frameworks, performs weaving at runtime.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Aspect들과 advise가 적용된 객체 사이의 연결이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 말해, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;포인트컷으로 지정한 메소드가 호출될 때, Advice에 해당하는 메소드가 삽입되는 과정&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;weaving은 Runtime에 진행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;AOP Proxy&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Proxy&lt;/b&gt;&lt;/span&gt;라는 것은 A라는 Class가 있을 떄, 이 Class를 감싸는 A Proxy Class가 있고, 외부에서는 A Proxy Class를 실행시키며, A Proxy Class의 특정 동작을 한 후, A Class를 동작시키며, A Proxy&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Class&lt;/span&gt;가 원하는 대로 호출하여 동작시키는 과정이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;AOP Proxy에 대해 &lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop-understanding-aop-proxies&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;다음 링크&lt;/a&gt;의 예시를 참고해 한번 보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public interface Pojo {
    void foo();
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class SimplePojo implements Pojo {

    public void foo() {
        System.out.println(&quot;run foo&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class Main {
    public static void main(String[] args) {
        Pojo pojo = new SimplePojo();
        pojo.foo();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;패키지를 만들어, 위와 같이 구성하였다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;508&quot; data-origin-height=&quot;192&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9yiY7/btrJB3lfuJT/6kiwaAAWtcXRKfuB1ZPCpK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9yiY7/btrJB3lfuJT/6kiwaAAWtcXRKfuB1ZPCpK/img.png&quot; data-alt=&quot;Proxy&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9yiY7/btrJB3lfuJT/6kiwaAAWtcXRKfuB1ZPCpK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9yiY7%2FbtrJB3lfuJT%2F6kiwaAAWtcXRKfuB1ZPCpK%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;508&quot; height=&quot;192&quot; data-origin-width=&quot;508&quot; data-origin-height=&quot;192&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Proxy&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서, Proxy에 대한 설명 했듯이, Proxy는 Plain Object (SimplePojo)를 부르기 전에, Proxy로 감싼다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, 코드를 호출할 때, Proxy를 통해 Plain Object를 호출하고, Proxy를 통해, 코드가 동작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class Main {
    public static void main(String[] args) {
        ProxyFactory factory = new ProxyFactory(new SimplePojo());
        factory.addInterface(Pojo.class);
        factory.addAdvice(new RetryAdvice());

        Pojo pojo = (Pojo) factory.getProxy();
        // this is a method call on the proxy!
        pojo.foo();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Proxy를 만들 때는 Java SDK에서는 Dynamic Proxy 기능을 사용하고, ProxyFactory를 만들고, 특정 Advice를 넣는 형태가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RetryAdvice가 없기 때문에, 해당 클래스도 만들어준다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class RetryAdvice implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        return null;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;invoke 메서드에 null을 리턴하다보니, pojo.foo()를 호출해도 동작하지 않는다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class RetryAdvice implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println(&quot;Before&quot;);
        Object proceed = invocation.proceed();
        System.out.println(&quot;After&quot;);
        return proceed; 
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이, Proxy를 통해 proceed를 리턴하여, pojo.foo()가 동작하게끔 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 방식도 Spring에서 제공하는 일종의 AOP이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Wrap up&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AOP는 개념부터 잡아야 하다보니, 블로깅을 나누어서 할 예정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 AOP의 개념을 알아보았고, 이후에 AOP를 어떻게 Spring에서 사용하는지 알아보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Framework/Spring</category>
      <category>AOP</category>
      <category>spring</category>
      <category>스프링</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/71</guid>
      <comments>https://koocci-dev.tistory.com/71#entry71comment</comments>
      <pubDate>Sat, 13 Aug 2022 03:40:51 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] Validation은 어떻게 확인할까?</title>
      <link>https://koocci-dev.tistory.com/70</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : 스프링에서 Validation을 확인할 수 있다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Validator&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring은 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Validator&lt;/b&gt;&lt;/span&gt;라는 Interface를 통해, Validation을 제공하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660223920646&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Person {

    private String name;
    private int age;

    // the usual getters and setters...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 클래스가 존재한다고 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, 위 Person 클래스의 필드에 대해, validation을 제공하는 클래스를 만들어볼 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1660223969765&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class PersonValidator implements Validator {

    /**
     * This Validator validates only Person instances
     */
    public boolean supports(Class clazz) {
        return Person.class.equals(clazz);
    }

    public void validate(Object obj, Errors e) {
        ValidationUtils.rejectIfEmpty(e, &quot;name&quot;, &quot;name.empty&quot;);
        Person p = (Person) obj;
        if (p.getAge() &amp;lt; 0) {
            e.rejectValue(&quot;age&quot;, &quot;negativevalue&quot;);
        } else if (p.getAge() &amp;gt; 110) {
            e.rejectValue(&quot;age&quot;, &quot;too.darn.old&quot;);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 &lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/validation/Validator.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Validator Interface&lt;/a&gt;를 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 가지 메서드를 지원하고 있으며, 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;supports(Class)&lt;/b&gt;: Can this&lt;span&gt;&amp;nbsp;&lt;/span&gt;Validator&lt;span&gt;&amp;nbsp;&lt;/span&gt;validate instances of the supplied&lt;span&gt;&amp;nbsp;&lt;/span&gt;Class?&lt;/li&gt;
&lt;li&gt;&lt;b&gt;validate(Object, org.springframework.validation.Errors)&lt;/b&gt;: Validates the given object and, in case of validation errors, registers those with the given&lt;span&gt;&amp;nbsp;&lt;/span&gt;Errors&lt;span&gt;&amp;nbsp;&lt;/span&gt;object.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;supports는&amp;nbsp; 해당 클래스가 Person 클래스인지 확인하며, validate는 실제 validation 로직이 작성된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때, 오류 상황에 대한 내용은 Errors Object로 확인할 수 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;validate Method&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;validate 메서드&lt;/b&gt;&lt;/span&gt;를 보면, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Return Type&lt;/b&gt;&lt;/span&gt;이 조금 생각한 것과 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;boolean이 아닌&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt; void 타입&lt;/span&gt;&lt;/b&gt;인 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 Validation을 할 때는 boolean으로 처리하거나, Exception 으로 예외처리하는데, 현재 코드는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Argument&lt;/b&gt;&lt;/span&gt;로 Errors를 받고, Errors의 값을 변경하는 형태의 코드다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 처리되는 것은&lt;a href=&quot;https://martinfowler.com/articles/replaceThrowWithNotification.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt; 다음 문서&lt;/a&gt;를 보면 이해가 쉽다.&lt;/p&gt;
&lt;pre id=&quot;code_1660226180408&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public void check() {
   if (date == null) throw new IllegalArgumentException(&quot;date is missing&quot;);
   LocalDate parsedDate;
   try {
     parsedDate = LocalDate.parse(date);
   }
   catch (DateTimeParseException e) {
     throw new IllegalArgumentException(&quot;Invalid format for date&quot;, e);
   }
   if (parsedDate.isBefore(LocalDate.now())) throw new IllegalArgumentException(&quot;date cannot be before today&quot;);
   if (numberOfSeats == null) throw new IllegalArgumentException(&quot;number of seats cannot be null&quot;);
   if (numberOfSeats &amp;lt; 1) throw new IllegalArgumentException(&quot;number of seats must be positive&quot;);
 }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드를 보면, 모든 데이터의 Validation에 대해 Exception 처리를 하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나, 위 문서의 제목처럼 Validation에서는 Exception을 Notification 으로 변경하라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 Exception 처리를 하면, 제일 처음 Exception 사항 외에는 처리 결과를 알지 못한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, 아래와 같이 변경하는 것을 추천한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1042&quot; data-origin-height=&quot;426&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OjtDB/btrJu1H7JCE/ujjHZqssEZq9vEZO68Imzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OjtDB/btrJu1H7JCE/ujjHZqssEZq9vEZO68Imzk/img.png&quot; data-alt=&quot;Replace Exception&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OjtDB/btrJu1H7JCE/ujjHZqssEZq9vEZO68Imzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOjtDB%2FbtrJu1H7JCE%2FujjHZqssEZq9vEZO68Imzk%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1042&quot; height=&quot;426&quot; data-origin-width=&quot;1042&quot; data-origin-height=&quot;426&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Replace Exception&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 id=&quot;validation-conversion&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Resolving Codes to Error Messages&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/validation/ValidationUtils.html&quot;&gt;ValidationUtils&lt;/a&gt;나&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/validation/Errors.html&quot;&gt;Errors&lt;/a&gt;를 통해 에러 상황을 처리중이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;에러 코드&lt;/b&gt;&lt;/span&gt;를 작성해 넣어주고 있는데 이에 대한 처리를 보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러 코드는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;국제화(i18n)&lt;/b&gt;&lt;/span&gt;에 따라, 사용자의 Locale에 따라, 적절한 언어로 응답을 만들어 줄 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러 코드와 에러 메세지는 보통 messages.properties와 같은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;properties 파일&lt;/b&gt;&lt;/span&gt;에서 읽어오도록 구현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 에러 메세지는 Spring에서&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;MessageSource&lt;/b&gt;&lt;/span&gt;를 통해, 가져오도록 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;MessageSource&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MessageSource의 구현은 2가지가 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;StaticMessageSource: 코드로 메시지를 등록한다.&lt;/li&gt;
&lt;li&gt;ResourceBundleMessageSource: 리소스 파일로부터 메시지를 읽어와 등록한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시를 통해 알아보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 사용한 Person과 PersonValidator 소스는 동일하다.&lt;/p&gt;
&lt;pre id=&quot;code_1660227562405&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Getter
@Setter
@AllArgsConstructor
public class Person {

    private String name;
    private int age;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1660227574229&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class PersonValidator implements Validator {

    /**
     * This Validator validates only Person instances
     */
    public boolean supports(Class clazz) {
        return Person.class.equals(clazz);
    }

    public void validate(Object obj, Errors e) {
        ValidationUtils.rejectIfEmpty(e, &quot;name&quot;, &quot;name.empty&quot;);
        Person p = (Person) obj;
        if (p.getAge() &amp;lt; 0) {
            e.rejectValue(&quot;age&quot;, &quot;negativevalue&quot;);
        } else if (p.getAge() &amp;gt; 110) {
            e.rejectValue(&quot;age&quot;, &quot;too.darn.old&quot;);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메인 함수를 통해, Validation을 체크할텐데, 이 때 Error는 Interface이기 때문에, 이에 대한 구현체 중 하나인 &lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/validation/BindException.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;BindException&lt;/a&gt;을 사용할 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1660227815334&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static void main(String[] args) {
    Person person = new Person(&quot;&quot;, 200);
    PersonValidator personValidator = new PersonValidator();
    if(personValidator.supports(person.getClass())) {
        BindException error = new BindException(person, &quot;person&quot;);
        personValidator.validate(person, error);

        log.error(&quot;&amp;gt;&amp;gt;&quot; + error.hasErrors());
        log.error(&quot;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&quot; + error.getAllErrors());
    } else {
        log.error(&quot;invalid Class&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;23:48:15.866 [main] ERROR com.example.demo.validation.Main - &amp;gt;&amp;gt;true&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;23:48:15.871&amp;nbsp;[main]&amp;nbsp;ERROR&amp;nbsp;co&lt;br /&gt;m.example.demo.validation.Main&amp;nbsp;-&amp;nbsp;&amp;gt;&amp;gt;&amp;gt;&amp;gt;[Field&amp;nbsp;error&amp;nbsp;in&amp;nbsp;object&amp;nbsp;'person'&amp;nbsp;on&amp;nbsp;field&amp;nbsp;'name':&amp;nbsp;rejected&amp;nbsp;value&amp;nbsp;[];&amp;nbsp;codes&amp;nbsp;[name.empty.person.name,name.empty.name,name.empty.java.lang.String,name.empty];&amp;nbsp;arguments&amp;nbsp;[];&amp;nbsp;default&amp;nbsp;message&amp;nbsp;[null],&amp;nbsp;Field&amp;nbsp;error&amp;nbsp;in&amp;nbsp;object&amp;nbsp;'person'&amp;nbsp;on&amp;nbsp;field&amp;nbsp;'age':&amp;nbsp;rejected&amp;nbsp;value&amp;nbsp;[200];&amp;nbsp;codes&amp;nbsp;[too.darn.old.person.age,too.darn.old.age,too.darn.old.int,too.darn.old];&amp;nbsp;arguments&amp;nbsp;[];&amp;nbsp;default&amp;nbsp;message&amp;nbsp;[null]]&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러에 대한 로그를 보면, 설정했던 에러 코드들을 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Validator의 단점&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이, 비즈니스 로직을 하나하나 구현해줘야 하는 단점이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 로직이 복잡하다면, 당연히 어울리는 방향이지만, &lt;b&gt;문자열이 없는 경우 ,특정값보다 큰 경우&lt;/b&gt;와 같은 건 Validator로 구현하는 것보다 더 간단한 방법이 필요해보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그에 따라,&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt; Annotation&lt;/b&gt;&lt;/span&gt;으로 설정하는 방법들이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Java Bean Validation&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#validation-beanvalidation&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;해당 링크&lt;/a&gt;를 보면, Annotation에 대한 설정들이 나온다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;package com.example.demo.validation;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;

@Setter
@Getter
@AllArgsConstructor
public class PersonForm {
    @NotNull
    @Size(max=64)
    private String name;

    @Min(0)
    private int age;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 과정에서 validation을 위한 Dependency를 추가했다는 것을 보기 위해, import도 추가해 두었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;358&quot; data-origin-height=&quot;591&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Jqq9l/btrJuS5Vj49/ECdPalr75RrUeFOMx85j11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Jqq9l/btrJuS5Vj49/ECdPalr75RrUeFOMx85j11/img.png&quot; data-alt=&quot;validation-api&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Jqq9l/btrJuS5Vj49/ECdPalr75RrUeFOMx85j11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJqq9l%2FbtrJuS5Vj49%2FECdPalr75RrUeFOMx85j11%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;358&quot; height=&quot;591&quot; data-origin-width=&quot;358&quot; data-origin-height=&quot;591&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;validation-api&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많은 Validation을 제공해주며, 간단한 것은 Annotation으로 처리가 가능하다는 것을 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Configuring a Bean Validation Provider&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이, &lt;b&gt;Annotation으로 적용 가능했고, 이를 이제 어떻게 쓰는지 알아야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시를 보며, 그 사용법을 먼저 보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선, Dependency부터 확인하자.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;implementation 'org.springframework.boot:spring-boot-starter-validation'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Springboot 에서는 위와 같이 등록되면 되며, Spring에서는 Hibernate Validator 와 같은 구현체가 필요하니, 유의하도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;spring-boot-starter-validation에는 Hibernate-validator가 이미 포함되어 있다.&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조심해야 하는 부분은, validation-api 가 jakarta 로 3.0.2버전이길래, 해당 버전으로 적용하려 했더니, 패키지 구조가 달라 정상적이 처리가 불가능했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(springboot-starter에서 적용되는 버전은 2버전 대였으며, javax를 사용하고 있었다.)&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AppConfig(Configuration)를 통해, validator를 Bean으로 등록하자.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Configuration
public class AppConfig {
    @Bean
    public LocalValidatorFactoryBean validator() {
        return new LocalValidatorFactoryBean();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이, Method를 Bean으로 등록하면, Autowired를 통해 Service에서 Validator를 가져와 쓸 수 있게 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1660236617728&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package com.example.demo.service;

import com.example.demo.validation.PersonForm;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class MyService {

    @Autowired
    private Validator validator;

    public void check() {
        PersonForm personForm = new PersonForm(&quot;KOO&quot;, 25);
        // PersonForm personForm = new PersonForm(&quot;KOO&quot;, -5);
        Set&amp;lt;ConstraintViolation&amp;lt;PersonForm&amp;gt;&amp;gt; results = validator.validate(personForm);

        if(!results.isEmpty()) {
            log.error(&quot;Validate Fail&quot;);
            results.forEach(v -&amp;gt; {
                log.error(&quot;&amp;gt;&amp;gt; error Msg : &quot; + v.getMessage());
            });
        } else {
            log.info(&quot;Validate Success&quot;);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 메인에서 실행해보며, 설정에 따라, Success 혹은 Fail를 확인하자.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Slf4j
public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(AppConfig.class);
        context.refresh();
        MyService service = context.getBean(MyService.class);
        service.check();
        context.close();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러 상황에서 로그를 확인하면 다음과 같이, 한글로 나오는 것을 볼 수 있다. (check method 내에 Locale 설정으로, 다른 언어도 가능하다)&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;01:55:46.733 [main] ERROR com.example.demo.service.MyService - Validate Fail &lt;br /&gt;01:55:46.737 [main] ERROR com.example.demo.service.MyService - &amp;gt;&amp;gt; error Msg : 110 이하여야 합니다 01:55:46.737 [main] ERROR com.example.demo.service.MyService - &amp;gt;&amp;gt; error Msg : 크기가 0에서 3 사이여야 합니다&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Custom Annotation for Validation (Configuring Custom Constraints)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring의 Validator를 사용하는 것보다, Annotation을 사용하는 것이 매우 간편하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데, 지원하지 않는 기능에 대한 Validation은 어떻게 적용할 수 있을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서, Validator Interface의 구현체가 또 필요한 것일까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다행히, 그렇지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Custom 하게 Annotation을 적용해 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그를 위해서는 2가지를 구현해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Constraint(제약)&lt;/b&gt;&lt;/span&gt;, 그리고 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Validator(검증자)&lt;/b&gt;&lt;/span&gt;다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;A&amp;nbsp;&lt;b&gt;@Constraint&amp;nbsp;annotation&lt;/b&gt; that declares the constraint and its configurable properties.&lt;/li&gt;
&lt;li&gt;An implementation of the&amp;nbsp;javax.validation.&lt;b&gt;ConstraintValidator&lt;/b&gt;&amp;nbsp;interface that implements the constraint&amp;rsquo;s behavior.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1660238364852&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy=MyConstraintValidator.class)
public @interface MyConstraint {
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1660238379027&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import javax.validation.ConstraintValidator;

public class MyConstraintValidator implements ConstraintValidator {

    @Autowired;
    private Foo aDependency;

    // ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시를 봐야 좀더 이해가 쉬울 것 같아,&lt;a href=&quot;https://meetup.toast.com/posts/223&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt; 다른 분이 적용해 둔 것&lt;/a&gt;을 가져와보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RUNTIME)
@Constraint(validatedBy = NoEmojiValidator.class)
@Documented
public @interface NoEmoji{
    String message() default &quot;Emoji is not allowed&quot;;

    Class&amp;lt;?&amp;gt;[] groups() default {};

    Class&amp;lt;? extends Payload&amp;gt;[] payload() default {};

    @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
    @Retention(RUNTIME)
    @Documented
    @interface List{
        NoEmoji[] value();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;public class NoEmojiValidator implements ConstraintValidator&amp;lt;NoEmoji, String&amp;gt; {
    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (StringUtils.isEmpty(value) == true) {
            return true;
        }

        return EmojiParser.parseToAliases(value).equals(value);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;public class CreateContact {
    @NoEmoji
    @Length(max = 64)
    @NotBlank
    private String uid;
    @NotNull
    private ContactType contactType;
    @Length(max = 1_600)
    private String contact;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Wrap up&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;꽤 길게 Validation에 대해 알아보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Annotation을 사용하는게 바람직하면서도, Custom 하게 만들 수도 있어야 한다는 점을 유념하도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Framework/Spring</category>
      <category>Anntation</category>
      <category>spring</category>
      <category>validation</category>
      <category>스프링</category>
      <category>유효성 검사</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/70</guid>
      <comments>https://koocci-dev.tistory.com/70#entry70comment</comments>
      <pubDate>Fri, 12 Aug 2022 02:29:33 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] Resource는 어떻게 처리할까?</title>
      <link>https://koocci-dev.tistory.com/69</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : 스프링에서 Resource 처리를 구현할 수 있다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Resource&lt;/b&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IoC Container에 대한 챕터를 마무리하고,&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#resources&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt; Resource 챕터&lt;/a&gt;를 확인해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Resource&lt;/b&gt;&lt;/span&gt;가 무엇인지 이해가 필요할 것 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;167&quot; data-origin-height=&quot;94&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwyEYc/btrJn73M79m/zkHK1McaGKzfsE0kI8wIj0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwyEYc/btrJn73M79m/zkHK1McaGKzfsE0kI8wIj0/img.png&quot; data-alt=&quot;resources&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwyEYc/btrJn73M79m/zkHK1McaGKzfsE0kI8wIj0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwyEYc%2FbtrJn73M79m%2FzkHK1McaGKzfsE0kI8wIj0%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;167&quot; height=&quot;94&quot; data-origin-width=&quot;167&quot; data-origin-height=&quot;94&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;resources&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;intellij로 스프링 프로젝트를 시작하면, resources 폴더가 생기게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring에서 java 뿐 아니라, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;외부의 파일&lt;/b&gt;&lt;/span&gt;들을 읽어야 하는 경우가 생긴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(앞서 배웠던 &lt;a href=&quot;https://koocci-dev.tistory.com/67?category=1012333&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;properties&lt;/a&gt;도 외부 파일 중 하나다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 &lt;b&gt;외부 파일들을 읽어드리거나, URL을 통해 가져와서 프로그래밍에 활용&lt;/b&gt;을 하는데, Spring에서는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Resource&lt;/b&gt;&lt;/span&gt;라는 Interface를 통해, 추상화를 해주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Spring이 없으면, 어떻게 할 수 있었을까?&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1660145119560&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static void main(String[] args) throws IOException {
    String path = &quot;C:\\Users\\lazye\\Desktop\\dev\\src\\main\\resources\\application-dev.properties&quot;;
    File file = new File(path);
    InputStream is = new FileInputStream(file);
    byte[] bytes = is.readAllBytes();
    String properties = new String(bytes);
    System.out.println(properties);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단히 파일을 읽어보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 특정 파일을 읽어오고 싶을 때는 위와 같이 했고, 다만 절대 경로를 알 수 없는 경우가 많으니, classPath를 설정해주는 경우가 많았다.&lt;/p&gt;
&lt;pre id=&quot;code_1660145396004&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static void main(String[] args) throws IOException {
    InputStream is = Main.class.getClassLoader().getResourceAsStream(&quot;application-dev.properties&quot;);
    byte[] bytes = is.readAllBytes();
    String properties = new String(bytes);
    System.out.println(properties);
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Resource Interface&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이제, &lt;a href=&quot;https://docs.spring.io/spring-framework/docs/5.3.22/javadoc-api/org/springframework/core/io/Resource.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Resource Interface&lt;/a&gt;를 보도록 하자.&lt;/p&gt;
&lt;pre id=&quot;code_1660145692974&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface Resource extends InputStreamSource {

    boolean exists();

    boolean isReadable();

    boolean isOpen();

    boolean isFile();

    URL getURL() throws IOException;

    URI getURI() throws IOException;

    File getFile() throws IOException;

    ReadableByteChannel readableChannel() throws IOException;

    long contentLength() throws IOException;

    long lastModified() throws IOException;

    Resource createRelative(String relativePath) throws IOException;

    String getFilename();

    String getDescription();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 보듯, &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;InputStreamSource&lt;/span&gt;&lt;/b&gt;를 상속받고 있고, 이 Interface는 간단히, getInputStream을 가져올 수 있도록 되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 위에서 해본 것처럼 Byte 배열을 가져올 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1660145896940&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface InputStreamSource {

    InputStream getInputStream() throws IOException;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;resources-implementations&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Built-in&lt;span&gt;&amp;nbsp;&lt;/span&gt;Resource&lt;span&gt;&amp;nbsp;&lt;/span&gt;Implementations&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, 우리는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Resource의 구현체&lt;/b&gt;&lt;/span&gt;를 주로 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring에서 제공하는 구현체가 있고, 관례에 따라(추후 확인할 Resource Loader에서 사용하는) 이를 가져와 사용한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#resources-implementations-urlresource&quot;&gt;UrlResource&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#resources-implementations-classpathresource&quot;&gt;ClassPathResource&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#resources-implementations-filesystemresource&quot;&gt;FileSystemResource&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#resources-implementations-pathresource&quot;&gt;PathResource&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#resources-implementations-servletcontextresource&quot;&gt;ServletContextResource&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#resources-implementations-inputstreamresource&quot;&gt;InputStreamResource&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#resources-implementations-bytearrayresource&quot;&gt;ByteArrayResource&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 구현체 중, 자주 사용하는 2가지만 알아보고 상황에 따라, 다른 구현체도 사용해볼 수 있도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;resources-implementations-urlresource&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;UrlResource&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;file:&lt;br /&gt;&amp;nbsp;for accessing filesystem paths,&amp;nbsp;&lt;br /&gt;https:&lt;br /&gt;&amp;nbsp;for accessing resources through the HTTPS protocol,&amp;nbsp;&lt;br /&gt;ftp:&lt;br /&gt;&amp;nbsp;for accessing resources through FTP&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이, &lt;b&gt;&lt;span style=&quot;color: #666666;&quot;&gt;file:, &lt;span style=&quot;color: #666666;&quot;&gt;https:, &lt;span style=&quot;color: #666666;&quot;&gt;ftp:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt; 같이 프로토콜을 명시하고, 해당 리소스의 위치를 URL 방식으로 알려주는 형태다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;resources-implementations-classpathresource&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;ClassPathResource&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서, ClassLoader를 통해, properties를 읽었듯이, ClassPath를 통해 리소스 위치를 찾는 방식이다.&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;ResourceLoader&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로는 구현체의 사용보다, ResourceLoader를 통해 리소스를 가져오는 경우가 많다.&lt;/p&gt;
&lt;pre id=&quot;code_1660147978786&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface ResourceLoader {

    Resource getResource(String location);

    ClassLoader getClassLoader();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이, ResourceLoader는 Interface다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, 우리가 사용하는 ApplicationContext의 상속구조를 타고 올라가보면 다음과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1660148195288&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
		MessageSource, ApplicationEventPublisher, ResourcePatternResolver
// ResourcePatternResolver Interface를 타고 들어간다.

public interface ResourcePatternResolver extends ResourceLoader&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Spring에서 사용하는 ApplicationContext 구현체는 ResourceLoader를 상속받아 구현하고 있다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, 다음과 같이 사용할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1660148290156&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Resource template = ctx.getResource(&quot;some/resource/path/myTemplate.txt&quot;);
Resource template = ctx.getResource(&quot;classpath:some/resource/path/myTemplate.txt&quot;);
Resource template = ctx.getResource(&quot;file:///some/resource/path/myTemplate.txt&quot;);
Resource template = ctx.getResource(&quot;https://myhost.com/resource/path/myTemplate.txt&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;resources-resourceloaderaware&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;ResourceLoaderAware&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Aware라는 postfix가 붙은 Interface의 공통점은, &lt;a href=&quot;https://koocci-dev.tistory.com/63&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;앞선 포스팅&lt;/a&gt;에서 알아봤듯이, ResourceLoader를 set하고, get하여 사용하는 형태로 Bean에서 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Wrap up&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 Resource를 사용하는 방법까지 알아보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 validation과 AOP를 알아본 후에, Core 부분을 마무리하도록 하자.&lt;/p&gt;</description>
      <category>Framework/Spring</category>
      <category>resource</category>
      <category>ResourceLoader</category>
      <category>spring</category>
      <category>리소스</category>
      <category>스프링</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/69</guid>
      <comments>https://koocci-dev.tistory.com/69#entry69comment</comments>
      <pubDate>Thu, 11 Aug 2022 01:36:32 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] 환경설정은 어떻게 할 수 있을까?</title>
      <link>https://koocci-dev.tistory.com/67</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : 스프링에서 Environment 설정을 할 수 있다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에 진행하고자 하는 사항은 Environment 설정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조금 더 구체적으로 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Environment Abstraction&lt;/b&gt;&lt;/span&gt;이며, 그 위치는 &lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-environment&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;다음&lt;/a&gt;과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Environment Interface&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Environment Abstraction이라는 단어들로 알 수 있듯, 환경에 대한 추상화, 즉, Spring에서는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Environment Interface&lt;/b&gt;&lt;/span&gt;를 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주로, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Environment Interface&lt;/b&gt;&lt;/span&gt;는 profiles 나 properties 처럼, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;프로그램의 환경 변수&lt;/b&gt;&lt;/span&gt; 그리고, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Applcation의 프로필&lt;/b&gt;&lt;/span&gt;을 관리할 때 사용하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 &lt;a href=&quot;https://docs.spring.io/spring-framework/docs/5.3.22/javadoc-api/org/springframework/core/env/Environment.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Environment Interface 문서&lt;/a&gt;를 보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 것들의 Super Interface는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;PropertyResolver&lt;/b&gt;&lt;/span&gt;이며, acceptsProfiles나 getDefaultProfiles 등의 Method로 프로필 정보를 받아올 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/5.3.22/javadoc-api/org/springframework/core/env/PropertyResolver.html&quot;&gt;PropertyResolver&lt;/a&gt;&lt;span&gt;&lt;span&gt; 의 경우, getProperty 등으로, 환경 변수를 가져올 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Resolver&lt;/b&gt;&lt;/span&gt; 라는 건 보통 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;변환기&lt;/b&gt;&lt;/span&gt;와 같은 의미로 사용된다.&lt;br /&gt;PropertyResolver 역시, 환경변수를 사용하기 좋게 변환하는 역할을 한다고 보면 이해하기 쉽다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Profile&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Profile&lt;/b&gt;&lt;/span&gt;의 경우는 보통 &lt;b&gt;서버환경에 따라 설정값을 달리 할 경우&lt;/b&gt;가 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dev 환경에서는 Profile에 dev를 설정하고, Testbed, staging 서버에서는 stage 혹은 tb, 그리고 상용 서버에선 prod 로 설정하면서 Properties나 &lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/javax/sql/DataSource.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Datasource&lt;/a&gt;를 다르게 읽는 경우가 가장 자주 쓰이게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 사용 예시를 한번 보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Datasource&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Datasource Interface&lt;/b&gt;는 &lt;b&gt;DB Connection&lt;/b&gt; 관리를 위해 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;jdbc에서 connection을 단순히 open을 하면, 하나의 Connection 만 연결된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나, 웹서버에서는 여러 요청에 따라 DB 자원을 사용해야하는데, 하나의 Connection으로는 무리가 따른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, DataSource를 통해 Connection을 관리(Connection Pool)한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660135921000&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Bean
public DataSource dataSource() {
    return new EmbeddedDatabaseBuilder()
        .setType(EmbeddedDatabaseType.HSQL)
        .addScript(&quot;my-schema.sql&quot;)
        .addScript(&quot;my-test-data.sql&quot;)
        .build();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 dataSource를 Bean으로 등록했다고 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소스를 보듯, Embedded된 Datasource로, &lt;b&gt;개발환경&lt;/b&gt;에서 사용하는 경우일 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660135967220&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Bean(destroyMethod=&quot;&quot;)
public DataSource dataSource() throws Exception {
    Context ctx = new InitialContext();
    return (DataSource) ctx.lookup(&quot;java:comp/env/jdbc/datasource&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #252525;&quot;&gt;이제 application의 DataSource가 상용 서버의 JNDI 디렉토리에 등록되어 있다고 가정하고, 이를 상용 환경에 배포할 수 있는 방법을 고려해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660136393245&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Bean(destroyMethod=&quot;&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;destroyMethod는 Bean이 Application Context에서 종료될 때, 호출되는 메서드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1660136397242&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Context ctx = new InitialContext();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Connection Pool에 접근하기 위해서는 JNDI 서비스를 사용해야 하며, JNDI는 서버에서 관리하고 있는 리소스에 대한 정보를 알고 있고, 특정 리소스를 찾아 사용할 수 있도록 객체를 반환한다.&lt;/p&gt;
&lt;pre id=&quot;code_1660136401749&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ctx.lookup(&quot;java:comp/env/jdbc/datasource&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;lookup은 DNS 서버에서 IP를 찾 듯, 리소스를 찾은 후 리소스를 사용할 수 있도록 객체를 반환해주는 메서드다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;찾고자 하는 리소스는 jdbc/datasource이며, WAS인 톰캣에서 리소스를 관리하는 가상의 디렉터리는 &quot;java:comp/env&quot;이라는 뜻이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;JNDI : &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;JNDI(Java Naming and Directory Interface)&lt;/b&gt;&lt;/span&gt;는 디렉터리 서비스에서 제공하는 데이터 및 객체를 발견하고 참고하기 위한 자바 API다. (분산환경에서 자원을 연결해주는 기능)&lt;/blockquote&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@Profile&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이제, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Profile&lt;/b&gt;&lt;/span&gt;을 통해 어떻게 접근할 수 있을지 보도록 하자.&lt;/p&gt;
&lt;pre id=&quot;code_1660136642077&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
@Profile(&quot;development&quot;)
public class StandaloneDataConfig {

    @Bean
    public DataSource dataSource() {
        return new EmbeddedDatabaseBuilder()
            .setType(EmbeddedDatabaseType.HSQL)
            .addScript(&quot;classpath:com/bank/config/sql/schema.sql&quot;)
            .addScript(&quot;classpath:com/bank/config/sql/test-data.sql&quot;)
            .build();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1660136648807&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
@Profile(&quot;production&quot;)
public class JndiDataConfig {

    @Bean(destroyMethod=&quot;&quot;)
    public DataSource dataSource() throws Exception {
        Context ctx = new InitialContext();
        return (DataSource) ctx.lookup(&quot;java:comp/env/jdbc/datasource&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위처럼 Annotation도 가능하지만, XML역시 가능하다.&lt;/p&gt;
&lt;pre id=&quot;code_1660136832258&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;beans profile=&quot;development&quot;
    xmlns=&quot;http://www.springframework.org/schema/beans&quot;
    xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
    xmlns:jdbc=&quot;http://www.springframework.org/schema/jdbc&quot;
    xsi:schemaLocation=&quot;...&quot;&amp;gt;

    &amp;lt;jdbc:embedded-database id=&quot;dataSource&quot;&amp;gt;
        &amp;lt;jdbc:script location=&quot;classpath:com/bank/config/sql/schema.sql&quot;/&amp;gt;
        &amp;lt;jdbc:script location=&quot;classpath:com/bank/config/sql/test-data.sql&quot;/&amp;gt;
    &amp;lt;/jdbc:embedded-database&amp;gt;
&amp;lt;/beans&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1660136837946&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;beans profile=&quot;production&quot;
    xmlns=&quot;http://www.springframework.org/schema/beans&quot;
    xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
    xmlns:jee=&quot;http://www.springframework.org/schema/jee&quot;
    xsi:schemaLocation=&quot;...&quot;&amp;gt;

    &amp;lt;jee:jndi-lookup id=&quot;dataSource&quot; jndi-name=&quot;java:comp/env/jdbc/datasource&quot;/&amp;gt;
&amp;lt;/beans&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, 다음과 같이, 어떤 Profile을 Active 시킬지, 설정할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1660136887809&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles(&quot;development&quot;);
ctx.register(SomeConfig.class, StandaloneDataConfig.class, JndiDataConfig.class);
ctx.refresh();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 위처럼 하면, 소스를 수정해야 하므로, 보통 properties로 설정을 하며, 다음과 같이 설정하여 구동한다.&lt;/p&gt;
&lt;pre id=&quot;code_1660139275241&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# properties 파일일 때 (application-prod.properties)
spring.profiles.active=prod

# yml 파일일 때 (application-prod.xml)
spring:
  profiles:
    active: prod&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;java -jar -Dspring.profiles.active=prod application.jar&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Wrap up&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아마 가장 처음에 Spring 프로젝트를 시작할 때 설정하는 부분일 것으로 보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;환경 설정은 아주 간단히 작성하였지만, 연동하는 point가 많을 수록 그 양이 상당해지고, 그에 따라 관리해야할 포인트도 많아진다. (특히, 배포 시에 Property 파일을 바꾸는 작업을 할 때는 주의해야한다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이, 단순히 환경설정하는 방법만 알고 진행하는 것보다 ,그에 대한 자세한 내용을 알아보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Framework/Spring</category>
      <category>Configuration</category>
      <category>environment</category>
      <category>Profile</category>
      <category>Properties</category>
      <category>spring</category>
      <category>스프링</category>
      <category>환경변수</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/67</guid>
      <comments>https://koocci-dev.tistory.com/67#entry67comment</comments>
      <pubDate>Wed, 10 Aug 2022 22:59:11 +0900</pubDate>
    </item>
    <item>
      <title>자바스크립트 기초부터 모던 자바스크립트까지 - this편</title>
      <link>https://koocci-dev.tistory.com/66</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : 자바스크립트의 this를 사용할 수 있다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 &lt;a href=&quot;https://koocci-dev.tistory.com/42?category=1030064&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;객체를 공부할 때&lt;/a&gt; 크게 2가지로 나누어진다는 것을 알았다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;프로퍼티&lt;/b&gt;&lt;/span&gt; : 객체의 상태를 나타내는 값(Data)&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;메서드&lt;/b&gt;&lt;/span&gt; : 프로퍼티(상태 데이터)를 참조하고 조작할 수 있는 동작(Behavior)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 두가지를 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;하나의 논리적인 단위로 묶은 복합적인 자료구조&lt;/b&gt;&lt;/span&gt;가 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;객체&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;메서드&lt;/b&gt;&lt;/span&gt;에서는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;자신이 속한 객체의 상태(프로퍼티)를 알 수 있어야&lt;/b&gt;&lt;/span&gt; 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 말은, 자신이 속한 곳이 어디인지 지칭할 수 있어야 한다는 말이며, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;자신이 속한 객체를 가리키는 식별자를 참조할 수 있어야 한다&lt;/b&gt;&lt;/span&gt;는 말로 귀결된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 역할을 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;this&lt;/b&gt;&lt;/span&gt; 가 하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;this 키워드&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;this&lt;/b&gt;&lt;/span&gt;는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;자신이 속한 객체&lt;/b&gt;&lt;/span&gt; 또는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;자신이 생성할 인스턴스&lt;/b&gt;&lt;/span&gt;를 가리키는 자기 참조 변수다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주의해야 할 점은 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;this는&lt;/span&gt; 상황&lt;span style=&quot;color: #006dd7;&quot;&gt;에 따라서&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&amp;nbsp;&lt;/span&gt;지칭하는 것이 달라진다&lt;/b&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 예시를 보자.&lt;/p&gt;
&lt;pre id=&quot;code_1659450445653&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 전역에서 this는 Window를 가리킨다.
console.log(this); // Window

// 일반 함수에서 this는 Window를 가리킨다. (전역과 동일)
function square(number) {
  console.log(this); // Window
  return number * number;
};
square(2);

// 객체 리터럴
const person = {
  name: 'Lee',
  getName() {
    // 메서드 내부에서 this는 메서드를 호출할 때 사용된 객체를 가리킨다.
    console.log(this); // {name: &quot;Lee&quot;, getName: f}
    return this.name;
  }
}
console.log(person.getName());

// 생성자 함수
function Person(name) {
  console.log(this); // Person {name: &quot;Lee&quot;}
  this.name = name;
}

const me = new Person(&quot;Lee&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;strict mode&lt;/b&gt;&lt;/span&gt;에서는 일반 함수 내부의 this는 &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;undefined&lt;/span&gt; &lt;/b&gt;처리된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;함수 호출 방식에 따른 this 바인딩&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조금 더 자세히 정리해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;this가 가리키는 값, 즉&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;this 바인딩&lt;/span&gt;은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;함수 호출 방식에 의해 동적으로 결정&lt;/span&gt;&lt;/b&gt;된다.&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;바인딩(binding)&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 식별자와 값을 연결하는 과정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시&amp;gt; 변수 선언은 변수 이름(식별자)과 확보된 메모리 공간 주소를 바인딩하는 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시&amp;gt; this 바인딩은 this와 this가 가리킬 객체를 연결하는 과정&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;함수 호출 방식, 즉&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;함수가 어떻게 호출되었는지&lt;/span&gt;에 따라 결정된다는 것이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://koocci-dev.tistory.com/49?category=1030064&quot;&gt;함수의 Scope를 공부할 때&lt;/a&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;렉시컬 스코프&lt;/b&gt;&lt;/span&gt;를 설명했었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;렉시컬 스코프&lt;/b&gt;&lt;/span&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;함수가 정의가 평가되어 함수 객체가 생성하는 시점에 상위 스코프를 결정&lt;/b&gt;&lt;/span&gt;했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나,&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;this&lt;/b&gt;&lt;/span&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;함수 호출 시점에 결정&lt;/b&gt;&lt;/span&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 설명을 하는 것에는 이유가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;this가 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;함수 호출 시점에 결정된다&lt;/b&gt;&lt;/span&gt;는 것은, &lt;b&gt;같은 함수더라도 &lt;span style=&quot;color: #006dd7;&quot;&gt;어떻게 호출되냐&lt;/span&gt;에 따라 그 환경이 다를 수 있다는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 말해, &lt;b&gt;this는 선언된 위치에 따라 다르게 지칭하며, 그 선언된 위치는 함수가 어떻게 호출되냐에 따라 다르다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 함수의 호출 방식에 어떤 것들이 있는지부터 알 필요가 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;일반 함수 호출&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;메서드 호출&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;생성자 호출&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Function.prototype.apply/call/bind 메서드에 의한 간접 호출&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 바로 예시를 보자.&lt;/p&gt;
&lt;pre id=&quot;code_1659451348212&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function square(number) {
  console.log(this);
  return number * number;
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적인 함수를 선언하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아마 앞서 본 예시와 같이, square(2);를 호출한다면, this는 Window 혹은 strict mode일 때 undefined를 출력할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 다음과 같이 바꾸어 보면, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;함수 호출 방식&lt;/b&gt;&lt;/span&gt;이라는 것이 무엇인지 감이 온다.&lt;/p&gt;
&lt;pre id=&quot;code_1659451434265&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 호출 방식에 따라 this 바인딩이 동적으로 결정된다.
function foo() {
  console.log(this);
};

// 1. 일반 함수 호출
// foo 함수를 일반적인 방식으로 호출
foo(); // Window

// 2. 메서드 호출
// 프로퍼티 값으로 square을 할당
// 메서드를 호출한 객체를 출력
const obj = { foo };
obj.foo(); // {foo: f}

// 3. 생성자 호출
// foo 함수가 생성한 인스턴스를 출력
new foo(); // foo&amp;nbsp;{}

// 4. Function.prototype.call/appliy/bind
const bar = { name: 'bar' };
foo.call(bar); // {name: 'bar'}
foo.apply(bar); // {name: 'bar'}
foo.bind(bar); // f foo() {console.log(this);}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;일반 함수 호출&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 기본적으로 this는 &lt;b&gt;전역 객체&lt;/b&gt;가 바인딩된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 일반 함수는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;중첩이더라도&lt;/b&gt;&lt;/span&gt; this에는 전역 객체가 바인딩된다.&lt;b&gt; 설령, &lt;span style=&quot;color: #ee2323;&quot;&gt;메서드 내&lt;/span&gt;에 있더라도, &lt;span style=&quot;color: #ee2323;&quot;&gt;콜백 함수&lt;/span&gt;더라도 말이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단, 앞서 말했듯이, &lt;b&gt;strict mode&lt;/b&gt;에서는 &lt;b&gt;undefined&lt;/b&gt;이다.&lt;/p&gt;
&lt;pre id=&quot;code_1659452806847&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var value = 1;
const obj = {
  value: 100,
  foo() {
    // 메서드에서의 this
    console.log(&quot;foo`s this: &quot;, this); // {value: 100, foo: f}
    console.log(&quot;foo`s this.value: &quot;, this.value); // 100

    // 일반함수에서의 this는 전역이므로, value는 1
    function bar1() {
      console.log(&quot;bar1`s this: &quot;, this); // Window
      console.log(&quot;bar1`s this.value: &quot;, this.value); // 1
    };

    // strict mode에서는 undefined
    function bar2() {
      'use strict';
      console.log(&quot;bar2`s this: &quot;, this); // undefined
      // console.log(&quot;bar2`s this.value: &quot;, this.value); // Error
    };
    bar1();
    bar2();
  },
  // callback 내에 일반함수 역시 전역
  callback() {
    setTimeout(function() {
      console.log(&quot;callback`s this: &quot;, this);
      console.log(&quot;callback`s this.value: &quot;, this.value);
    }, 100);
  }
}
obj.foo();
obj.callback();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;일반 함수로 호출된 모든 함수(중첩, 콜백 포함) 내부의 this는&lt;span style=&quot;color: #ee2323;&quot;&gt; 전역 객체&lt;/span&gt;가 바인딩된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 중첩함수, 콜백함수에서까지, 전역 객체로 바인딩되는 것은 좀 문제가 있어보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통, &lt;b&gt;중첩함수나 콜백함수의 목적은 헬퍼 함수로서가 크다&lt;/b&gt;. 즉, &lt;b&gt;외부 함수의 로직을 대체할 경우가 많다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, 이에 대한 적절한 절차가 필요해 보인다.&lt;/p&gt;
&lt;pre id=&quot;code_1659453424943&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var value = 1;
const obj = {
  value: 100,
  foo() {
    const that = this;
    setTimeout(function() {
      console.log(&quot;callback`s this: &quot;, this);
      console.log(&quot;callback`s that: &quot;, that);
    }, 100);
  }
}
obj.foo();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;약간의 변조를 주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 앞서 잠깐 다뤘던 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;apply, call, bind&lt;/b&gt;&lt;/span&gt; 메서드 혹은 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;화살표 함수&lt;/b&gt;&lt;/span&gt;를 사용하면 해결할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이에 대해서는 잠시 후에(화살표 함수는 나중에) 다루어 보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;메서드 호출&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 계속해서 메서드 호출을 확인해왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주의할 점은 메서드 내부의 this는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;메서드를 소유한 객체가 아니라 &lt;span style=&quot;color: #ee2323;&quot;&gt;메서드를 호출한 객체&lt;/span&gt;에 바인딩된다는 것&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소유와 호출의 개념을 정리해보자.&lt;/p&gt;
&lt;pre id=&quot;code_1659453959133&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const person1 = {
  name: 'Lee',
  getName() {
    // 메서드 내부의 this는 메서드를 호출한 객체에 바인딩
    return this.name;
  }
};

// 메서드 getName을 호출한 객체는 person이다.
console.log(person1.getName()); // Lee

const person2 = {
	name: 'Kim'
}

// person2의 getName 메서드를 person1에게서 가져와 할당
person2.getName = person1.getName;
// getName을 호출한 객체는 person2이다.
console.log(person2.getName()); // Kim

// getName 변수에 person1.getName 메서드를 할당
const getName = person1.getName;
console.log(getName()); // ''
// Window.name이 호출되어, ''이 출력된다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분명, getName 메서드는 처음에 person1에서 소유하고 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 person2의 메서드나 변수에서 getName을 가져왔더니, &lt;b&gt;this의 지칭이 바뀐 것을 알 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분은 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;메서드&lt;/b&gt;&lt;/span&gt;가 단지 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;프로퍼티에 바인딩된 함수&lt;/b&gt;&lt;/span&gt;라는 개념을 알아야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, getName 메서드는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;독립적인 함수 객체&lt;/b&gt;&lt;/span&gt;이고, person1 객체에서 프로퍼티로 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;해당 함수를 지칭&lt;/b&gt;&lt;/span&gt;하고 있을 뿐이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 테스트 하면 조금 헤깔릴 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;prototype으로 알아보면, 왜 호출한 객체라고 표현하는지 더 명확해진다.&lt;/p&gt;
&lt;pre id=&quot;code_1659456531769&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Person(name){
  this.name = name;
};

Person.prototype.getName = function() {
  console.log(this);
  return this.name;
}

const person1 = new Person('Lee');
const person2 = new Person('Kim');
const person3 = new Person('Koo');
person1.getName(); // Person {name: 'Lee'}
person2.getName(); // Person {name: 'Kim'}
person3.getName(); // Person {name: 'Koo'}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;생성자 함수 호출&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 이전 &lt;a href=&quot;https://koocci-dev.tistory.com/56?category=1030064&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;생성자&lt;/a&gt;를 공부하면서도 다루었기에 이해가 더 쉬울 것으로 보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;생성자 함수&lt;/b&gt;&lt;/span&gt; 내부의 this는 생성자 함수가 미래에 생성할 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;인스턴스&lt;/b&gt;&lt;/span&gt;가 바인딩된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1659456780407&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Circle(radius) {
    // 생성자 함수 내부의 this는 생성자 함수가 생성할 인스턴스를 가리킨다.
    this.radius = radius;
    this.getDiameter = function() {
    	return 2 * this.radius;
    };
}

const circle1 = new Circle(5);
const circle2 = new Circle(7);

console.log(circle1.getDiameter()); // 10
console.log(circle2.getDiameter()); // 14&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, &lt;b&gt;new가 아니라 그냥 호출한 경우, 일반 함수로 동작한다는 점&lt;/b&gt;을 다시 한번 되새기자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Function.prototype.apply/call/bind&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;apply,call,bind&lt;/b&gt;&lt;/span&gt; 메서드를 설명하고자 할 때, 계속 Function.prototype의 메서드임을 붙여주고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 의미는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;모든 함수는 위 3가지 메서드를 호출할 수 있다는 것&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://koocci-dev.tistory.com/62?category=1030064&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;모든 함수 리터럴은 Function을 생성자(constructor)로 가지기 때문&lt;/a&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 해당 메서드들의 사용법을 보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Function/apply&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;apply&lt;/a&gt; 와 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Function/call&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;call&lt;/a&gt;은 다음과 같이 설명된다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;i&gt;@thisArg : this로 사용할 객체&lt;/i&gt;&lt;br /&gt;&lt;i&gt;@argsArray : 함수에게 전달할 인수 리스트의 배열 또는 유사 배열 객체&lt;/i&gt;&lt;br /&gt;&lt;i&gt;@return : 호출된 함수의 반환값&lt;/i&gt;&lt;br /&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;
&lt;pre class=&quot;autoit&quot;&gt;&lt;code&gt;func.apply(thisArg, [argsArray])&lt;/code&gt;&lt;/pre&gt;
&lt;b&gt;&lt;b&gt;&lt;br /&gt;&lt;b&gt;&lt;i&gt;@thisArg : this로 사용할 객체&lt;/i&gt;&lt;br /&gt;&lt;i&gt;@argsArray : 함수에게 전달할 인수 리스트&lt;/i&gt;&lt;br /&gt;&lt;i&gt;@return : 호출된 함수의 반환값&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/b&gt;
&lt;pre class=&quot;autoit&quot;&gt;&lt;code&gt;func.call(thisArg[, arg1[, arg2[, ...]]])&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;pre id=&quot;code_1659457625693&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function getThisBinding() {
  console.log(arguments);
  return this;
}

// this로 사용할 객체
const thisArg = {a: 1};
console.log(getThisBinding()); // window

console.log(getThisBinding.apply(thisArg, [1,2,3])); // {a:1}
console.log(getThisBinding.call(thisArg,1,2,3)); // {a:1}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;apply&lt;/b&gt;&lt;/span&gt;와 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;call&lt;/b&gt;&lt;/span&gt;은 둘다 기본적으로 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;함수를 호출&lt;/b&gt;&lt;/span&gt;하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 때, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;특정 객체를 this로 바인딩&lt;/b&gt;&lt;/span&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Function/bind&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;bind&lt;/a&gt;는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;this로 사용할 객체&lt;/b&gt;&lt;/span&gt;만 전달한다.&lt;/p&gt;
&lt;pre id=&quot;code_1659458679112&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function getThisBinding() {
  return this;
}

// this로 사용할 객체
const thisArg = {a: 1};

// 함수를 호출하지는 않고, this로 사용할 객체만 전달한다.
console.log(getThisBinding.bind(thisArg)); // getThisBinding
// 명시적으로 호출이 필요하다.
console.log(getThisBinding.bind(thisArg)()); // {a:1}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;bind 메서드는 흔히 앞서 알아봤던&amp;nbsp;&lt;b&gt;중첩 함수 혹은 콜백 함수의 this가 다른 문제&lt;/b&gt;를 해결할 때 사용된다.&lt;/p&gt;
&lt;pre id=&quot;code_1659458804437&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var value = 1;
const obj = {
  value: 100,
  foo() {
    setTimeout(function() {
      console.log(&quot;callback`s this: &quot;, this);
    }.bind(this), 100);
  }
}
obj.foo();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 this와 that으로 처리했던 함수를 위와 같이 처리하니 훨씬 깔끔해졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Wrap Up&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트에서 this를 정리해보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;this는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;함수 호출 시점&lt;/b&gt;&lt;/span&gt;에 따라 동적으로 할당되며, 그 종류는 &lt;b&gt;일반 함수, 메서드, 생성자 함수, Function.prototype.call/apply/bind&lt;/b&gt;가 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 차이점들을 잘 정리해보도록 하자.&lt;/p&gt;</description>
      <category>Programming/javascript</category>
      <category>JavaScript</category>
      <category>This</category>
      <category>자바스크립트</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/66</guid>
      <comments>https://koocci-dev.tistory.com/66#entry66comment</comments>
      <pubDate>Wed, 3 Aug 2022 01:49:19 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] Classpath와 Component가 뭘까?</title>
      <link>https://koocci-dev.tistory.com/65</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : 스프링의 Classpath와 Component를 설명할 수 있다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 진행하고 있는 &lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-classpath-scanning&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;문서의 위치는 다음과 같다.&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조금 생소하다면 생소하고, 많이 봤으면서도 설명하기 어려웠던 개념이 나오기에, 잘 정리하도록 해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Classpath&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Classpath&lt;/b&gt;&lt;/span&gt;가 무엇인지 부터 알도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;java는 빌드 후에 실행파일이 나오게 된다. (javac 로 컴파일 이후에 Java Byte Code인(JVM이 이해할 수 있는 언어) .class 파일이 나오는 것 정도는 알아야 한다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Classpath&lt;/b&gt;&lt;/span&gt;는 이 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;컴파일된 파일의 경로&lt;/b&gt;&lt;/span&gt;를 가리키게 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;206&quot; data-origin-height=&quot;131&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjTE2y/btrII2t79wk/lHNpF3MCKcxtumJK5KkVi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjTE2y/btrII2t79wk/lHNpF3MCKcxtumJK5KkVi0/img.png&quot; data-alt=&quot;classes 폴더&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjTE2y/btrII2t79wk/lHNpF3MCKcxtumJK5KkVi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjTE2y%2FbtrII2t79wk%2FlHNpF3MCKcxtumJK5KkVi0%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;206&quot; height=&quot;131&quot; data-origin-width=&quot;206&quot; data-origin-height=&quot;131&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;classes 폴더&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 흔히, Spring을 빌드하고 나면, target 폴더에 결과물이 남는데, 이 때 classes 폴더가 바로 해당 파일의 경로가 될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Classpath Scanning&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://koocci-dev.tistory.com/64?category=1012333&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이전 포스팅&lt;/a&gt;에서는 Annotation기반으로 소스코드 상에서 Metadata를 제공하는 방법을 알아보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼에도 사실 이전까지 bean에 대한 기본적인 정의는 XML을 통해 제공해 주입시켜 주어야만 했다. (Autowired를 한다고 해도, Bean이 XML에 정의가 되어야 가능했다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이제 자연스럽게 &lt;b&gt;어떻게 Bean들을 소스코드 상에서 넣어줄 수 있을지가 궁금해진다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 방법이 바로 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Classpath Scanning&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java에서는 Classpath 경로 이후의 클래스 파일, 리소스 파일들을 읽을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Classpath 경로 이후의 관리할 Bean을 @Component Annotation을 통해 Scanning할 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://koocci-dev.tistory.com/64?category=1012333&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;앞서,&lt;/a&gt; 명시적으로 Bean을 XML에 등록해야했고, @Bean Annotation을 method에 주입해서 사용했는데, 그게 아니라, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Class Level에 &lt;span style=&quot;color: #ee2323;&quot;&gt;@Component&lt;/span&gt;라는 Annotation을 넣어주면서, Bean으로 넣어주라는 명령을 할 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;@Component&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/stereotype/Component.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;@Component&lt;/a&gt;를 주의깊게 들여다 보자.&lt;/p&gt;
&lt;pre class=&quot;less&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component { ... }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 Runtime에 동작한다는 점이 눈에 띄며, Indexed라는 Annotation도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 그 설명이 다음과 같다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Indicates that an annotated class is a &quot;component&quot;. Such classes are considered as candidates for auto-detection when using annotation-based configuration and classpath scanning.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주석이 달린 class가 Component임을 나타낸다. 또한 annotation으로 configuration 되고 자동 detecting되어 classpath scanning이 된다는 내용이 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Marker Interface&lt;/b&gt;&lt;/span&gt;로 &lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/stereotype/Repository.html&quot;&gt;Repository&lt;/a&gt;&lt;span style=&quot;background-color: #ffffff; color: #353833;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/stereotype/Service.html&quot;&gt;Service&lt;/a&gt;&lt;span style=&quot;background-color: #ffffff; color: #353833;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/stereotype/Controller.html&quot;&gt;Controller&lt;/a&gt;&lt;span style=&quot;background-color: #ffffff; color: #353833;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/ClassPathBeanDefinitionScanner.html&quot;&gt;ClassPathBeanDefinitionScanner&lt;/a&gt; 들이 있음을 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;@Retention&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #6d7376;&quot;&gt;어노테이션의 지속시간을 의미한다. RUNTIME은 RUNTIME 시 계속 지속된다는 것(.class에 존재)을 말하며,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #666666;&quot;&gt;SOURCE 는 Compile 시에만 있으며, Byte Code에는 버려지고, CLASS는 class load때 버려지며 bytecode-level post-processing 때 유용하게 사용되는 기본값이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;@Indexed&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 스프링의 스테레오타입임을 나타낸다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;280&quot; data-origin-height=&quot;439&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cz89gW/btrIEZdW0Ai/SqL7khOoimNNQWKNZSKsyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cz89gW/btrIEZdW0Ai/SqL7khOoimNNQWKNZSKsyK/img.png&quot; data-alt=&quot;stereotype&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cz89gW/btrIEZdW0Ai/SqL7khOoimNNQWKNZSKsyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcz89gW%2FbtrIEZdW0Ai%2FSqL7khOoimNNQWKNZSKsyK%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;280&quot; height=&quot;439&quot; data-origin-width=&quot;280&quot; data-origin-height=&quot;439&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;stereotype&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Marker Interface&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #6d7376;&quot;&gt;일반적인 인터페이스와 동일하지만 사실상 아무 메소드도 선언하지 않고 의미만 전달하는 인터페이스&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@Repository&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;자동으로 Bean으로 등록될 &lt;span style=&quot;color: #ee2323;&quot;&gt;Component&lt;/span&gt;이며, DAO 처럼 DataBase에 Access 시 사용할 Bean일 때 설정한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@Service&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;자동으로 Bean으로 등록될 &lt;span style=&quot;color: #ee2323;&quot;&gt;Component&lt;/span&gt;이며, Besiness 로직을 담당하는 Bean일 때 설정한다.&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@Bean VS @Component&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;@Bean&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Annotation은 method에만 사용할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;less&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean { ... }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;그에 비해,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;@Component&lt;/b&gt;&lt;/span&gt;는 TYPE (&lt;i&gt;Class, interface (including annotation type), or enum declaration&lt;/i&gt;)이 Target으로 등록되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 둘 사이에는 사용할 수 있는 Target이 달라,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;용도가 다르다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@Component는 개발자가 직접 개발한 클래스에 쓰이게 되며, @Bean은 외부로부터 주입받아야 하지만, 직접 수정이 어려운 사항 (Configuration에서의 DataSource 등)을 주입할 때 사용하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;명시적으로 패키지명과 클래스명으로 하는 것이 아닌,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;특정 Classpath 이하에 있는 @Component로 등록된 클래스들은 bean으로 등록될 것이라고 자동 Scanning 해주는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 XML 설정 등이 줄어드는 효과를 가질 수 있다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Automatically Detecting Classes and Registering Bean Definitions&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 어떻게 자동으로 찾는 것일까? 그 절차에 대해 알아보자.&lt;/p&gt;
&lt;pre id=&quot;code_1659363677474&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Service
public class SimpleMovieLister {

    private MovieFinder movieFinder;

    public SimpleMovieLister(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1659363690135&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Repository
public class JpaMovieFinder implements MovieFinder {
    // implementation elided for clarity
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring은 자동으로 &lt;span&gt;위 2개와 같은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;스테레오타입의 클래스&lt;/b&gt;&lt;/span&gt;를 감지하고 해당 BeanDefinition 인스턴스를 ApplicationContext에 등록할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1659363712437&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
@ComponentScan(basePackages = &quot;org.example&quot;)
public class AppConfig  {
    // ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, 이런 클래스를 자동으로 감지하고 Bean을 등록하려면 @Configuration 에 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;@ComponentScan&lt;/b&gt;&lt;/span&gt;이 추가되어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때, basePackages 는 두 클래스의 공통된 상위 패키지여야 한다. (혹은 각 클래스의 상위 패키지를 쉼표, 세미콜론, 공백 등으로 구분하여 등록해야 한다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 XML로 하고 싶다면, 다음과 같이 적용할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1659364481891&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
    xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
    xmlns:context=&quot;http://www.springframework.org/schema/context&quot;
    xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd&quot;&amp;gt;

    &amp;lt;context:component-scan base-package=&quot;org.example&quot;/&amp;gt;

&amp;lt;/beans&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예시에서 annotation-config 설정이 빠진 것을 볼 수 있다.&lt;/p&gt;
&lt;pre class=&quot;crystal&quot;&gt;&lt;code&gt;&amp;lt;context:annotation-config/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 @componentScan을 설정했을 때 생략이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;AnnotationConfigApplicationContext&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에 예시를 들 때마다, ApplicationContext에 대해 다음과 같이 선언했다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;ApplicationContext context = new ClassPathXmlApplicationContext(&quot;aop.xml&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나, &lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/AnnotationConfigApplicationContext.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AnnotationConfigApplicationContext&lt;/a&gt;를 설정하면 XML을 전혀 쓰지 않을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 문서의 Constructor를 보면, &lt;b&gt;componentClass&lt;/b&gt; 혹은 &lt;b&gt;basePackage&lt;/b&gt;를 설정할 수 있음을 알 수 있다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(&quot;com.test.classpath&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Filter&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Component Scan을 할 때, Component 등록에 대한 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Filter&lt;/b&gt;&lt;/span&gt;를 적용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;크게 2 가지 종류로 나뉘어 진다.&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt; (includeFilters, excludeFilters)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Filter의 타입으로는&amp;nbsp;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;annotation, assignable, aspectj, regex, custom&lt;/b&gt;&amp;nbsp;&lt;/span&gt;이 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1659367652196&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Slf4j
@Configuration
@ComponentScan(basePackageClasses = Main.class,
excludeFilters = @Filter(type=FilterType.ASSIGNABLE_TYPE, classes = Test.class))
public class AppConfig {
    ConfigurableApplicationContext context = new AnnotationCOnfigApplicationContext(Main.class);
    Test test = context.getBean(Test.class);
    log.info(&quot;&quot; + test);
    context.close();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 설정한다면, 에러메세지가 나올 것이다.&amp;nbsp; Test라는&amp;nbsp; Bean이 exclude 되었기 때문이다.&lt;/p&gt;
&lt;pre id=&quot;code_1659368007860&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Slf4j
@Configuration
@ComponentScan(basePackageClasses = Main.class,
excludeFilters = @Filter(type=FilterType.REGEX, pattern = &quot;com.test.Test&quot;))
public class AppConfig {
    ConfigurableApplicationContext context = new AnnotationCOnfigApplicationContext(Main.class);
    Test test = context.getBean(Test.class);
    log.info(&quot;&quot; + test);
    context.close();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 REGEX를 사용했고, 역시 동일하게 에러가 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;includeFilters도 사용법은 동일하니 알아두도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Wrap Up&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;꽤 중요한 내용들을 다룬 것으로 보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Annotation의 활용을 조금씩 깨우치면서 왜 이런 내용을 정리하고 있는지 생각해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;난 우선, &lt;a href=&quot;https://koocci-dev.tistory.com/57?category=1012333&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Spring이 무엇인지&lt;/a&gt;, &lt;a href=&quot;https://koocci-dev.tistory.com/58?category=1012333&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;IoC Container가 무엇인지&lt;/a&gt;, &lt;a href=&quot;https://koocci-dev.tistory.com/59?category=1012333&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Bean이 무엇인지&lt;/a&gt;, &lt;a href=&quot;https://koocci-dev.tistory.com/60?category=1012333&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DI가 무엇인지&lt;/a&gt;, 그리고 나아가서 &lt;a href=&quot;https://koocci-dev.tistory.com/61?category=1012333&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Bean의 Scope&lt;/a&gt; 나 &lt;a href=&quot;https://koocci-dev.tistory.com/63?category=1012333&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;LifeCycle을 정리&lt;/a&gt;하고 &lt;a href=&quot;https://koocci-dev.tistory.com/64?category=1012333&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Annotation Configuration&lt;/a&gt;까지 정리하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;점진적으로 제일 처음 알아보고자 했던 2가지에 가까워지고 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;스프링은 무엇을 도와주는가?&lt;/li&gt;
&lt;li&gt;스프링의 사용법은 어떻게 되는가?&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Annotation을 정리하는 것은 스프링의 사용법이며, 확실히 이해하고 쓰기 위함의 준비 과정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;XML로 정리하던 구축방법에서 Annotation으로 설정하는 방법까지 넘어왔으며, Spring이 Annotation으로 선언된 Component들을(Bean들을) Scanning 한다는 것을 알 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직 갈길이 멀고, AOP 와 같은 관점의 정리도 필요할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;차근히 하나씩 진행해보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Framework/Spring</category>
      <category>annotation</category>
      <category>classpath</category>
      <category>Component</category>
      <category>spring</category>
      <category>Spring Core</category>
      <category>스프링</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/65</guid>
      <comments>https://koocci-dev.tistory.com/65#entry65comment</comments>
      <pubDate>Tue, 2 Aug 2022 00:05:53 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] Annotation Configuration은 어떻게 할까?</title>
      <link>https://koocci-dev.tistory.com/64</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : Spring의 Anntation 설정을 할 수 있다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이번엔 계속 XML에서 설정해온 Configuration 정보들을 Annotation으로 어떻게 할 수 있을지 알아볼 예정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-annotation-config&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;해당 링크&lt;/a&gt;를 중심으로 하나씩 알아가 보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Annotation-based Container Configuration&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 &lt;b&gt;Annotation이 XML보다 Spring configuration하는 것에 있어서 더 좋은가?&lt;/b&gt; 에 대한 질문으로 시작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;답은 역시나 &lt;b&gt;&quot;상황에 따라 다르다&quot;&lt;/b&gt; 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;XML 방식은 소스 코드 외, XML만 보고도 설정을 알 수 있다. 즉, &lt;b&gt;설정과 소스 코드의 분리가 가능&lt;/b&gt;하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나, 프로젝트가 커질수록 &lt;b&gt;XML 관리가 복잡해지기 시작한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Annotation은 &lt;span style=&quot;color: #252525;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;더 짧고 간결한 구성이 가능하지만 &lt;/b&gt;&lt;/span&gt;&lt;b&gt;소스 코드와 설정의 분리가 애매&lt;/b&gt;해진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;context namespace&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1659274784095&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
    xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
    xmlns:context=&quot;http://www.springframework.org/schema/context&quot;
    xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd&quot;&amp;gt;

    &amp;lt;context:annotation-config/&amp;gt;

&amp;lt;/beans&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;context라는 namespace를 넣어준 것에 집중하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, &lt;span style=&quot;background-color: #ffffff; color: #222222;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #222222;&quot;&gt;&amp;lt;&lt;span style=&quot;color: #000088;&quot;&gt;context:annotation-config&lt;/span&gt;/&amp;gt; 를 적용하며, 이제 Annotation을 통해 설정할 수 있도록 변경되었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #222222;&quot;&gt;@Autowired&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #222222;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Autowired&lt;/b&gt;&lt;/span&gt;는 Bean과 Bean간의 관계에 대해, Spring Container가 자동으로 연결해주는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #222222;&quot;&gt;그 때, Bean의 이름, Bean의 Type등으로 관계를 설정할 수 있다.&lt;/span&gt;&lt;span style=&quot;color: #222222;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1659274977590&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class MovieRecommender {

    private final CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
        this.customerPreferenceDao = customerPreferenceDao;
    }

    // ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 예시를 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MovieRecommender의 생성자에 Autowired Annotation을 사용하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CustomerPreferenceDao와 관계를 설정해준 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 이전 XML 문법의 다음과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1659275080491&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;bean id=&quot;customerPreferenceDao&quot; class=&quot;kr.co.test.CustomerPreferenceDao&quot;/&amp;gt;
  
&amp;lt;bean id=&quot;movieRecommender&quot; class=&quot;kr.co.test.MovieRecommender&quot;&amp;gt;
    &amp;lt;constructor-arg ref=&quot;customerPreferenceDao&quot; /&amp;gt;
&amp;lt;/bean&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, Spring 버전이 올라가면서, 생성자 주입 시, 자동 Autowired 가 될 수 있고, 필드에 쓰는 경우도 많다.&lt;/p&gt;
&lt;pre id=&quot;code_1659275861975&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class MovieRecommender { 
	private final CustomerPreferenceDao customerPreferenceDao;
    // Autowired 생략 가능
	public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
		this.customerPreferenceDao = customerPreferenceDao;
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1659276055645&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@RequiredArgsConstructor // Lombok 활용
public class MovieRecommender { 
    private final CustomerPreferenceDao customerPreferenceDao;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1659276095187&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class MovieRecommender { 
    @Autowired // 필드에 설정 가능
    private final CustomerPreferenceDao customerPreferenceDao;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@Primary&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Autowired를 할 때, 이름 혹은 타입 등으로 설정할 수 있는데, 그 중, &lt;b&gt;타입으로 연결했더니 중복인 경우, 어떤 것을 Autowired를 할지 모를 경우가 있다. 그 때 활용할 수 있는 Annotation&lt;/b&gt;이다.&lt;/p&gt;
&lt;pre id=&quot;code_1659276519328&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
public class MovieConfiguration {

    @Bean
    @Primary
    public MovieCatalog firstMovieCatalog() { ... }

    @Bean
    public MovieCatalog secondMovieCatalog() { ... }

    // ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;@Configuration&lt;/b&gt; &lt;/span&gt;: Bean 설정으로 등록되면서, Spring 설정과 관련있는 Bean이라는 것을 알려주는 Annotation&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;@Bean&lt;/b&gt;&lt;/span&gt; : XML에서 Bean 설정하는 것 대신, Java Annotation을 통해 Bean 설정할 수 있게 도와주는 Annotation&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예시를 보았을 때, &lt;b&gt;@Primary가 없다고 가정하면 에러가 나오게 된다.&lt;/b&gt; (No Unique Bean)&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 id=&quot;beans-autowired-annotation-qualifiers&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@Qualifiers&amp;nbsp;&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1659354633785&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class MovieRecommender {

    private MovieCatalog movieCatalog;

    private CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    public void prepare(@Qualifier(&quot;main&quot;) MovieCatalog movieCatalog,
            CustomerPreferenceDao customerPreferenceDao) {
        this.movieCatalog = movieCatalog;
        this.customerPreferenceDao = customerPreferenceDao;
    }

    // ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1659354554476&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
    xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
    xmlns:context=&quot;http://www.springframework.org/schema/context&quot;
    xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd&quot;&amp;gt;

    &amp;lt;context:annotation-config/&amp;gt;

    &amp;lt;bean class=&quot;example.SimpleMovieCatalog&quot;&amp;gt;
        &amp;lt;qualifier value=&quot;main&quot;/&amp;gt; 

        &amp;lt;!-- inject any dependencies required by this bean --&amp;gt;
    &amp;lt;/bean&amp;gt;

    &amp;lt;bean class=&quot;example.SimpleMovieCatalog&quot;&amp;gt;
        &amp;lt;qualifier value=&quot;action&quot;/&amp;gt; 

        &amp;lt;!-- inject any dependencies required by this bean --&amp;gt;
    &amp;lt;/bean&amp;gt;

    &amp;lt;bean id=&quot;movieRecommender&quot; class=&quot;example.MovieRecommender&quot;/&amp;gt;

&amp;lt;/beans&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 타입의 Bean을 만들 때, Quialifier는 Autowired 시, Qualifier 라는 Annotation과 Value를 넣으면, 선택하여 실행시킬 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@Resource&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@Autowired와 같은 역할을 한다고 보면된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;약간의 차이는 Bean의 이름을 통해 주입하며, 생성자에 적용할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@Value&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 Application에서 XML 외에 application.properties 라는 파일을 만들어, property를 읽어들인다.&lt;/p&gt;
&lt;pre id=&quot;code_1659355104742&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
@PropertySource(&quot;classpath:application.properties&quot;)
public class AppConfig { }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이, Property를 연결하는 구문을 만들고, application.properties를 만들어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, Key=Value 형태로 값을 저장하면, 해당 값을 가져와 쓸 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;beans-postconstruct-and-predestroy-annotations&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@PostConstruct, @PreDestroy&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LifeCycle과 관련된 Annotation이다.&lt;/p&gt;
&lt;p id=&quot;beans-postconstruct-and-predestroy-annotations&quot; data-ke-size=&quot;size16&quot;&gt;@PostConstruct 는 Bean이 생성되기 전에 실행되는 함수이다.&lt;/p&gt;
&lt;p id=&quot;beans-postconstruct-and-predestroy-annotations&quot; data-ke-size=&quot;size16&quot;&gt;@PreDestroy는 Bean의 소멸을 앞두고 실행되는 함수이다. &lt;b&gt;단, context.close()가 필요하다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;WrapUp&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Annotation이라는 것이 사용자의 편의를 생각해, 만들어지다보니 암기해야할 것처럼 느껴질 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, 사용을 하다보면 자연스럽게 알게되고, 자주 쓰다보면 당연스레 써지게 되기도 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, 이 Annotation의 역할과 상황을 잘 기억하여 쓸 수 있도록 하자.&lt;/p&gt;</description>
      <category>Framework/Spring</category>
      <category>annotation</category>
      <category>spring</category>
      <category>springMVC</category>
      <category>스프링</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/64</guid>
      <comments>https://koocci-dev.tistory.com/64#entry64comment</comments>
      <pubDate>Mon, 1 Aug 2022 21:09:38 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] Bean의 LifeCycle는 어떻게 될까?</title>
      <link>https://koocci-dev.tistory.com/63</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : Spring에서 Bean의 LifeCycle에 대해 설명할 수 있다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Bean에도 LifeCycle이 있을 것이고, 그에 따라 여러 설정값들도 있을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그에 대해 알아보면서, 결국 서블릿 컨테이너를 통해 서블릿이 관리되고, 하나의 서블릿에서 Application Context가 관리하는 Bean들이 실행되는 전체적인 관점도 알아보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Customizing the Nature of a Bean&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-factory-nature&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;계속 참고하여 보던 문서&lt;/a&gt;의 제목이며, Bean의 성질이 어떻게 되는지 보고, 수정할 수 있는 방향을 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 LifeCycle에 대해 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;LifeCycle&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring에서는 객체를 다루므로, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;객체를 만들거나 객체를 없애는 행위&lt;/b&gt;&lt;/span&gt;를 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체를 만들 때는 new로 객체를 만드는 작업을 Spring이 한다. 즉, 해당 시점에 Callback을 호출 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 특정 Bean에 대해 Close, 자원 Release할 때도 Callback을 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떻게 할 수 있는지에 대해서는 크게 3가지 방법을 설명한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;InitializingBean,DisposableBean이라는 인터페이스를 구현하는 방법&lt;/li&gt;
&lt;li&gt;JSR-250의 @PostConstruct 및 @PreDestroy를 사용하는 방법&lt;/li&gt;
&lt;li&gt;XML 설정을 통해, init-method, destroy-method를 하는 방법&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어노테이션을 활용하는 것은 다음에 진행할 예정이므로, 2번을 제외한 다른 것들부터 보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Initialization Callbacks&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Bean이 만들어질 때, CallBack 함수가 실행되는 것들을 알아보자.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;InitializingBean&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/InitializingBean.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;InitializingBean&lt;/a&gt; 을 보면, 하나의 메서드를 지원하고 있다. (afterPropertiesSet())&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 메서드의 역할도 함께 적혀있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Invoked by the containing BeanFactory after it has set all bean properties and satisfied BeanFactoryAware, ApplicationContextAware etc.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;모든 bean Property 설정과 BeanFactoryAware, ApplicationContextAware 등이 &lt;span style=&quot;color: #ee2323;&quot;&gt;끝난 후에,&lt;/span&gt; container인 BeanFactory에 의해 호출된다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;init-method&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;XML로 설정하는 방법이다.&lt;/p&gt;
&lt;pre id=&quot;code_1659187630280&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;bean id=&quot;exampleInitBean&quot; class=&quot;examples.ExampleBean&quot; init-method=&quot;init&quot;/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;init-method 이름이 init이니, 해당 init 이란 이름의 메서드를 만들어 활용하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Destruction Callbacks&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Bean이 사라질 때의 Callback을 알아보자.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;DisposableBean&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;InitailizingBean과 반대되는 개념이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 역시, &lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/DisposableBean.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;문서&lt;/a&gt;를 보면 destroy() 메서드 한가지만 구현할 수 있게 되어있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;bean에 대해, Interface를 구현하여 사용하면 되지만, 한가지 문제가 생길 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1659189800351&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ApplicationContext context = new ClassPathXmlApplicationContext(&quot;test.xml&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ClassPathXmlApplicationContext는 정말 많은 추상클래스, 인터페이스들을 상속받고 있는데, 실제로 Assign한 타입은 ApplicationContext이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시말해, &lt;a href=&quot;https://koocci-dev.tistory.com/32?category=1012334&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Java에서의 형변환 업캐스팅&lt;/a&gt;으로&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt; &lt;b&gt;ClassPathXmlApplicationContext&lt;/b&gt;&lt;/span&gt;&lt;b&gt;의 &lt;span style=&quot;color: #006dd7;&quot;&gt;모든 멤버 변수에 대한 메모리는 생성&lt;/span&gt;되지만, 변수 타입이 &lt;span style=&quot;color: #ee2323;&quot;&gt;ApplicationContext&lt;/span&gt;이므로 실제로 접근 가능한 변수나 메서드는&lt;span style=&quot;color: #006dd7;&quot;&gt;ApplicationContext의 변수와 메서드&lt;/span&gt;가 된다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ClassPathXmlApplicationContext 에서는 결국 ConfigurableApplicationContext 라는 Interface를 상속받고 있고, ConfigurableApplicationContext는 ApplicationContext, Lifecycle, Closeable 을 구현하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이중 중요한 것은 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Closeable&lt;/b&gt;&lt;/span&gt; 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ApplicationContext 에는 Closeable이 없기 때문에, Close 함수가 호출될 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;DisposableBean을 상속받아 destroy 메서드를 구현하더라도,&lt;span style=&quot;color: #ee2323;&quot;&gt; 해당 메서드가 호출될 수 없다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, 다음과 같이 구현해야 정상적으로 destroy 메서드가 호출되는 것을 볼 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1659190465419&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; ConfigurableApplicationContext context = new ClassPathXmlApplicationContext(&quot;test.xml&quot;);
 
 /**
 * TODO :
 */
 
 context.close();&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Destroy-method&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;XML로 설정하는 방법이며 사용법은 동일하다.&lt;/p&gt;
&lt;pre id=&quot;code_1659193225309&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;bean id=&quot;exampleInitBean&quot; class=&quot;examples.ExampleBean&quot; destroy-method=&quot;cleanup&quot;/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Default Initialization and Destroy Methods&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매번 Bean들에게 init이나 destroy 메서드를 할 필요 없이, beans에 default 설정을 할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1659193678108&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;beans default-init-method=&quot;init&quot; default-destroy-method=&quot;destroy&quot;&amp;gt;

    &amp;lt;bean id=&quot;blogService&quot; class=&quot;com.something.DefaultBlogService&quot;&amp;gt;
        &amp;lt;property name=&quot;blogDao&quot; ref=&quot;blogDao&quot; /&amp;gt;
    &amp;lt;/bean&amp;gt;

&amp;lt;/beans&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 각 bean들에게서 init이나 destroy 메서드가 있다면, 각각의 bean들에서 생성/삭제될 때, 해당 메서드들이 실행되는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Startup and Shutdown Callbacks&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서, &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;DisposableBean&lt;/span&gt; 을 찾아볼 때, &amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;ConfigurableApplicationContext&lt;/span&gt;에 대해 찾아보았다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1659194005561&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
    /*...*/
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Lifecycle&lt;/b&gt;&lt;/span&gt;이라는 Interface가 있는 것을 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, 우리가 context에서 해당 Lifecycle.class를 getBean으로 가져올 수 있고, 이를 사용할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1659194423016&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface Lifecycle {
    void start();

    void stop();

    boolean isRunning();
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1659194608205&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static void main(String[] args) {
    ApplicationContext context = new ClassPathXmlApplicationContext(&quot;test.xml&quot;);
    Lifecycle lifecycle = context.getBean(Lifecycle.class);
    log.info(&quot;isRunning : &amp;gt;&amp;gt; &quot; + lifecycle.isRunning()); // isRunning : &amp;gt;&amp;gt; true
    context.close();
    log.info(&quot;isRunning : &amp;gt;&amp;gt; &quot; + lifecycle.isRunning()); // isRunning : &amp;gt;&amp;gt; false
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 Interface를 통해, Spring Container의 Running 유무에 따른 설정에 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;beans-factory-aware&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;ApplicationContextAware&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 앞서, ClassPathXmlApplicationContext 라는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;ApplicationContext&lt;/b&gt;&lt;/span&gt;를 사용하고 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&amp;nbsp;Bean에서 사용하고 싶을 때&lt;/span&gt;, ApplicationContextAware가 사용된다&lt;/b&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 예시를 보자.&lt;/p&gt;
&lt;pre id=&quot;code_1659195127182&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Slf4j
public class Aca implements ApplicationContextAware {
    private ApplicationContext applicationContext;
    
    void init() {
      log.info(&quot;Null Check &amp;gt;&amp;gt; &quot; + applicationContext);  
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Aca라는 클래스는 ApplicationContextAware를 구현하고 있고, init 메서드를 통해, Bean 시작점에 자동으로 실행될 메서드도 구현하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ApplicationContextAware 인터페이스는 setApplicationContext 를 구현하도록 되어 있고, 간단히 필드의 ApplicationContext에 값을 넣어주도록 하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 함으로서, Aca를 Bean으로 등록만 한다면, 자동으로 Bean이 생성될 때, init 메서드가 실행될 것이고, Aca에서는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;applicationContext 를 set으로 전달받아 사용할 수 있는 상태&lt;/b&gt;&lt;/span&gt;가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;ApplicationContextAware&lt;/b&gt;&lt;/span&gt;를 사용하는 방법을 알아보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Aware라는 단어로 붙은 인터페이스들은 &lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aware-list&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;다음과 같이,&lt;/a&gt; 특정 목적에 따라 사용하는 방법이 위 ApplicationContextAware와 유사하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 잘 알아보고 사용하도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Wrap Up&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 Spring 내에서 Bean의 LifeCycle을 알아보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빠진 내용은 아마 Annotation일 것이고, 이건 다시 한 번 정리해 나가도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, &lt;a href=&quot;https://koocci-dev.tistory.com/57?category=1012333&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;앞서 Servlet을 알아보며&lt;/a&gt; 여러 자료를 찾게 되다가, 제목이 &lt;a href=&quot;https://jeong-pro.tistory.com/204&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Coltoller 1개가 어떻게 수 많은 Request를 처리하는가?&lt;/a&gt; 라는 블로그를 보자마자 나도 순간 헤깔리게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Bean이 생성되고 삭제될 때, 기본적으로 Singleton으로 객체가 이루어진다. (&lt;a href=&quot;https://koocci-dev.tistory.com/61?category=1012333&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Default Bean Scope&lt;/a&gt;다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 Servlet은 이 Bean들을 통해 구현되어지고, Servlet은 Servlet Container 를 통해 관리되어 진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면, 하나의 Servlet이 하나의 Path에 대한 Client Request를 처리한다고 할 때 (DispatcherServlet이더라도), 결국 하나의 Bean Instance를 사용하는 것이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;논리적으로 요청이 동시에 천이든 만이든 큰 단위로 들어올 수 있는데, 그럼 해당 path로 전달받는 Request는 Servlet Container의 Thread 갯수만큼 받는다고 해도, Controller를 담당하는 Servlet이 같은 Bean Instance를 바라보면 데이터가 섞이거나, 문제가 생기지 않을까?&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과부터 보면, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Controller 를 담당하는 Bean은 한 개가 생성되며, 그 하나의 컨트롤러가 모든 요청을 처리한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어찌보면 당연하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Controller의 로직은 함께 쓸 수 있지만, 각 요청과 개별적인 Thread의 정보는 동기화될 필요가 없다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Bean은 Stateless해야 하며, &lt;a href=&quot;https://beyondj2ee.wordpress.com/2013/02/28/%EB%A9%80%ED%8B%B0-%EC%93%B0%EB%A0%88%EB%93%9C-%ED%99%98%EA%B2%BD%EC%97%90%EC%84%9C-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B9%88-%EC%A3%BC%EC%9D%98%EC%82%AC%ED%95%AD/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;멤버변수에 값을 저장하는 행위가 위험한 이유&lt;/a&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멤버변수에 값을 저장하는 순간, 정보는 동기화가 되어버릴 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring Bean의 LifeCycle과 함께 헤깔리지 않도록 잘 정리해두자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Framework/Spring</category>
      <category>Bean</category>
      <category>lifecycle</category>
      <category>spring</category>
      <category>빈</category>
      <category>생명주기</category>
      <category>스프링</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/63</guid>
      <comments>https://koocci-dev.tistory.com/63#entry63comment</comments>
      <pubDate>Sun, 31 Jul 2022 20:34:50 +0900</pubDate>
    </item>
    <item>
      <title>자바스크립트 기초부터 모던 자바스크립트까지 - 프로토타입편</title>
      <link>https://koocci-dev.tistory.com/62</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : 자바스크립트의 프로토타입을 설명할 수 있다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 계속해서 나오던 내용이 프로토타입이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;__proto__ 접근자 프로퍼티나, prototype 프로퍼티를 다루기도 했고, 이제 프로토타입에 대해 정확히 알아가볼 시간이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;b&gt;자바스크립트는 어떤 언어인가?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트는 멀티 패러다임 언어다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시말해, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;명령형, 함수형, &lt;span style=&quot;color: #ee2323;&quot;&gt;프로토타입 기반 객체지향 프로그래밍&lt;/span&gt;을 지원하는 멀티 패러다임 프로그래밍 언어&lt;/b&gt;&lt;/span&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 보자. 자바스크립트는 프로토타입을 기반으로 한 객체 지향 프로그래밍 언어다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;객체 기반의 프로그래밍 언어&lt;/b&gt;&lt;/span&gt;로 자바스크립트를 이루고 있는 거의 모든 것이 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;객체&lt;/b&gt;&lt;/span&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 다시 &lt;a href=&quot;https://koocci-dev.tistory.com/42&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;객체&lt;/a&gt;로 돌아온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이 객체로 상속과 프로토타입에 대해 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;상속과 프로토타입&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;상속&lt;/b&gt;&lt;/span&gt;은 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;어떤 객체의 프로퍼티 또는 메서드를 다른 객체가 상속받아 그대로 사용할 수 있는 것&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트에서는 상속을 프로토타입 기반으로 구현하여, 코드를 재사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1659022757366&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 생성자 함수
function Circle(radius) {
    this.radius = radius;
    this.getDiameter = function() {
    	return 2 * this.radius;
    };
}

const circle1 = new Circle(5);
const circle2 = new Circle(7);

console.log(circle1.getDiameter); // &amp;fnof; () { return 2 * this.radius;}
console.log(circle1.getDiameter); // &amp;fnof; () { return 2 * this.radius;}

console.log(circle1.getDiameter === circle2.getDiameter); // false&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 &lt;a href=&quot;https://koocci-dev.tistory.com/56?category=1030064&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;생성자 함수&lt;/a&gt;에서 살펴보았듯이, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;생성자 함수&lt;/b&gt;&lt;/span&gt;는 &lt;b&gt;동일한 프로퍼티나 메서드 구조를 갖는 객체를 여러 개 생성할 때 유용&lt;/b&gt;하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데, 위 예시는 좀 아쉬운 것이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;getDiameter 메서드는 단 하나만 생성해서 모든 인스턴스가 공유할 때 가장 바람직해 보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나, 생성자 함수로 인스턴스가 생성될 때마다, 중복생성하고 중복 소유하는 형태다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1659023009239&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 생성자 함수
function Circle(radius) {
    this.radius = radius;
}

Circle.prototype.getDiameter = function() {
    return 2 * this.radius;
};

const circle1 = new Circle(5);
const circle2 = new Circle(7);

console.log(circle1.getDiameter); // &amp;fnof; () { return 2 * this.radius;}
console.log(circle1.getDiameter); // &amp;fnof; () { return 2 * this.radius;}

console.log(circle1.getDiameter === circle2.getDiameter); // true&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Circle 생성자 함수에 prototype 이라는 데이터 프로퍼티에 메서드로 getDiameter를 할당하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성자 함수에 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;prototype&lt;/b&gt;&lt;/span&gt;은 &lt;a href=&quot;https://koocci-dev.tistory.com/56?category=1030064&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;앞서 알아본 바와 같이&lt;/a&gt;, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;생성자 함수로 호출 할 수 있는 함수 객체&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #555555;&quot;&gt;. 즉,&lt;/span&gt;&lt;span style=&quot;color: #555555;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;constructor 만이 소유하는 프로퍼티&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #555555;&quot;&gt;다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;그리고, &lt;b&gt;함수가 객체를 생성하는 생성자 함수로 호출될 때, &lt;span style=&quot;color: #ee2323;&quot;&gt;생성자 함수가 생성할 인스턴스의 프로토타입 객체&lt;/span&gt;를 가리킨다.&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #555555;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;따라서, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Circle 생성자 함수가 생성하는 모든 인스턴스는 getDiameter라는 메서드를 상속받아 사용할 수 있게 된다.&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #555555;&quot;&gt;프로토타입 객체&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;프로토타입 객체(= 프로토타입)&lt;/b&gt;&lt;/span&gt;는 객체 지향 프로그래밍의 근간을 이루는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;객체 간 상속&lt;/b&gt;&lt;/span&gt;을 구현하기 위해 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;어떤 객체의 상위(부모) 객체의 역할을 하는 객체&lt;/b&gt;&lt;/span&gt;로서 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;다른 객체에 공유 프로퍼티(또는 메서드)를 제공&lt;/b&gt;&lt;/span&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로토타입을 상속받은 하위 객체는 상위 객체의 프로퍼티를 자신의 프로퍼티처럼 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조금 더 세부적으로 들어가보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;[[Prototype]]&lt;/b&gt;&lt;/span&gt;이라는 내부 슬롯이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 내부 슬롯의 값은 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;프로토타입 참조&lt;/b&gt;&lt;/span&gt;(null일수도 있다)다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[[Prototype]]에 저장되는 프로토타입은 객체 생성 방식에 의해 결정된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;객체가 생성될 때 객체 생성 방식에 따라 프로토타입이 결정된다. 그리고 그 프로토타입의 참조값은 [[Prototype]]에 저장된다&lt;/b&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체 리터럴로 하나의 객체가 생성될 것이라고 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 객체의 프로토타입은 객체 생성 방식에 따라, Object.prototype이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성자 함수에 의해 생성된 객체가 있다고 하자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 객체의 프로토타입은 객체 생성 방식에 따라, 생성자 함수의 prototype 프로퍼티에 바인딩되어 있는 객체다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;모든 객체&lt;/b&gt;&lt;/span&gt;는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;하나의 프로토타입&lt;/b&gt;&lt;/span&gt;을 갖는다. 그리고 &lt;b&gt;모든 프로토타입은 생성자 함수와 연결되어 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1598&quot; data-origin-height=&quot;679&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cprEIF/btrIoCi3SNT/4YBx1fEFMoTaK67dXmH8L1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cprEIF/btrIoCi3SNT/4YBx1fEFMoTaK67dXmH8L1/img.png&quot; data-alt=&quot;객체와 생성자함수와 프로토타입의 관계&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cprEIF/btrIoCi3SNT/4YBx1fEFMoTaK67dXmH8L1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcprEIF%2FbtrIoCi3SNT%2F4YBx1fEFMoTaK67dXmH8L1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1598&quot; height=&quot;679&quot; data-origin-width=&quot;1598&quot; data-origin-height=&quot;679&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;객체와 생성자함수와 프로토타입의 관계&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 객체를 생성하고자 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예시에서 사용한 circle1 이라고 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;circle1의 생성은 생성자 함수를 통하여 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;circle1(3번)의 프로토타입은 객체 생성 방식에 따라, 생성자 함수 Circle(1번)의 prototype 프로퍼티에 바인딩되어 있는 Circle.prototype 객체(2번)다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1659025953891&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 생성자 함수
function Circle(radius) {
    this.radius = radius;
}

Circle.prototype.getDiameter = function() {
    return 2 * this.radius;
};

const circle1 = new Circle(5);

console.log('생성자 함수 = [1번]');
console.log(Circle);
// &amp;fnof; Circle(radius) {
//     this.radius = radius;
// }

console.log('[1번]의 prototype 프로퍼티 = [2번]');
console.log(Circle.prototype);
// {getDiameter: &amp;fnof;, constructor: &amp;fnof;}

console.log('[2번]의 constructor 프로퍼티');
console.log(Circle.prototype.constructor);
// &amp;fnof; Circle(radius) {
//     this.radius = radius;
// }

console.log('[1번] 과 [2번]의 construcotor 프로퍼티 관계');
console.log(Circle === Circle.prototype.constructor);  
// true

console.log('[1번]으로 생성된 인스턴스 = [3번]');
console.log(circle1);
// Circle&amp;nbsp;{radius: 5}

console.log('[3번]의 __proto__ 접근자 프로퍼티');
console.log(circle1.__proto__);
// {getDiameter: &amp;fnof;, constructor: &amp;fnof;}

console.log('[3번]의 __proto__ 접근자 프로퍼티와 [2번]의 관계');
console.log(Circle.prototype === circle1.__proto__); 
// true

console.log('[3번]의 constructor');
console.log(circle1.constructor);
// &amp;fnof; Circle(radius) {
//     this.radius = radius;
// }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Circle 생성자 함수는 circle1 객체를 생성했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때, circle1 객체는 프로토타입의 constructor 프로퍼티를 통해 생성자 함수와 연결된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;circle1 객체는 constructor 프로퍼티가 없지만, circle1 객체의 __proto__인 Circle.prototype에는 constructor가 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;따라서, 상속받아서 Circle과 연결된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 예시를 보며 한번 정리해보도록 하자.&lt;/p&gt;
&lt;pre id=&quot;code_1659162832820&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// obj 객체를 생성한 생성자 함수는 Object이다.
const obj = new Object();
console.log(obj.constructor === Object); // true

// add 함수 객체를 생성한 생성자 함수는 Function이다
const add = new Function('a', 'b', 'return a+b');
console.log(add.constructor === Function); // true

// 생성자 함수
function Person(name) {
  this.name = name;
}

// me 객체를 생성한 생성자 함수는 Person이다.
const me = new Person('Lee');
console.log(me.constructor === Person); // true&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;리터럴 타입으로 생성된 객체에서는 어떻게 될까?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 생성자 함수에 대해 프로토타입이 어떻게 되는지 알아보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 리터럴 타입으로 생성된 객체에 대해서는 프로토타입이 어떻게될까?&lt;/p&gt;
&lt;pre id=&quot;code_1659162701400&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 객체 리터럴
const obj = {};

// 함수 리터럴
const add = function(a, b) { return a+b; };

// 배열 리터럴
const arr = [1,2,3];

// 정규 표현식 리터럴
const regex = /ab+c/;

console.log(obj.constructor === Object); // true
console.log(add.constructor === Function); // true
console.log(arr.constructor === Array); // true
console.log(regex.constructor === RegExp); // true&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체 리터럴로 생성한 obj임에도, 그 constructor는 Object가 나왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 리터럴은 Function으로 생성하지 않았는데도, Function이 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이에 대해서 ECMA Script 사양에 별도로 예외적으로 적혀있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히, Function은 클로져같은 제약사항이 있는 문법인데도, 함수 리터럴의 생성자라고 나오고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, 함수라는 그 특성 자체는 동일하므로 어느정도 연관성이 있는 것으로 보고 넘어가도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;프로토타입 체인&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1659164052711&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 생성자 함수
function Person(name) {
  this.name = name;
}

// 프로토타입 메서드
Person.prototype.sayHello = function() {
  console.log(`Hi My name is ${this.name}`);
};

const me = new Person(&quot;James&quot;);
console.log(me.hasOwnProperty('name')); // true&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예시를 보면 알 수 있듯이, 자바스크립트는 객체의 프로퍼티(메서드 포함)에 접근하려고 할 때, 해당 객체에 원하는 프로퍼티가 있는지 찾는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;없다면, [[Prototype]] 내부 슬롯의 참조를 따라 자신의 부모 프로토타입에서 순차적으로 찾기 시작한다&lt;/b&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;프로토타입 체인&lt;/b&gt;&lt;/span&gt;이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 체이닝의 종점은 Object.prototype일 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;프로토타입 체인&lt;/b&gt;&lt;/span&gt;은&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt; 프로퍼티 검색을 위한 메커니즘&lt;/b&gt;&lt;/span&gt;이라면, 이전에 공부한 식별자는 &lt;a href=&quot;https://koocci-dev.tistory.com/49?category=1030064&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;스코프 체인&lt;/a&gt;으로 검색할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 프로토타입 체인을 통해,&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt; instanceof&lt;/b&gt; &lt;/span&gt;같은 연산자도 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;instanceof는 &lt;b&gt;객체의 체이닝 내에 존재하는 프로토타입인지 검색하여, true/false로 평가한다.&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Wrap up&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트의 프로토타입에 대해 알아보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 Class에 대한 내용이랑도 연결되며, 앞서 배웠던 생성자, 프로퍼티 등의 개념이 최종적으로 어우러지는 부분이라는 것을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;프로토타입&lt;/b&gt;&lt;/span&gt;은 &lt;b&gt;객체간의 상속을 표현하기 위해서 사용되었고, 그로인해 오버라이딩과 같은 기능도 동일하게 구현할 수 있었다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 다음은 This 객체부터 조금 자세히 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/javascript</category>
      <category>JavaScript</category>
      <category>Prototype</category>
      <category>자바스크립트</category>
      <category>프로토타입</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/62</guid>
      <comments>https://koocci-dev.tistory.com/62#entry62comment</comments>
      <pubDate>Sat, 30 Jul 2022 16:10:43 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] Bean Scope 가 뭘까?</title>
      <link>https://koocci-dev.tistory.com/61</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : Bean Scope에 대해 설명할 수 있다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Bean Scope&lt;/b&gt;&lt;/span&gt;라는 것은 Bean의 범위인데, 아마 바로는 이해가 쉽지 않을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Bean Scope는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;객체를 만들 때, 컨테이너가 이 객체를 한번만 호출하는지, 아니면 호출 할 때마다 여러번 만드는지&lt;/b&gt;&lt;/span&gt;에 대한 내용이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 &lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-factory-scopes&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;문서 상&lt;/a&gt;에 여러 Scope가 있는 걸 볼 수 있고, 대부분 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;singleton&lt;/b&gt;&lt;/span&gt; 혹은 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;prototype&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 두가지를 알아보기 전에 한가지 정리가 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;용어부터 정리해보자.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Identity (동일성) &lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;그리고 &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;equals (동등성) &lt;/b&gt;&lt;/span&gt;두가지가 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Identity (동일성)&lt;/b&gt; &lt;/span&gt;은 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;객체의 주소&lt;/b&gt;&lt;/span&gt;가 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 말은&amp;nbsp; obj1 == obj2 &amp;amp;&amp;amp; obj2 == obj3 를 했을 때, true가 나오는 Hashcode가 동일한 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;equals(동등성)&lt;/b&gt; &lt;/span&gt;은 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;객체의 값&lt;/b&gt;&lt;/span&gt;이 같은 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;equals는 obj1.equals(obj2) == ture 와 같이 그 값들이 같은 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;equals는 객체의 equals에 대해 Overload에 따라 달라질 수 있고, 그 내부 정보가 같다면 같을 수 있지만, Identity는 그 주소가 같다는 것으로 Singleton일 때는 하나의 객체를 재사용하므로 같을 것이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Singleton&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Default로서, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Spring IoC container에서 호출될 때 딱 하나의 객체만 만들어서 재사용하는 것&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 위에서 배운 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Identity(동일성)&lt;/b&gt;&lt;/span&gt;을 확인해보도록 하자.&lt;/p&gt;
&lt;pre id=&quot;code_1659019674241&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;bean id=&quot;A&quot; class=&quot;com.something.A&quot;/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 처럼 선언된 bean을 getBean으로 가져와, 비교를 해볼 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1659019831672&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ApplicationContext context = new ClassPathXmlApplicationContext(&quot;test.xml&quot;);

A a1 = context.getBean(&quot;A&quot;, A.class);
A a2 = context.getBean(&quot;A&quot;, A.class);

log.info(&quot;result Identity = &quot; + (a1 == a2)); // true&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Prototype&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Spring IoC Container가 호출될 때마다 객체를 만드는 것(new 로 만드는 것과 동일)이다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;이 역시, &lt;b&gt;Identity(동일성)&lt;/b&gt;&lt;/span&gt;을 확인해보도록 하자.&lt;/p&gt;
&lt;pre id=&quot;code_1659019956500&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;bean id=&quot;B&quot; class=&quot;com.something.B&quot; scope=&quot;prototype&quot;/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1659019921731&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ApplicationContext context = new ClassPathXmlApplicationContext(&quot;test.xml&quot;);

B b1 = context.getBean(&quot;B&quot;, B.class);
B b2 = context.getBean(&quot;B&quot;, B.class);

log.info(&quot;result Identity = &quot; + (b1 == b2)); // false&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Wrap Up&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단하게 Bean Scope에 대해 알아보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IoC Container에서 Bean이 어떻게 생성되는가에 대한 내용이고, 가장 대표적인 2가지를 알아보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Framework/Spring</category>
      <category>Bean</category>
      <category>Bean Scope</category>
      <category>spring</category>
      <category>Spring Framework</category>
      <category>빈스코프</category>
      <category>스프링</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/61</guid>
      <comments>https://koocci-dev.tistory.com/61#entry61comment</comments>
      <pubDate>Fri, 29 Jul 2022 00:14:04 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] 스프링의 DI가 뭘까?</title>
      <link>https://koocci-dev.tistory.com/60</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : Spring의 DI에 대해 설명할 수 있다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;DI(Dependency Injection)&lt;/b&gt;&lt;/span&gt;에 대해 알아보려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 &lt;a href=&quot;https://koocci-dev.tistory.com/58?category=1012333&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;IoC Container에 대한 설명&lt;/a&gt;에서 Spring 공식문서에 &lt;b&gt;IoC&lt;/b&gt;와 &lt;b&gt;DI&lt;/b&gt;를 동일하게 표현하고 있다는 걸 먼저 볼 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼에도 용어가 다른 것에는 다른 의미가 있을 텐데, 어떻게 된건지 알아보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에도 역시, &lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-dependencies&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Spring 공식문서의 Dependencies 부분&lt;/a&gt;을 참고하여 확인해볼 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Dependencies&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통의 Application은 하나 이상의 Object로 구성된다. 그리고, 이 Object들은 서로 함께 동작하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 예시를 보도록 하자.&lt;/p&gt;
&lt;pre id=&quot;code_1658757711255&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// A.java
public class A {
    private B b = new B();
    public void print() {
	    System.out.println(b.calc());
    }
}

// B.java
public class B {
    public int calc() {
    	return 1;
    }
}

// main.java
public static void main(String[] args) {
	A a = new A();
	a.print();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A라는 클래스(Object)는 B라는 클래스(Object)와 관련이 있고, A와 B는 함께 동작하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;A는 내부에서 B를 호출하고 있다.&lt;/b&gt; 이런 관계를 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;A는 B라는 객체에 &lt;span style=&quot;color: #ee2323;&quot;&gt;의존성(Dependency)&lt;/span&gt;이 있다&lt;/b&gt;&lt;/span&gt;고 말할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 B 클래스가 조금 수정된다고 생각해보자.&lt;/p&gt;
&lt;pre id=&quot;code_1658758044514&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class B {
    private boolean condition;

    public B(boolean condition) {
        this.condition = condition;
    }
    public int calc() {
        return condition? 1 : 0;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;B가 condition이라는 값에 따라, calc되는 값이 바뀌도록 수정되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거기다가 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;생성자&lt;/b&gt;&lt;/span&gt;도 추가되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;A는 B에 의존성이 있으므로, 코드 레벨에서 수정될 수 밖에 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;B의 Condition을 넣어주기 위해서는 A도 생성자를 만들거나, 인스턴스 생성 때 부터 B 생성자에 초깃값을 넣어주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, 보통 원하는 방향은 Main함수에서 condition을 조절하기 떄문에, A에 생성자를 넣어줄 필요가 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1658758395859&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// A.java
public class A {
    private B b;
    public A(boolean condition) {
        this.b = new B(condition);
    }
    public void print() {
        System.out.println(b.calc());
    }
}

//Main.java
public static void main(String[] args) {
    boolean condition = true;
    A a = new A(condition);
    a.print();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 계속해서, &lt;b&gt;코드의 복잡도가 증가하게 된다. A는 Main에서, B는 A에서 Condition을 받아야 하고, 나중에는 개발자가 감당하기 힘들어진다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 상황에서는&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;DI(Dependency Injection : 의존성 주입)&lt;/b&gt;&lt;/span&gt;를 통해 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;디커플링(Decoupling)&lt;/b&gt;&lt;/span&gt;하는 작업이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;간결하고 유지보수가 편해야 하기 때문이다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;디커플링&lt;/b&gt;&lt;/span&gt; : 소프트웨어 공학에서 결합도(Coupling)란 모듈간 의존도를 나타내는 것을 의미. &lt;br /&gt;반대로 디커플링이란 인터페이스 등을 활용하여 모듈간 의존도를 최소화하여 개발하는 방법을 의미&lt;/blockquote&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;DI를 통해 디커플링한다는 것이 무엇일까?&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DI를 통해 디커플링한다는 것은 코드 레벨에서 관계를 맺는 작업이 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;A 클래스에 B를 넣는 생성자를 만들어보자.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1658839619157&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// A.java
public class A {
    private B b;

    public A(B b) {
        this.b = b;
    }

    public void print() {
        System.out.println(b.calc());
    }
}

// B.java
public class B {
    private boolean condition;

    public B(boolean condition) {
        this.condition = condition;
    }
    public int calc() {
        return condition ? 1: 0;
    }
}

// Main.java
public static void main(String[] args) {
    boolean condition = true;
    B b = new B(condition);
    A a = new A(b);
    a.print();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 변경하면 어떻게 변할까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;A는 B가 가져야 할 값에서 독립된다(B가 가져야할 값을 A는 몰라도 된다).&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 디커플링 되고, 소스 복잡도가 줄어든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;IoC Container&lt;/b&gt;&lt;/span&gt;는 이런 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;DI 작업을 프레임워크화, 도구화한 것&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Spring 이라는 프레임워크가 DI 원리를 이용해 객체간의 관계를 만들어주는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 말해,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;DI가 IoC Container의 주요 원리다.&lt;/span&gt;&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;그럼 어디서 DI를 설정하는 것일까?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로, 앞서 배웠던 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Configuration Metadata&lt;/b&gt;&lt;/span&gt;에서의 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Bean 설정&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;pre id=&quot;code_1658840212536&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
    xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
    xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd&quot;&amp;gt;

    &amp;lt;bean id=&quot;a&quot; class=&quot;com.test.A&quot;&amp;gt;  
        &amp;lt;constructor-arg ref=&quot;b&quot; /&amp;gt;
    &amp;lt;/bean&amp;gt;

    &amp;lt;bean id=&quot;b&quot; class=&quot;com.test.B&quot;&amp;gt;  
        &amp;lt;constructor-arg value=&quot;true&quot;&amp;gt;&amp;lt;/constructor-arg&amp;gt;
    &amp;lt;/bean&amp;gt;

    &amp;lt;!-- more bean definitions go here --&amp;gt;

&amp;lt;/beans&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;constructor-arg&lt;/b&gt;&lt;/span&gt;라는 것이 새롭게 나왔지만, A 클래스에는 id가 b로 가진 Bean을 생성자에 주입해주는 것이며, 나중에 다시 한번 볼 예정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;B 클래스 역시, Boolean 값이 생성자에 필요하므로, value로 넣어준 것이며, 이후에 문법은 다시 한 번 보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문법과 별개로 위와 같이, &lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;Configuration Metadata&lt;/span&gt;&lt;/b&gt;를 설정하면 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Main 함수에서 new 로 생성했던 A와 B를 없애고, ApplicationContext에서 가져올 수 있게 된다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1658840508415&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static void main(String[] args) {
    ApplicationContext context = new ClassPathXmlApplicationContext(my.xml);
    A a = context.getBean(&quot;a&quot;, A.class);
    a.print();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;DI&lt;/b&gt;&lt;/span&gt;를 명쾌하게 정리해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;DI&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666;&quot;&gt;는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #fcfcfc;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;IoC Container&lt;/span&gt; 의 대표적인 동작 원리로서,&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;객체간의 관계를 외부로 부터 주입받아, 그 관계를 느슨하고 동적으로 가져가는 것&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666;&quot;&gt;을 말한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc;&quot;&gt;외부라고 함은, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Configuration Metadata&lt;/b&gt;&lt;/span&gt;에서 정의한 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Bean&lt;/b&gt;&lt;/span&gt;이며, 그 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;객체간의 관계를 설정&lt;/b&gt;&lt;/span&gt;할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;객체의 관계를 설정으로 빼면 어떤 면이 좋아질까?&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;설정으로 객체간의 관계를 알 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Container 사용을 위한 코드를 제외하면, Business 로직만 고려할 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문서로 잠깐 돌아가 보자.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;your classes become easier to test, particularly when the dependencies are on interfaces or abstract base classes, which allow for stub or mock implementations to be used in unit tests.&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;요약하면,&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt; 테스트&lt;/span&gt;가 더 하기 쉬워진다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트는 또 한번 이야기 할 것이기 때문에, 구체적인 내용은 나중에 배우도록 하고, 내용만 알아두도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Constructor-Based / Setter-Based DI&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미, 생성자를 기준으로한 DI를 위 예시에서 보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 다른 것으로 Setter를 통해 DI가 가능하다.&lt;/p&gt;
&lt;pre id=&quot;code_1658842816296&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// A.java
public class A {
    private B b;

    public void setB(B b) {
    	this.b = b;
    }

    public void print() {
        System.out.println(b.calc());
    }
}

// B.java
public class B {
    private boolean condition;

    public B(boolean condition) {
        this.condition = condition;
    }
    public int calc() {
        return condition ? 1: 0;
    }
}

// Main.java
public static void main(String[] args) {
    ApplicationContext context = new ClassPathXmlApplicationContext(my.xml);
    A a = context.getBean(&quot;a&quot;, A.class); // 에러 남
    a.print();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아마 바로하면 에러가 날 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Bean 설정이 Constructor 로 되어 있기 때문이다.&lt;/p&gt;
&lt;pre id=&quot;code_1658842889280&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
    xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
    xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd&quot;&amp;gt;

    &amp;lt;bean id=&quot;a&quot; class=&quot;com.test.A&quot;&amp;gt;  
        &amp;lt;property name=&quot;b&quot; ref=&quot;b&quot; /&amp;gt;
    &amp;lt;/bean&amp;gt;

    &amp;lt;bean id=&quot;b&quot; class=&quot;com.test.B&quot;&amp;gt;  
        &amp;lt;constructor-arg value=&quot;true&quot;&amp;gt;&amp;lt;/constructor-arg&amp;gt;
    &amp;lt;/bean&amp;gt;

    &amp;lt;!-- more bean definitions go here --&amp;gt;

&amp;lt;/beans&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문법은 나중에 다시 보도록 하고, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Setter&lt;/b&gt;&lt;/span&gt; 로 가능하다는 것을 알도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;생성자&lt;/span&gt;와 &lt;span style=&quot;color: #ee2323;&quot;&gt;Setter&lt;/span&gt;의 차이점&lt;/b&gt;은 생성자는 &lt;b&gt;객체가 만들어질 때 단 한번만 동작&lt;/b&gt;하므로, 생성할 때만 필요한 코드를 넣을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Setter는 &lt;b&gt;런타임에 Setter를 통해 객체의 관계를 재설정&lt;/b&gt;할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나, 보통은 관계는 변경되지 않는 것이 복잡도를 떨어트리므로, Setter보다 &lt;b&gt;생성자를 권장&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문서에도 동일하게 나와 있으니 참고하도록 하자.&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Constructor-based or setter-based DI?&lt;/p&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Since you can mix constructor-based and setter-based DI, it is a good rule of thumb to use constructors for mandatory dependencies and setter methods or configuration methods for optional dependencies. Note that use of the&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-required-annotation&quot;&gt;@Required&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;annotation on a setter method can be used to make the property be a required dependency; however, constructor injection with programmatic validation of arguments is preferable.&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;The Spring team generally advocates constructor injection, as it lets you implement application components as immutable objects and ensures that required dependencies are not&lt;span&gt;&amp;nbsp;&lt;/span&gt;null. Furthermore, constructor-injected components are always returned to the client (calling) code in a fully initialized state. As a side note, a large number of constructor arguments is a bad code smell, implying that the class likely has too many responsibilities and should be refactored to better address proper separation of concerns.&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Setter injection should primarily only be used for optional dependencies that can be assigned reasonable default values within the class. Otherwise, not-null checks must be performed everywhere the code uses the dependency. One benefit of setter injection is that setter methods make objects of that class amenable to reconfiguration or re-injection later. Management through&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/reference/html/integration.html#jmx&quot;&gt;JMX MBeans&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;is therefore a compelling use case for setter injection.&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Use the DI style that makes the most sense for a particular class. Sometimes, when dealing with third-party classes for which you do not have the source, the choice is made for you. For example, if a third-party class does not expose any setter methods, then constructor injection may be the only available form of DI.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Dependency Resolution Process (의존성 해결 프로세스)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ApplicationContext가 XML, java code, annotation 를 통해 정의된 Configuration Metadata를 읽어 Beans를 생성하고 초기화 한다.&lt;/li&gt;
&lt;li&gt;각각의 Bean에 대해서는 Property, 생성자 Argument, Static-Factory Method(기본 생성자를 쓰지 않을 때)의 Argument를 통해 의존성이 표현된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Circular Dependency&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순환 참조가 되는 경우가 당연히 있을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A에서 B에 대해 의존성이 있고, B는 A에 대해 의존성을 있을 때, 에러가 날 것이다. 서로서로 참조하면서 초기화 할 것이기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때, Spring 은 &lt;b&gt;BeanCurrentlyInCreationException&lt;/b&gt; 을 throw 하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Wrap-up&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 전체적으로 한번 다시 정리해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://koocci-dev.tistory.com/59&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;앞선 포스팅&lt;/a&gt;의 Bean 부분도 시원하지 않게 넘어갔으니, 같이 정리해 보도록 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저, 앞서 배운 내용들을 나열해보자.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Spring Framework에서는 ApplicationContext를 통해 IoC Container를 제공하고 있다.&lt;br /&gt;ApplicationContext는 인터페이스이며, 그 구현체는 Spring Container(=IoC Container)라고 한다.&lt;br /&gt;Spring Container는 Bean이라고 하는 사용하고자 하는 객체의 생성, 인스턴스화 등을 관리하고 있다.&lt;br /&gt;Bean에 대한 정보는 Configuration Metadata에 정의하여 관리된다.&lt;br /&gt;DI는 객체간의 관계를 외부로 부터 주입받아, 그 관계를 느슨하고 동적으로 가져가는 것을 말하며,&amp;nbsp;&lt;br /&gt;IoC Container&amp;nbsp;의 대표적인 동작 원리다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 전체 흐름을 정리하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;ApplicationContext&lt;/b&gt;&lt;/span&gt;의 구현체인 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Spring Container(=IoC Container)&lt;/b&gt;&lt;/span&gt;는 &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;Bean을 생성하고 관리하고 인스턴스화&lt;/span&gt; &lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Bean&lt;/b&gt;&lt;/span&gt;은 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Spring Container에 의해 관리되는 객체&lt;/b&gt;&lt;/span&gt;이며,&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Configuration Metadata&lt;/b&gt;&lt;/span&gt;를 통해&amp;nbsp;&lt;b&gt;3가지 방법(생성자(Constructor), Static-Factory Method, Instance-Factory Method)&lt;/b&gt;으로 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;생성&lt;/b&gt;&lt;/span&gt;될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각의 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Bean(객체)의 관계&lt;/b&gt;&lt;/span&gt;도 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Configuration Metadata에서 설정&lt;/b&gt;&lt;/span&gt;할 수 있는데, IoC Container에서는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;DI(= Dependency Injection)&lt;/b&gt;&lt;/span&gt;라고 하는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;대표적인 동작 원리&lt;/b&gt;&lt;/span&gt;를 통해 그 관계를 &lt;b&gt;느슨하고 동적으로 연결&lt;/b&gt;하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;DI&lt;/b&gt;&lt;/span&gt;는 &lt;b&gt;생성자를 통한 주입, Setter를 통한 주입&lt;/b&gt; 2가지의 종류로 제공할 수 있으며, &lt;b&gt;생성자를 통한 주입이 권장&lt;/b&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Framework/Spring</category>
      <category>ApplicationContext</category>
      <category>Bean</category>
      <category>Dependency Injection</category>
      <category>di</category>
      <category>IOC</category>
      <category>spring</category>
      <category>Spring Framework</category>
      <category>스프링</category>
      <category>스프링 프레임워크</category>
      <category>의존성 주입</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/60</guid>
      <comments>https://koocci-dev.tistory.com/60#entry60comment</comments>
      <pubDate>Tue, 26 Jul 2022 23:16:16 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] 스프링의 Bean을 어떻게 쓸 수 있을까?</title>
      <link>https://koocci-dev.tistory.com/59</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : Spring 의 Bean을 간단히 사용해볼 수 있다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;스프링은 무엇을 도와주는가?&lt;/li&gt;
&lt;li&gt;스프링의 사용법은 어떻게 되는가?&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라는 두가지 주제 중, 스프링은 무엇을 도와주는가? 에 대해&amp;nbsp; 간략히 정의와 함께 알아보았고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링의 사용법을 알기 이전에 그 사용 용어들부터 정리해보고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선, &lt;a href=&quot;https://koocci-dev.tistory.com/58?category=1012333&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이전 포스트&lt;/a&gt;에서 Spring 의&lt;b&gt; IoC Container&lt;/b&gt;가 무엇인지 설명할 수 있게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, 그 Detail을 조금 더 파고 들고자 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Bean이라는 것&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 보던 Spring 공식 문서에서 &lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-definition&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Bean Overview&lt;/a&gt;를 통해 자세히 알아보고자 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 우린 Bean이라는 것도 이미 배웠다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Bean&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #555555;&quot;&gt;은&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Spring Container (ApplicationContext 구현체) 가 관리하고 생성하고 인스턴스화 해주는 &lt;span style=&quot;color: #ee2323;&quot;&gt;객체&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #555555;&quot;&gt;다.&lt;/span&gt;&lt;span style=&quot;color: #555555;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 공식 문서의 첫 문장은 IoC Container가 하는 일에 대해 적혀있다..&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;A Spring IoC container manages one or more beans. These beans are created with the configuration metadata that you supply to the container (for example, in the form of XML&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&amp;lt;bean/&amp;gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;definitions).&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;Spring IoC container&lt;/span&gt; 는 다수의 Bean들을 관리한다. 이 &lt;span style=&quot;color: #ee2323;&quot;&gt;Bean&lt;/span&gt;들은 &lt;span style=&quot;color: #ee2323;&quot;&gt;Configuration Metadata&lt;/span&gt;를 통해 만들어지며, 이는 XML과 같은 형태로 제공된다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이제 Bean이라는 게 어떻게 정의되는지 알아보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Bean은 어떻게 생성할 수 있는가?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Annotation은 차츰 진행하면서 다시한번 공부하기로 하고, XML 형태를 먼저 보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;XML의 &amp;lt;bean/&amp;gt;으로 정의되는&amp;nbsp; Bean은 여러가지 Property들이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;용도에 따라 각기 다른 내용들이 있는데, 우선은 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Class, Name&lt;/b&gt;&lt;/span&gt; 두가지에 집중해서 볼 예정이다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Naming Beans&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;bean은 하나 이상의 Unique한 ID를 갖는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;XML에서는 id나 name attribute로 설정가능하다. (ID는 유일하지만, name은 여러개 작성이 가능하다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유니크한 값이 있는 이유는 &lt;b&gt;같은 Class라도 Spring이 관리하는 Bean이 다를 수 있기 때문&lt;/b&gt;이다.&lt;/p&gt;
&lt;pre id=&quot;code_1658554624132&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;bean id=&quot;dao1&quot; name=&quot;dao2, dao3&quot; class=&quot;com.test.myobj&quot;/&amp;gt;
&amp;lt;bean id=&quot;new_dao&quot;  class=&quot;com.test.myobj&quot;/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Instantiating Beans&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Bean을 객체로 만드는 건 크게 3가지 방법이 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Constructor (생성자)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Static Factory Method&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Instance Factory Method&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하기 예시로 설명해보자.&lt;/p&gt;
&lt;pre id=&quot;code_1658554920851&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;bean id=&quot;exampleBean&quot; class=&quot;examples.ExampleBean&quot;/&amp;gt;

&amp;lt;bean name=&quot;anotherExample&quot; class=&quot;examples.ExampleBeanTwo&quot;/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 bean의 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;class를 정의&lt;/b&gt;&lt;/span&gt;하면, &lt;b&gt;ExampleBean의 &lt;span style=&quot;color: #ee2323;&quot;&gt;기본 생성자&lt;/span&gt;를 통해 Bean을 만든다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약, 기본 생성자가 없다면? 그럼 에러가 나고 별도 과정이 더 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1658555272710&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;bean id=&quot;clientService&quot;
    class=&quot;examples.ClientService&quot;
    factory-method=&quot;createInstance&quot;/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1658561319932&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class ClientService {
    private static ClientService clientService = new ClientService();
    private ClientService() {}

    public static ClientService createInstance() {
        return clientService;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;factory-method&lt;/b&gt;&lt;span&gt;라는 attribute를 추가하였고,&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Static Factory Method&lt;/b&gt;&lt;/span&gt;로 생성하는 방법이다.&lt;/p&gt;
&lt;pre id=&quot;code_1658561462953&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- the factory bean, which contains a method called createInstance() --&amp;gt;
&amp;lt;bean id=&quot;serviceLocator&quot; class=&quot;examples.DefaultServiceLocator&quot;&amp;gt;
    &amp;lt;!-- inject any dependencies required by this locator bean --&amp;gt;
&amp;lt;/bean&amp;gt;

&amp;lt;!-- the bean to be created via the factory bean --&amp;gt;
&amp;lt;bean id=&quot;clientService&quot;
    factory-bean=&quot;serviceLocator&quot;
    factory-method=&quot;createClientServiceInstance&quot;/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Instance Factory Method&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때는 2개의 bean이 필요하다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Bean을 만들어줄 클래스&lt;/b&gt;&lt;/span&gt;가 정의된 Bean&lt;/li&gt;
&lt;li&gt;사용할 Bean (&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;class 대신 factory-bean이 들어간다&lt;/b&gt;&lt;/span&gt;.)&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용할 Bean에 factory-bean이라는 attribute로 Bean을 만들어줄 클래스가 정의된 Bean을 지정하고, 동작시킬 factory-method를 정의해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;자기 자신이 Factory-method를 가진 경우&lt;/b&gt; 앞선 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;static factory method&lt;/b&gt;&lt;/span&gt;를 사용하고, &lt;b&gt;외부에서 자신을 정의시켜준다면&lt;/b&gt;, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;instance factory method&lt;/b&gt;&lt;/span&gt;를 사용한다.&lt;/p&gt;
&lt;pre id=&quot;code_1658561687087&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class DefaultServiceLocator {

    private static ClientService clientService = new ClientServiceImpl();

    public ClientService createClientServiceInstance() {
        return clientService;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Wrap up&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;Configuration Metadata를 통해 간단한 Bean을 만드는 법을 알 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무래도 Bean에 대해 시원하게 다루지 못한 감이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DI라는 개념과 함께 Bean Scope, Annotation으로 발전시켜나가야 하는데, 모든 걸 한번에 다룰 수 없으니&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시한번 Wrap up하는 시점이 나오지 않을까 한다.&lt;/p&gt;</description>
      <category>Framework/Spring</category>
      <category>Bean</category>
      <category>Instance Factory Method</category>
      <category>IoC Container</category>
      <category>spring</category>
      <category>Spring Framework</category>
      <category>static factory method</category>
      <category>스프링</category>
      <category>스프링 프레임워크</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/59</guid>
      <comments>https://koocci-dev.tistory.com/59#entry59comment</comments>
      <pubDate>Sat, 23 Jul 2022 16:45:14 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] 스프링의 IoC Container가 뭘까?</title>
      <link>https://koocci-dev.tistory.com/58</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : 스프링의 IoC Container 에 대해 설명할 수 있다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://koocci-dev.tistory.com/57?category=1012333&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;앞선 포스팅&lt;/a&gt;에서 스프링 프레임워크가 주는 의문 두가지,&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;스프링은 무엇을 도와주는가?&lt;/li&gt;
&lt;li&gt;스프링의 사용법은 어떻게 되는가?&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중에서 스프링의 사용법은 어떻게 되는지 알아볼 차례다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 그 전에, 용어를 정리해야 사용법도 알게 될 것이므로 용어부터 하나씩 보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 중, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;IoC Container&lt;/b&gt;&lt;/span&gt; 에 대해 알아볼 것이고, 그 내용은 &lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/reference/html/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;스프링 공식 문서&lt;/a&gt;를 기반으로 확인해 보겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스프링 코어 (spring-core)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 코어의 가장 처음 나오는 용어가 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;IoC Container&lt;/b&gt; &lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 그 문장을 그대로 가져오면 다음과 같다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Foremost amongst these is the Spring Framework&amp;rsquo;s Inversion of Control (IoC) container.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 프레임워크의 가장 중요한 것은 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Inversion of Control(IoC)&lt;/b&gt; &lt;b&gt;container&lt;/b&gt;&lt;/span&gt; 다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 IoC는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Dependency Injection(DI, 종속성 주입)&lt;/b&gt;&lt;/span&gt; 이라고도 하는데 그 설명을 읽어보면 바로 직관적으로 와닿지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기에 우선은 간략하게 아래 처럼 이해해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 프레임워크는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;ApplicationContext&lt;/b&gt;&lt;/span&gt;라는 인터페이스를 통해서&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt; IoC Container&lt;/span&gt;&lt;/b&gt; 를 제공하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/ApplicationContext.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;b&gt;org.springframework.context.ApplicationContext&lt;/b&gt; &lt;/a&gt;&lt;span style=&quot;color: #333333;&quot;&gt;가 IoC Container 의 핵심인데, &lt;b&gt;이 인터페이스를 기준으로 구현된 다양한 구현체를 통해서 다양한 방식, 다양한 방법으로 IoC Container 기능이 구현&lt;/b&gt;되어 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭔지 모르겠지만, ApplicationContext라는 친구가 스프링 프레임워크의 IoC Container 를 책임지고 있는 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 아래 이미지를 보며 좀더 구체적으로 이해해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;container-magic.png&quot; data-origin-width=&quot;498&quot; data-origin-height=&quot;296&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cl6Pfp/btrH1zeve74/HYDMpebpde8FM8ekkeIFM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cl6Pfp/btrH1zeve74/HYDMpebpde8FM8ekkeIFM1/img.png&quot; data-alt=&quot;Figure 1. The Spring IoC Container&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cl6Pfp/btrH1zeve74/HYDMpebpde8FM8ekkeIFM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcl6Pfp%2FbtrH1zeve74%2FHYDMpebpde8FM8ekkeIFM1%2Fimg.png&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; alt=&quot;https://docs.spring.io/spring-framework/docs/current/reference/html/images/container-magic.png&quot; loading=&quot;lazy&quot; width=&quot;498&quot; height=&quot;296&quot; data-filename=&quot;container-magic.png&quot; data-origin-width=&quot;498&quot; data-origin-height=&quot;296&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Figure 1. The Spring IoC Container&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;POJO(Plain Old Java Object)&lt;/span&gt;로 만들어진 나의 비즈니스 오브젝트(나의 소스코드, 객체들)들은&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;스프링에서 제공하는 방법에 따라 만들어준 &lt;span style=&quot;color: #ee2323;&quot;&gt;설정정보(Configuration Metadata)&lt;span style=&quot;color: #006dd7;&quot;&gt;와&lt;/span&gt;&lt;/span&gt; 결합되고,&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;Application Context를 구현한 구현체(Spring Container)&lt;/span&gt;가 생성되고 초기화되었을 때, 실행가능한 프로그램&lt;b&gt;(스프링에서 구동가능한 형태)&lt;/b&gt;이 되는 것&lt;/b&gt;&lt;/span&gt;이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;번역하다보니 어렵지만, 결국 프레임워크 설명과 유사하다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;내가 만든 소스코드가 잘 작성된 설정정보랑 합쳐지면, &lt;span&gt;Application Context의 구현체가&lt;/span&gt; 스프링에서 동작 가능하도록 만들어준다는 것&lt;/b&gt;이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;그럼 먼저, &lt;b&gt;설정 정보&lt;/b&gt;라는 것이 무엇인지 보자.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Configuration Metadata&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;스프링에서 제공하는 설정방법은 크게 2가지, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;XML&lt;/b&gt;&lt;/span&gt; 과 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Annotation&lt;/b&gt;&lt;/span&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;먼저 XML 예시를 보도록 하자. (Annotation은 나중에 다시 볼 것이다)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1658501867533&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
    xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
    xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd&quot;&amp;gt;

    &amp;lt;bean id=&quot;...&quot; class=&quot;...&quot;&amp;gt;  
        &amp;lt;!-- collaborators and configuration for this bean go here --&amp;gt;
    &amp;lt;/bean&amp;gt;

    &amp;lt;bean id=&quot;...&quot; class=&quot;...&quot;&amp;gt;
        &amp;lt;!-- collaborators and configuration for this bean go here --&amp;gt;
    &amp;lt;/bean&amp;gt;

    &amp;lt;!-- more bean definitions go here --&amp;gt;

&amp;lt;/beans&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설명에서는 계속 등장했었지만, 뭔지 몰라도 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Bean&lt;/b&gt;&lt;/span&gt;이라는게 설정 정보에도 등장했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 위와 같은 형태로 작성한다는 내용을 인지하고, ApplicationContext 설명부터 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;ApplicationContext 인스턴스화&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;ApplicationContext&lt;/b&gt;&lt;/span&gt;는 인터페이스고 그 구현체가 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 말했듯이 &lt;b&gt;구현된 다양한 구현체를 통해서 다양한 방식, 다양한 방법으로 IoC Container 기능을 구현&lt;/b&gt;하기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 예시로 다음을 들고 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1658503225112&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ApplicationContext context = new ClassPathXmlApplicationContext(&quot;services.xml&quot;, &quot;daos.xml&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서는 &lt;span style=&quot;background-color: #ffffff; color: #222222;&quot;&gt;ClassPathXmlApplicationContext 라는 구현체를 사용했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222;&quot;&gt;그 Argument로는 services.xml과 daos.xml을 넣어주고 있다. (그 예시 역시 &lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#spring-core&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;해당 페이지&lt;/a&gt;에 나온다)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222;&quot;&gt;이제 앞선 설정정보와 연결해서 보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Bean은 뭐고, ApplicationContext, Configuration Metadata랑 어떻게 연결되는 거지?&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring Framework에서는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Bean&lt;/b&gt;&lt;/span&gt;이라는 것을 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉽게 생각하면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;객체&lt;/b&gt;&lt;/span&gt;다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;이 객체를 관리하는 것&lt;/b&gt;&lt;/span&gt;이&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Container&lt;/b&gt;&lt;/span&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 말해, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Bean&lt;/b&gt;&lt;/span&gt;은&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Spring Container (ApplicationContext 구현체) 가 관리하고 생성하고 인스턴스화 해주는 객체&lt;/b&gt;&lt;/span&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 우리가 java에서 객체를 만들고 사용할 때는 다음 문장처럼 작성한다.&lt;/p&gt;
&lt;pre id=&quot;code_1658504978973&quot; class=&quot;haxe&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;MyObject obj = new MyObject():&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 위처럼 직접 객체를 만들어주지않고,&lt;span&gt;&amp;nbsp;&lt;/span&gt;설정정보에 작성하면 Spring Framework가 이 객체를 관리/생성/인스턴스화 하게 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1658505156239&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
    xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
    xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd&quot;&amp;gt;

    &amp;lt;bean class=&quot;com.text.myObject&quot;/&amp;gt;  

&amp;lt;/beans&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 설정 정보에 작성해준다면, MyObject 클래스를 더이상 new 로 생성하지 않고, ApplicationContext로부터 얻어오는 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1658505239628&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ApplicationContext context = new ClassPathXmlApplicationContext(&quot;myObject.xml&quot;); // 설정정보
MyObject obj = context.getBean(MyObject.class);
obj.method(); // 행위&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222;&quot;&gt;위 과정을 다시한번 정리해보자.&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Spring Framework에서, ApplicationContext의 구현체인 Spring Container는 Bean이라는 것으로 사용하고자 하는 객체를 관리한다.&lt;br /&gt;그 생성과 인스턴스화를 관리하며, Bean에 대한 정보는 Configuration Metadata를 통해 정의한다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 마지막, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;IoC Container&lt;/b&gt;&lt;/span&gt;에 대해 정리하며 마무리하도록 하자.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222;&quot;&gt;Wrap Up&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222;&quot;&gt;Spring Framework에서는 ApplicationContext를 통해 IoC Container를 제공하고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222;&quot;&gt;ApplicationContext는 인터페이스이며, 그 구현체는 Spring Container(=IoC Container)라고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222;&quot;&gt;Spring Container는 Bean이라고 하는 사용하고자 하는 객체의 생성, 인스턴스화 등을 관리하고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222;&quot;&gt;Bean에 대한 정보는 Configuration Metadata에 정의하여 관리된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Configuration Metadata에 정의된 Bean이라는 객체를 관리하고 생성을 책임지고 인스턴스화 하는&amp;nbsp;&lt;b&gt;ApplicationContext의 구현체인 Spring Container&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;를 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;IoC Container 라고 하며, &lt;span style=&quot;color: #333333;&quot;&gt;Spring&lt;/span&gt; &lt;span style=&quot;background-color: #ffffff; color: #222222;&quot;&gt;Framework에게 객체에 대한 관리,제어를 넘겨 주는 것을 제어의 역전(Inversion of Control, IoC) &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222;&quot;&gt;이&lt;/span&gt;&lt;/span&gt;라고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Framework/Spring</category>
      <category>ApplicationContext</category>
      <category>Bean</category>
      <category>Configuration Metadata</category>
      <category>Inversion of Control</category>
      <category>IOC</category>
      <category>spring</category>
      <category>Spring Container</category>
      <category>Spring Framework</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/58</guid>
      <comments>https://koocci-dev.tistory.com/58#entry58comment</comments>
      <pubDate>Sat, 23 Jul 2022 01:23:32 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] 스프링 프레임워크가 뭘까?</title>
      <link>https://koocci-dev.tistory.com/57</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : 스프링(Spring)이 무엇인지 설명할 수 있다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;서론이자 내 생각..&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링을 별도로 공부한 적은 많이 있지만, 글을 적으려고 할 때마다, 그리고 너무 겉핥기로 알고 있다보니 난감한 부분이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히나 어려운 부분은, 오랫동안 발전해왔고 그 히스토리를 온전히 공부하면서 쌓아가야하는 건 아닐까 하는 생각이 항상 들어, 어디부터 어떻게 시작해야하는지 감이 잘 잡히지 않는다. 게다가 Spring Security, Data, Batch, Cloud, JPA 등등 너무도 다양해지는 탓에 어떻게 시작해야하는지 모르는 경우가 많았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무작정 토비의 스프링을 들고 공부하면 될지, 아니면 스프링부트로 API 서버 만드는 법부터 하면 되는 건지, JSP를 비롯한 이제는 점점 Legacy라는 단어로 표현되는 부분부터 차근히 발전한 과정을 쌓아올려야 할지, 어디부터 알면 되는 건지에 대한 부담감에 선뜻 도전하기 어렵고, 그래서 당장 필요한 부분만 보고 흐지부지 된 적도 많았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 지금도 어디부터 봐야할지 잘 모르겠지만, 언젠가는 따라가겠지라는 마음으로 하나씩 진행해 보고자 한다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Spring 은 프레임워크다.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링은 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;프레임워크&lt;/b&gt;&lt;/span&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프레임워크라 함은 쉽게 말해 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;사용법을 잘 알면 하고자 하는 일을 쉽게 할 수 있게 도와주는 뼈대&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 개발자가 사용법에 맞게 작성을 하면, 프레임워크는 Main 함수를 실행시켜 개발자가 작성한 내용을 목적에 맞게 구동시켜 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 2가지 의문이 나온다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;스프링은 무엇을 도와주는가?&lt;/li&gt;
&lt;li&gt;스프링의 사용법은 어떻게 되는가?&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스프링은 무엇을 도와주는가?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링은 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;웹 프레임워크&lt;/b&gt;&lt;/span&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바, Kotlin 등의 언어로 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;웹 서비스를 만들고자 할 때&lt;/b&gt;&lt;/span&gt;, 좀더 쉽게 만들 수 있도록 도와준다. (자바를 기준으로 설명할 것이다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조금더 구체적으로 말해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링은 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;자바 엔터프라이즈(JAVA EE) 애플리케이션 개발을 쉽게 도와주는 프레임워크&lt;/b&gt;&lt;/span&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;옛날에 자바를 통한 서버 개발에 필요한 기능을 모아서 J2EE(현재의 Java EE) 표준을 만들었고 특히, 핵심 기술인 EJB를 사용해 왔으나 이에 대한 불편함과 난이도가 매우 높았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, 스프링은 이를 해소하고자 하여 나오게 된 프레임워크다.&lt;s&gt;&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 상세한 내용은 &lt;a href=&quot;https://okky.kr/article/415474&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이 링크&lt;/a&gt;를 확인하도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바로 웹 서비스를 만들고자 한다면 Java EE API 중 하나인&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;서블릿(Servlet)&lt;/b&gt;&lt;/span&gt;이라는 친구의 도움이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;서블릿&lt;/b&gt;&lt;/span&gt;은 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;정적인 HTML의 한계를 극복하고&lt;/b&gt; &lt;b&gt;자바를 사용하여 웹페이지를 동적으로 생성하는 서버측 프로그램 혹은 그 사양&lt;/b&gt;&lt;/span&gt;을 뜻한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉽게 말하면, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;자바로 웹 서비스를 개발하기 위해 만들어진 표준 혹은 그 프로그램&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;표준&lt;/b&gt;&lt;/span&gt;이라는 점을 먼저 주목하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JAVA SE (Standard Edition)에서 Enterprise Edition으로 버전이 달라질 때, 추가되는 javax API들을 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/javaee/7/api/toc.htm&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://docs.oracle.com/javaee/7/api/toc.htm&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1658328650017&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Java(TM) EE 7 Specification APIs&quot; data-og-description=&quot;&quot; data-og-host=&quot;docs.oracle.com&quot; data-og-source-url=&quot;https://docs.oracle.com/javaee/7/api/toc.htm&quot; data-og-url=&quot;https://docs.oracle.com/javaee/7/api/toc.htm&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/javaee/7/api/toc.htm&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.oracle.com/javaee/7/api/toc.htm&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; data-ke-size=&quot;size16&quot;&gt;Java(TM) EE 7 Specification APIs&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.oracle.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/javaee/7/api/javax/servlet/package-summary.html&quot;&gt;javax.servlet&lt;/a&gt; 라는 친구가 눈에 띌 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기 만들어져 있는 Interface들이 앞서 말했던 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Servlet&lt;/b&gt;&lt;/span&gt;, &lt;b&gt;자바로 웹 서비스를 개발하기 위해 만들어진 표준 인터페이스&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 스팩을 다양한 벤더들 (Apache Tomcat, 티맥스의 jeus)이 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;이를 구현하여, 구현체로서 그&lt;/b&gt;&amp;nbsp;&lt;b&gt;구동&amp;nbsp;환경을 제공&lt;/b&gt;&lt;/span&gt;하고 있으며, 이를 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;서블릿 컨테이너&lt;/b&gt;&lt;/span&gt;라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 중, Apache Tomcat은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;오픈소스 자바 서블릿 컨테이너&lt;/b&gt;&lt;/span&gt;로 Servlet 뿐만 아니라 JSP, WebSocket 등 핵심적인 자바 엔터프라이즈 영역을 구현하였으며, 가장 많이 사용하는 WAS 중 하나다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요즘은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;서블릿 컨테이너&lt;/b&gt;&lt;/span&gt;를 별도로 쓰지 않고,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;서비스에 내장한 형태의&lt;/span&gt;&amp;nbsp;Embedded Tomcat, Undertow 등을 많이 사용하지만 이전에는 Apache Tomcat을 별도로 설치하고, WAR파일과 연결하기도 했다. (아직 우리 회사에서는 이렇게 쓰는 곳이 많이 있다)&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fafafa;&quot;&gt;요즘엔 대부분 Spring Boot로 하거나, 최소 Spring 3.0 이상인 프로젝트가 많다보니 잘 쓰지 않지만, servlet을 만들어 Controller 로서 요청을 처리할 수 있게 만들고,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;web.xml&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa;&quot;&gt;을 통해서 servlet 이름, 클래스를 매핑하는 작업이 필요했다. (이제는 어노테이션으로 다 처리한다)&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;아무튼 &lt;span style=&quot;color: #ee2323;&quot;&gt;Spring&lt;/span&gt;은 &lt;span style=&quot;color: #006dd7;&quot;&gt;서블릿 컨테이너를 통해 훨씬 간편하게 배포할 수 있고, 이전 EJB때보다 Dependency도 매우 많이 해소가 된 것&lt;/span&gt;이다.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Servlet Container 를 잠시 정리하고 가자.&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;서블릿 컨테이너&lt;/b&gt;&lt;/span&gt;&lt;span&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;servlet Interface의 method에 의해서 정의된&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;Life Cycle&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(Init, service, destroy)을 구현&lt;/b&gt;하였고, 자연스럽게 &lt;b&gt;서블릿을 관리&lt;/b&gt;하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조금 상세하게 풀어서 순서를 정리해보자.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;서블릿 컨테이너&lt;/b&gt;&lt;/span&gt;가 시작할 때 해당 프로젝트에 대한 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;모든 서블릿을 가지고 있는다.&lt;/b&gt;&lt;/span&gt; (&lt;b&gt;서블릿 인스턴스를 싱글턴으로 갖고 있다 - 서블릿 컨테이너가 살아있는 한, 메모리에서 해제되지 않는다.&lt;/b&gt;)&lt;/li&gt;
&lt;li&gt;클라이언트로부터 요청이 들어왔을 때, Request(HttpServletRequest)와 Response(HttpServletResponse) Instance 를 생성한다.&lt;/li&gt;
&lt;li&gt;사용자의 요청 URL을 분석하여, &lt;b&gt;어떤 서블릿이 담당인지 찾아내고&lt;/b&gt;, 해당 서블릿 스레드를 생성하여 앞서 생성한 Request, Response객체를 전달한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;이 때, 컨테이너는 서블릿의 service() 메소드를 호출해 request, response 객체를 전달하고 메소드에 따라, doGet, doPost 등의 메서드가 호출된다.&lt;/li&gt;
&lt;li&gt;해당 메서드에서는 response에 응답하고자 하는 내용을 작성한다.&lt;/li&gt;
&lt;li&gt;서블릿 컨테이너는&amp;nbsp; response 객체를 클라이언트로 전달하고, request, response 객체를 소멸시킨다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;서블릿 인스턴스는 사라지지 않고, 여러 요청에 대한 처리를 서블릿 컨테이너가 멈추기 전까지 계속 진행한다.&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;그럼 Servlet과 Spring Framework 는 무슨 관계가 있는가?&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;열심히 servlet이라는 것과 servlet container에 대해 알아보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 Spring Framework와 연결시켜 보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Javax.servlet 인터페이스는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;상속관계&lt;/b&gt;&lt;/span&gt;로 서블릿 컨테이너부터 Spring까지 이어지게 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;images_jakeseo_me_post_1f9f7e7e-0ef4-4892-8227-f71b6276b87d_image.png&quot; data-origin-width=&quot;1212&quot; data-origin-height=&quot;626&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zLuuV/btrIkuSsoM7/i7ADD3pKi5NrPRLvLGoR50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zLuuV/btrIkuSsoM7/i7ADD3pKi5NrPRLvLGoR50/img.png&quot; data-alt=&quot;https://velog.io/@jakeseo_me/%EC%9E%90%EB%B0%94-%EC%84%9C%EB%B8%94%EB%A6%BF%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90.-%EA%B7%BC%EB%8D%B0-%ED%86%B0%EC%BA%A3%EA%B3%BC-%EC%8A%A4%ED%94%84%EB%A7%81%EC%9D%84-%EC%82%B4%EC%A7%9D-%EA%B3%81%EB%93%A4%EC%9D%B8&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zLuuV/btrIkuSsoM7/i7ADD3pKi5NrPRLvLGoR50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzLuuV%2FbtrIkuSsoM7%2Fi7ADD3pKi5NrPRLvLGoR50%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1212&quot; height=&quot;626&quot; data-filename=&quot;images_jakeseo_me_post_1f9f7e7e-0ef4-4892-8227-f71b6276b87d_image.png&quot; data-origin-width=&quot;1212&quot; data-origin-height=&quot;626&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://velog.io/@jakeseo_me/%EC%9E%90%EB%B0%94-%EC%84%9C%EB%B8%94%EB%A6%BF%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90.-%EA%B7%BC%EB%8D%B0-%ED%86%B0%EC%BA%A3%EA%B3%BC-%EC%8A%A4%ED%94%84%EB%A7%81%EC%9D%84-%EC%82%B4%EC%A7%9D-%EA%B3%81%EB%93%A4%EC%9D%B8&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tomcat을 기준으로, 서블릿 인터페이스는 &lt;a href=&quot;https://github.com/apache/tomcat/blob/main/java/jakarta/servlet/http/HttpServlet.java&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HttpServlet&lt;/a&gt;까지 구현이 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, Spring에서는&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt; DispatcherServlet&lt;/b&gt;&lt;/span&gt;까지 이를 그대로 받아서 구현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;이제 다시 주제로 돌아가자.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정리하자면 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;최초에 서버 개발을 위한 Java EE 표준이 나왔을 때는 표준에 포함된 Servlet, JSP등으로 인해 각광을 받았다.&lt;/li&gt;
&lt;li&gt;수많은 서버가 Java EE 표준에 맞추어 어플리케이션 서버를 개발하였으나, EJB 중심의 서버에 대한 불편함과 난이도가 높아, Spring이 등장하였다.&lt;/li&gt;
&lt;li&gt;특히, EJB 없이 개발하는 방법에 대한 내용이 주가 되었으며 그 핵심이 DI 등 현재 Spring에 중심이 되는 컨셉들이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;그럼, 스프링은 무엇을 도와주는가?&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;기존에 어렵던 서버 통신, 트랜젝션과 같은 기능들을 조금의 학습만 한다면, 이제는 잊혀질 정도로 어려웠던 사항을 쉽고 간편하게 개발할 수 있도록 도와주는 프레임워크&lt;/b&gt;&lt;/span&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;결론&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 프레임워크가 주는 의문 두가지,&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;스프링은 무엇을 도와주는가?&lt;/li&gt;
&lt;li&gt;스프링의 사용법은 어떻게 되는가?&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중에서 첫번째, 스프링은 무엇을 도와주는가? 에 대해 알아보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, 다음에는 그 사용법에 대해 알아볼텐데 몇가지 용어 정리가 필요할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IoC, Bean 등의 개념부터 잡고 가도록 하자.&lt;/p&gt;</description>
      <category>Framework/Spring</category>
      <category>Java</category>
      <category>spring</category>
      <category>Spring Framework</category>
      <category>Spring MVC</category>
      <category>SpringBoot</category>
      <category>스프링</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/57</guid>
      <comments>https://koocci-dev.tistory.com/57#entry57comment</comments>
      <pubDate>Fri, 22 Jul 2022 22:50:12 +0900</pubDate>
    </item>
    <item>
      <title>자바스크립트 기초부터 모던 자바스크립트까지 - 생성자편</title>
      <link>https://koocci-dev.tistory.com/56</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : 자바스크립트에서는 생성자를 어떻게 표현하는지 알아본다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://koocci-dev.tistory.com/42?category=1030064&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;앞선 포스트&lt;/a&gt;에서 객체가 어떻게 생성되는지 알아본 적이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 객체 리터럴이 가장 생성하기 쉬운 방식이지만, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Object&lt;/b&gt; &lt;b&gt;생성자 함수&lt;/b&gt;&lt;/span&gt;를 사용해 생성하는 방식에 대해 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;생성자 함수&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;생성자 함수(constructor)&lt;/b&gt;&lt;/span&gt;는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;new 연산자와 함께 호출하여 객체(인스턴스)를 생성하는 함수&lt;/b&gt;&lt;/span&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, 생성자 함수에 의해 생성된 객체를 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;인스턴스(Instance)&lt;/b&gt;&lt;/span&gt;라고 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1658317704966&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const person = new Object();

person.name = 'Lee';
person.sayHello = function() {
    console.log('Hi! My name is ' + this.name);
}

console.log(person); // {name: 'Lee', sayHello: &amp;fnof;}
console.log(person.sayHello()); // Hi! My name is Lee&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트는 Object 생성자 함수 말고도, &lt;b&gt;String, Number, Boolean, Function, Array, Date, RegExp, Promise 등의 빌트인(Built-in) 생성자 함수를 제공&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;객체 리터럴로 생성하는게 훨씬 편하지 않은가?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맞다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;굳이, Object 생성자 함수로 객체를 생성할 필요가 없어 보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 불편한 점이 한가지 떠오른다.&lt;/p&gt;
&lt;pre id=&quot;code_1658318025627&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const circle1 = {
    radius: 5,
    getDiameter() {
        return 2 * this.radius;
    }
};

console.log(circle1.getDiameter()); // 10

const circle2 = {
    radius: 7,
    getDiameter() {
        return 2 * this.radius;
    }
};

console.log(circle2.getDiameter()); // 14&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;객체 리터럴로 생성하는 방식은 &lt;span style=&quot;color: #006dd7;&quot;&gt;단 하나의 객체만 생성&lt;/span&gt;할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이, 데이터 프로퍼티 값만 바뀌었고 구조가 동일한데, 두번이나 작성해야하는 번거로움이 생긴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이를 생성자 함수를 호출하는 것으로 바꿔보자.&lt;/p&gt;
&lt;pre id=&quot;code_1658318236171&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Circle(radius) {
    // 생성자 함수 내부의 this는 생성자 함수가 생성할 인스턴스를 가리킨다.
    this.radius = radius;
    this.getDiameter = function() {
    	return 2 * this.radius;
    };
}

const circle1 = new Circle(5);
const circle2 = new Circle(7);

console.log(circle1.getDiameter()); // 10
console.log(circle2.getDiameter()); // 14&lt;/code&gt;&lt;/pre&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;this&lt;/b&gt;&lt;/span&gt;는 자바스크립트에서 중요한 키워드 중 하나이므로, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;언제 호출되냐에 따라 가리키는 값이 달라진다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 생성자 함수 내부에서는 위 주석처럼 생성자 함수가 생성할 인스턴스를 가리키는 것으로 넘어가고, 이후에 다시 알아보도록 하자.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시, 위 예시로 넘어가서 new 연산자로 인스턴스를 생성하는 것을 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트는 자바와 같은 언어와 다르게 특별한 형식을 가지고 인스턴스를 생성하는 것이 아니라, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;생성자 함수를 정의하고 new 연산자로 호출하면 해당 함수는 생성자 함수로서 동작하며,&amp;nbsp;new 연산자 없이 호출한다면, 일반 함수와 동일하게 동작하게 된다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조금만 더 상세히 생성되는 과정을 작성해보자.&lt;/p&gt;
&lt;pre id=&quot;code_1658318874241&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Circle(radius) {
    // 1. 암묵적으로 빈 객체가 생성되고 this에 바인딩된다.
    console.log(this); // Circle {}
    // 2. this에 바인딩되어 있는 인스턴스를 초기화한다.
    this.radius = radius;
    this.getDiameter = function() {
    	return 2 * this.radius;
    };
    
    // 3. 완성된 인스턴스가 바인딩된 this가 암묵적으로 반환된다.
}

const circle = new Circle(1);
console.log(circle); // Circle {radius: 1, getDiameter: f}&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;향후 생성자 함수가 생성한 인스턴스가 될 빈 객체가 생성된다. 그리고 이 빈 객체(인스턴스)는 this에 바인딩된다. (this가 생성자 함수의 인스턴스를 가리키는 이유)&lt;/li&gt;
&lt;li&gt;생성자 함수에 기술되어 있는 코드가 한 줄씩 실행되어 this에 바인딩되어 있는 인스턴스를 초기화한다. (개발자가 기술한 내용)&lt;/li&gt;
&lt;li&gt;생성자 함수 내부의 처리가 끝나면, 인스턴스가 바인딩된 this가 암묵적으로 반환된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서, 암묵적으로 this가 반환되지만, 명시적으로 객체를 반환하면 암묵적인 this 반환이 무시되며, 원시 값을 반환하면 암묵적인 this값이 반환된다.&lt;b&gt; (생성자 함수 내부에 return문이 반드시 생략되야 하는 이유)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1658319178706&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Circle(radius) {
    this.radius = radius;
    this.getDiameter = function() {
    	return 2 * this.radius;
    };
    
    // return {}; // this를 무시해버리고, {}를 반환한다.
    // return 100; // 100을 무시해버리고, this를 반환한다.
}

const circle = new Circle(1);
console.log(circle); // {} or Circle {radius: 1, getDiameter: f}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;그럼 결국 객체, 함수, 생성자 함수 셋의 관계가 어떻게 되는거지?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수는 객체다. 그렇지만, 모든 객체는 함수가 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 말해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;함수 선언문 또는 함수 표현식으로 정의한&lt;/b&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt; 함수 &lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;i&gt;&lt;u&gt;(이 제한을 놓치지 말자!)&lt;/u&gt;&lt;/i&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;일반적인 함수&lt;/b&gt;&lt;/span&gt;로서 호출할 수도 있고, new 연산자와 함께 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;생성자 함수&lt;/b&gt;&lt;/span&gt;로도 호출할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;함수는 객체이므로, 일반 객체와 동일하게 동작할 수 있다.&lt;/b&gt; 일반 객체가 가지고 있는 내부 슬롯과 내부 메서드를 함수 객체도 가지고 있기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇지만, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;일반 객체는 다르다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;일반 객체는 호출할 수 없지만, 함수는 호출할 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;함수에는 함수 객체만을 위한 [[Environment]], [[FormalParameters]] 같은 내부 슬롯과&lt;span style=&quot;color: #ee2323;&quot;&gt; [[Call]], [[Construct]]&lt;/span&gt; 같은 내부 메서드를 갖고 있기 때문이다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;함수가 일반 함수로서 호출이 되면, Call 메서드가 호출이 되고, new 연산자로 호출이 되면, Constuct가 호출이 되는 것이다.&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1658320015999&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function foo() {};

foo(); // 일반 함수 : [[Call]] 호출

new foo(); // 생성자 함수 : [[Construct]] 호출&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수는 호출할 수 있어야 하므로, [[Call]] 내부 메서드를 무조건 가지고 있다. (Callable이라고 한다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그치만, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;[[Construct]]는 항상 갖고 있는 것은 아니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 일반 함수로서만 호출할 수 있는 함수 객체가 있다는 것이다. (&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;non-constructor&lt;/b&gt;&lt;/span&gt;라고 하며, [[Construct]]가 있다면 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;constructor&lt;/b&gt;&lt;/span&gt;라고 한다.)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;constructor : 함수 선언문, 함수 표현식, 클래스(클래스도 함수다)&lt;/li&gt;
&lt;li&gt;non-constructor : 메서드(ES6 함수 축약 표현), 화살표 함수&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1658320386473&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const arrow = {} =&amp;gt; {};
new arrow(); // TypeError: arrow is not a constructor

const obj = {
	x() {} // ES6 함수 축약 표현으로, 메서드라고 할 때는 ES6의 축약 표현에서만 메서드라고 명명한다.
}

new obj.x(); // TypeError: obj is not a constructor&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;차근히 다 배울 내용이니, 예제로 대신하고 넘어가도록 하자.&lt;/p&gt;
&lt;pre id=&quot;code_1658320630765&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Circle(radius) {
    this.radius = radius;
    this.getDiameter = function() {
    	return 2 * this.radius;
    };
    
}

const circle = Circle(5); // 일반 함수로서 호출하면 어떻게 되는지 보자.
console.log(circle); // undefined

console.log(radius); // 5
console.log(getDiameter()); // 10

console.log(circle.getDiameter()); // Uncaught TypeError: Cannot read properties of undefined (reading 'getDiameter')&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;재밌는 건 마치 생성자 함수처럼 만들어둔 함수를 그냥 일반 함수처럼 호출을 하면 위 예시와 같이 진행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, &lt;b&gt;Circle 함수를 일반 함수로 호출했을 때, &lt;span style=&quot;color: #ee2323;&quot;&gt;this&lt;/span&gt;는 &lt;span style=&quot;color: #ee2323;&quot;&gt;전역 객체&lt;/span&gt; window를 가리키게 되어, 그 값을 쓸 수 있게 된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 전역으로 생성되버리는 것을 막고자 나온 ES6 문법이 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;new.target&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;pre id=&quot;code_1658320872061&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Circle(radius) {
    if(!new.target) {
        return new Circle(radius);
    }
    this.radius = radius;
    this.getDiameter = function() {
    	return 2 * this.radius;
    };
    
}

const circle = Circle(5);
console.log(circle.getDiameter()); // 10&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약, new로 생성되지 않았다면, new.target은 undefined가 되어 위와 같은 형태로 생성자 함수가 동작하도록 설정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;일급 객체는 한번 알고 가자.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 그냥 넘어가긴 했지만, &lt;a href=&quot;https://koocci-dev.tistory.com/43&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이전 포스팅&lt;/a&gt;에서도 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;일급 객체&lt;/b&gt;&lt;/span&gt;를 언급했었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 함수가 객체라고 하는 이유이므로 알아보고 넘어가자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일급 객체에는 조건이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트 함수가 일급 객체 조건을 몇개나 만족하는지 보도록 하자.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;무명의 리터럴로 생성할 수 있다. 즉, 런타임에 생성이 가능하다.&lt;/li&gt;
&lt;li&gt;변수나 자료구조(객체, 배열 등)에 저장할 수 있다.&lt;/li&gt;
&lt;li&gt;함수의 매개변수에 전달할 수 있다.&lt;/li&gt;
&lt;li&gt;함수의 반환값으로 사용할 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1658852733738&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 무명의 리터럴로 생성
const increase = function(num) {
  return ++num;
}

const decrease = function(num) {
  return --num;
}

// 객체에 저장
const predicates = { increase, decrease };

// 매개변수로 함수 전달
// 반환값으로 함수 반환
function makeCounter(predicate) {
  let num = 0;
  return function() {
    num = predicate(num);
    return num;
  };
}

// 매개변수로 함수 전달
const increaser = makeCounter(predicates.increase);
console.log(increaser()); // 1
console.log(increaser()); // 2

// 매개변수로 함수 전달
const decreaser = makeCounter(predicates.decrease);
console.log(decreaser()); // -1
console.log(decreaser()); // -2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 조건을 만족하고 있고, 따라서 자바스크립트에서 함수는 객체다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 말했듯이,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;함수는 일반 객체랑은 다르다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;함수는 호출이 가능하지만, 일반 객체는 호출할 수 없다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;함수 객체에는 고유의 프로퍼티가 있다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;함수 객체의 프로퍼티&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;argument, caller, length, name, prototype 프로퍼티는 모두 함수 객체 고유의 데이터 프로퍼티다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 부분은 별도로 찾아보는 것으로 넘어가도 되지만, prototype 프로퍼티는 한번 보고 넘어가자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;prototype 프로퍼티&lt;/b&gt;&lt;/span&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;생성자 함수로 호출 할 수 있는 함수 객체&lt;/b&gt;&lt;/span&gt;. 즉,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;constructor 만이 소유하는 프로퍼티&lt;/b&gt;&lt;/span&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, non-constructor에는 prototype 프로퍼티가 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;함수가 객체를 생성하는 생성자 함수로 호출될 때, 생성자 함수가 생성할 인스턴스의 프로토타입 객체를 가리킨다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 말하면, 모든 함수는 non-constructor가 아니라면(화살표 함수, 메서드 등)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;생성자 함수로 호출&lt;/b&gt;될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때, 인스턴스가 생성될 수 있고 이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;인스턴스의 프로토타입 객체를 생성자 함수가 prototype이라는 프로퍼티로 가지고 있는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;일반 객체는 생성자 함수가 될 수 없기 때문에, prototype을 갖고 있을 수 없다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;__proto__ 프로퍼티&lt;/b&gt;&lt;/span&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;[[Prototype]] 이라는 내부 슬롯이 가리키는 프로토타입 객체에 접근하기 위한 접근자 프로퍼티&lt;/b&gt;&lt;/span&gt;이며,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;상속&lt;/b&gt;&lt;/span&gt;의 개념이 필요하므로 다음에 설명할 프로토타입에 대해 잘 알아보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;결론&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트에서의 생성자에 대해 알아보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 자바스크립트 생성자와 함수의 차이, 객체 생성의 차이를 좀더 명확히 할 수 있게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 생성자를 토대로, 다음은 프로토타입에 대해 진행해보도록 하자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/javascript</category>
      <category>construct</category>
      <category>constructor</category>
      <category>JavaScript</category>
      <category>new</category>
      <category>객체</category>
      <category>생성자</category>
      <category>자바스크립트</category>
      <category>함수</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/56</guid>
      <comments>https://koocci-dev.tistory.com/56#entry56comment</comments>
      <pubDate>Wed, 20 Jul 2022 21:43:00 +0900</pubDate>
    </item>
    <item>
      <title>자바스크립트 기초부터 모던 자바스크립트까지 - 프로퍼티편</title>
      <link>https://koocci-dev.tistory.com/55</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : 객체 프로퍼티에 대해 알아보자.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체는 자바스크립트의 핵심이다. (함수도 객체다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 토대로, 프로토타입, this 등의 개념으로 확장시켜 나갈 예정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 자바스크립트에서 객체 프로퍼티의 숨은 요소들을 찾아보고, 이후에 함수와 생성자 개념으로 확장시켜 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;객체의 프로퍼티를 다시한번 꺼내보자.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;프로퍼티&lt;/b&gt;&lt;/span&gt;가 무엇인가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://koocci-dev.tistory.com/42?category=1030064&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;기억이 안날 수 있으니 되돌아가보자.&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체 상태를 나타내는 값(Data) 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Key:Value 로 되어 있으며, 객체는 0개 이상의 프로퍼티로 이루어진 집합&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트 엔진은 객체의 프로퍼티를 생성할 때, 기본값으로 자동 정의하는 요소가 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1658237554001&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const person = {a:1};

console.log(Object.getOwnPropertyDescriptors(person));
// a: {value: 1, writable: true, enumerable: true, configurable: true}
// [[Prototype]]: Object&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 이중 대괄호로 되어있는 [[Prototype]]이 보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 객체는 [[Prototype]]이라는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;내부 슬롯&lt;/b&gt;&lt;/span&gt;을 가진다. 내부 슬롯은 자바스크립트 엔진의 내부 로직이므로 원칙적으로 접근할 수 없지만, [[Prototype]]은 __proto__를 통해 간접적으로 접근할 수 있다.&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;내부 슬롯&lt;/b&gt;&lt;/span&gt; : 자바스크립트 엔진의 구현 알고리즘을 설명하기 위해 ECMAScript 사양에서 사용하는 의사 프로퍼티(psudo property)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;내부 메서드&lt;/b&gt;&lt;/span&gt; : 위 설명과 동일한 의사 메서드 (psudo method)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ECMAScript 사양에 등장하는 이중 대괄호로 감싼 이름들이 내부 슬롯과 내부 메서드다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트 엔진에서 실제로 동작하지만, 개발자가 직접 접근할 수 있도록 공개된 프로퍼티는 아니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Object.getOwnPropertyDescriptors&lt;/b&gt;&lt;/span&gt; 라는 메서드로 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;프로퍼티 어트리뷰트&lt;/b&gt;&lt;/span&gt;를 확인해 보고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로퍼티 어트리뷰트 역시, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;자바 스크립트 엔진이 관리하는 내부 상태 값&lt;/b&gt;&lt;/span&gt;이라서 내부 슬롯이지만, 위 메서드로 간접적으로 확인해 본 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 처음으로 돌아가서 자바스크립트 엔진은 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;객체의 프로퍼티를 생성할 때, 기본값으로 프로퍼티 어트리뷰트를 자동 정의한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;프로퍼티에도 종류가 있을까?&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;뭔지 모르겠지만, 프로퍼티라는 걸 조금 까보았더니, 프로퍼티 어트리뷰트라는게 나왔다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그럼 또 다른 이야기로 넘어가서, 프로퍼티에는 2가지 종류가 있다.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;&lt;b&gt;데이터 프로퍼티 (Data Property)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;&lt;b&gt;접근자 프로퍼티 (Accessor Property)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;키와 값으로 구성된 일반적인 프로퍼티&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;자체적으로 값을 갖지 않고 다른 데이터 프로퍼티의 값을 읽거나 저장할 때 호출되는 접근자 함수(Accssor Function)으로 구성된 프로퍼티&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;데이터 프로퍼티&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;데이터 프로퍼티&lt;/b&gt;&lt;/span&gt;는 우리가 일반적으로 확인해본 현재까지의 객체의 프로퍼티로 보면된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, 데이터 프로퍼티는 위에서 살펴보았듯이, 다음과 같은 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;프로퍼티 어트리뷰트&lt;/b&gt;&lt;/span&gt;를 갖는다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 285px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;width: 24.7286%; text-align: center; height: 40px;&quot;&gt;&lt;b&gt;프로퍼티 어트리뷰트&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 21.5892%; text-align: center; height: 40px;&quot;&gt;&lt;b&gt;프로퍼티 디스크립터&lt;/b&gt;&lt;br /&gt;&lt;b&gt;객체의 프로퍼티&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 53.6821%; text-align: center; height: 40px;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 60px;&quot;&gt;
&lt;td style=&quot;width: 24.7286%; text-align: center; height: 60px;&quot;&gt;[[Value]]&lt;/td&gt;
&lt;td style=&quot;width: 21.5892%; text-align: center; height: 60px;&quot;&gt;value&lt;/td&gt;
&lt;td style=&quot;width: 53.6821%; height: 60px;&quot;&gt;프로퍼티 키를 통해 반환되는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;프로퍼티 값&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;값을 변경할 때, [[Value]]를 재할당 하는 것.&lt;br /&gt;프로퍼티가 없을 때는 동적 생성하고 저장한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;width: 24.7286%; text-align: center; height: 40px;&quot;&gt;[[Writable]]&lt;/td&gt;
&lt;td style=&quot;width: 21.5892%; text-align: center; height: 40px;&quot;&gt;writable&lt;/td&gt;
&lt;td style=&quot;width: 53.6821%; height: 40px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;프로퍼티 값&lt;/b&gt;&lt;/span&gt;의 변경 가능 여부를 boolean 값으로 갖는다.&lt;br /&gt;false면, [[Value]]의 값을 변경할 수 없는 읽기 전용으로 만든다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;width: 24.7286%; text-align: center; height: 40px;&quot;&gt;[[Enumerable]]&lt;/td&gt;
&lt;td style=&quot;width: 21.5892%; text-align: center; height: 40px;&quot;&gt;enumerable&lt;/td&gt;
&lt;td style=&quot;width: 53.6821%; height: 40px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;프로퍼티&lt;/b&gt;&lt;/span&gt;의 열거 가능 여부를 boolean 값으로 갖는다.&lt;br /&gt;for...in 이나 Object.keys 사용 가능 여부가 된다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 105px;&quot;&gt;
&lt;td style=&quot;width: 24.7286%; text-align: center; height: 105px;&quot;&gt;[[Configurable]]&lt;/td&gt;
&lt;td style=&quot;width: 21.5892%; text-align: center; height: 105px;&quot;&gt;configurable&lt;/td&gt;
&lt;td style=&quot;width: 53.6821%; height: 105px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;프로퍼티&lt;/b&gt;&lt;/span&gt;의 재정의 가능 여부를 boolean 값으로 갖는다.&lt;br /&gt;false인 경우, 해당 프로퍼티의 삭제, 프로퍼티 어트리뷰트 값의 변경이 금지된다.&lt;br /&gt;[[Writable]]이 True라면, [[Value]]의 변경과 [[Writable]]의 변경만 허용된다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;숨겨진 친구들이 설명된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;객체라는 것은 0개 이상의 프로퍼티의 집합으로 구성되며, 이 중, 데이터 프로퍼티가 생성될 때에는 위와 같은 프로퍼티 어트리뷰트들이 함께 자동 정의가 되는 것&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, 그 설명을 보았을 때, 왜 &lt;b&gt;프로퍼티 어트리뷰트 (속성)&lt;/b&gt;이라고 하는 지 명시적으로 알 수 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;접근자 프로퍼티&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;접근자 프로퍼티&lt;/b&gt;&lt;/span&gt;에서는 또 다른 프로퍼티 어트리뷰트들이 정의된다.&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 285px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;width: 24.7286%; height: 40px;&quot;&gt;&lt;b&gt;프로퍼티 어트리뷰트&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 21.5892%; height: 40px;&quot;&gt;&lt;b&gt;프로퍼티 디스크립터&lt;/b&gt;&lt;br /&gt;&lt;b&gt;객체의 프로퍼티&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 53.6821%; height: 40px;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 60px;&quot;&gt;
&lt;td style=&quot;width: 24.7286%; height: 60px;&quot;&gt;[[Get]]&lt;/td&gt;
&lt;td style=&quot;width: 21.5892%; height: 60px;&quot;&gt;get&lt;/td&gt;
&lt;td style=&quot;width: 53.6821%; height: 60px;&quot;&gt;접근자 프로퍼티를 통해 데이터 프로퍼티 값을 읽을 때 호출되는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;접근자 함수&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;접근자 프로퍼티 키로 프로퍼티 값에 접근하면 프로퍼티 어트리뷰트 [[Get]]의 값, 즉 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;getter 함수&lt;/b&gt;&lt;/span&gt;가 호출되고 그 결과가 프로퍼티 값으로 반환된다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;width: 24.7286%; height: 40px;&quot;&gt;[[Set]]&lt;/td&gt;
&lt;td style=&quot;width: 21.5892%; height: 40px;&quot;&gt;set&lt;/td&gt;
&lt;td style=&quot;width: 53.6821%; height: 40px;&quot;&gt;&lt;span&gt;접근자 프로퍼티를 통해 데이터 프로퍼티 값을 저장할 때 호출되는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;접근자 함수&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;접근자 프로퍼티 키로 프로퍼티 값을 저장하면 프로퍼티 어트리뷰트 [[Set]]의 값, 즉&lt;span style=&quot;color: #ee2323;&quot;&gt; s&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;etter 함수&lt;/b&gt;&lt;/span&gt;가 호출되고 그 결과가 프로퍼티 값으로 저장된다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;width: 24.7286%; height: 40px;&quot;&gt;[[Enumerable]]&lt;/td&gt;
&lt;td style=&quot;width: 21.5892%; height: 40px;&quot;&gt;enumerable&lt;/td&gt;
&lt;td style=&quot;width: 53.6821%; height: 40px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;프로퍼티&lt;/b&gt;&lt;/span&gt;의 열거 가능 여부를 boolean 값으로 갖는다.&lt;br /&gt;for...in 이나 Object.keys 사용 가능 여부가 된다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 105px;&quot;&gt;
&lt;td style=&quot;width: 24.7286%; height: 105px;&quot;&gt;[[Configurable]]&lt;/td&gt;
&lt;td style=&quot;width: 21.5892%; height: 105px;&quot;&gt;configurable&lt;/td&gt;
&lt;td style=&quot;width: 53.6821%; height: 105px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;프로퍼티&lt;/b&gt;&lt;/span&gt;의 재정의 가능 여부를 boolean 값으로 갖는다.&lt;br /&gt;false인 경우, 해당 프로퍼티의 삭제, 프로퍼티 어트리뷰트 값의 변경이 금지된다.&lt;br /&gt;[[Writable]]이 True라면, [[Value]]의 변경과 [[Writable]]의 변경만 허용된다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;접근자 프로퍼티에서는 우리가 흔히 아는 getter, setter 가 자동적으로 정의된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 getter, setter 모두 정의할 수 있고, 하나만 정의할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시로 다시한번 보도록 하자.&lt;/p&gt;
&lt;pre id=&quot;code_1658240171589&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const person = {
  // 데이터 프로퍼티
  firstName: 'Ungmo',
  lastName: 'Lee',
  // 접근자 프로퍼티 (접근자 함수로 구성)
  get fullName() {
    return `${this.firstName} ${this.lastName}`;
  },
  // 접근자 프로퍼티 (접근자 함수로 구성)
  set fullName(name) {
    [this.firstName, this.lastName] = name.split(' ');
  }
};

console.log(person.firstName + ' ' + person.lastName);
// Ungmo Lee

person.fullName = 'Heegun Lee';
console.log(person);
// {firstName: 'Heegun', lastName: 'Lee'}

console.log(person.fullName);
// Heegun Lee

let descriptor = Object.getOwnPropertyDescriptors(person, 'firstName');
console.log(descriptor);
// {firstName: {&amp;hellip;}, lastName: {&amp;hellip;}, fullName: {&amp;hellip;}}
// firstName: {value: 'Heegun', writable: true, enumerable: true, configurable: true}
// fullName: {enumerable: true, configurable: true, get: &amp;fnof;, set: &amp;fnof;}
// lastName: {value: 'Lee', writable: true, enumerable: true, configurable: true}
// [[Prototype]]: Object

descriptor = Object.getOwnPropertyDescriptors(person, 'fullName');
console.log(descriptor);
// {firstName: {&amp;hellip;}, lastName: {&amp;hellip;}, fullName: {&amp;hellip;}}
// firstName: {value: 'Heegun', writable: true, enumerable: true, configurable: true}
// fullName: {enumerable: true, configurable: true, get: &amp;fnof;, set: &amp;fnof;}
// lastName: {value: 'Lee', writable: true, enumerable: true, configurable: true}
// [[Prototype]]: Object&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예시를 통해 프로퍼티에 대해 조금 더 상세히 알아보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;번외로, 흔히 헤깔려하는 __proto__ 와 함수의 prototype은 각각 어떤 프로퍼티인지 알아보자&lt;/p&gt;
&lt;pre id=&quot;code_1658240938737&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Object.getOwnPropertyDescriptor(Object.prototype, '__proto__');
// {enumerable: false, configurable: true, get: &amp;fnof;, set: &amp;fnof;}

Object.getOwnPropertyDescriptor(function(){}, 'prototype');
// {value: {&amp;hellip;}, writable: true, enumerable: false, configurable: false}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;__proto__&lt;/b&gt;&lt;/span&gt; 는 &lt;b&gt;접근자 프로퍼티&lt;/b&gt;이며, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;함수의 prototype&lt;/b&gt;&lt;/span&gt;은&lt;b&gt; 데이터 프로퍼티&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음에 생성자 이야기를 하면서 조금 더 구체적으로 알아갈 것이기 때문에, 참고만 하도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;프로퍼티 어트리뷰트도 설정할 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체는 변경이 가능한 값이기 때문에 재할당 없이 직접 변경할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 프로퍼티는&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;추가, 삭제, 갱신이 가능하며, &lt;/span&gt;&lt;span&gt;프로퍼티 어트리뷰트가 자동 정의가 된다고 하지만, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Object.defineProperty&lt;/b&gt;&lt;/span&gt;나 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Object.defineProperties&lt;/b&gt;&lt;/span&gt;와 같은 메서드를 통해, 그 값을 직접 넣어줄 수도 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;또한, 객체의 변경을 방지할 수 있는데, 다음과 같은 메서드들이 있으니 참고하도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.5%; text-align: center;&quot;&gt;&lt;b&gt;구분&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%; text-align: center;&quot;&gt;&lt;b&gt;메서드&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%; text-align: center;&quot;&gt;&lt;b&gt;프로퍼티&lt;/b&gt;&lt;br /&gt;&lt;b&gt;추가&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%; text-align: center;&quot;&gt;&lt;b&gt;프로퍼티&lt;/b&gt;&lt;br /&gt;&lt;b&gt;삭제&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%; text-align: center;&quot;&gt;&lt;b&gt;프로퍼티&lt;/b&gt;&lt;br /&gt;&lt;b&gt;읽기&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%; text-align: center;&quot;&gt;&lt;b&gt;프로퍼티&lt;/b&gt;&lt;br /&gt;&lt;b&gt;쓰기&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%; text-align: center;&quot;&gt;&lt;b&gt;프로퍼티 &lt;br /&gt;어트리뷰트&lt;/b&gt;&lt;br /&gt;&lt;b&gt;재정의&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;객체 확장 금지&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;Object.preventExtensions&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;X&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;O&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;O&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;O&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;O&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;객체 밀봉&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;Object.seal&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;X&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;X&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;O&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;O&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;X&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;객체 동결&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;Object.freeze&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;X&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;X&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;O&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;X&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;X&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;다만, 중첩된 객체에 대해서는 동결이 안된다. 즉, &lt;b&gt;재귀적으로 동결&lt;/b&gt; 시켜주어야 한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/javascript</category>
      <category>JavaScript</category>
      <category>property</category>
      <category>Prototype</category>
      <category>자바스크립트</category>
      <category>프로토타입</category>
      <category>프로퍼티</category>
      <category>프로퍼티 어트리뷰트</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/55</guid>
      <comments>https://koocci-dev.tistory.com/55#entry55comment</comments>
      <pubDate>Tue, 19 Jul 2022 23:39:27 +0900</pubDate>
    </item>
    <item>
      <title>자바 기초부터 모던 자바까지 - 스트림(stream)편</title>
      <link>https://koocci-dev.tistory.com/54</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : 람다를 기준으로 스트림 문법을 이해한다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 포스팅으로, JAVA가 인터페이스를 통해 람다식을 어떻게 만들어 왔는지 히스토리를 보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, java에서는 &lt;a href=&quot;https://koocci-dev.tistory.com/48?category=1012334&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;앞서 배운&lt;/a&gt; 함수형 인터페이스의 주요 표현들인 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Consumer, Function, Predicate, Supplier&lt;/b&gt;&lt;/span&gt;들이 어떻게 사용되어 지는지 Stream을 보면서 이해해보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Stream(스트림) 부터 알아보자.&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Stream(스트림)&lt;/b&gt;&lt;/span&gt;이라는 단어는 어떤 &lt;b&gt;데이터의 흐름&lt;/b&gt;을 뜻한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히, java.io에서는 I/O 프로그래밍을 사용하는 클래스 명에 Stream이라는 단어를 사용하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나, 지금 배우고자 하는 Stream은 &lt;b&gt;주로 컬렉션 프레임워크나 이와 유사한 형태의 데이터를 처리할 때 도움을 줄 수 있는, 자바 8에서 새롭게 제안한 API다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Stream API의 주 목적&lt;/b&gt;&lt;/span&gt;은 &lt;b&gt;람다 표현식과 메서드 참조 등의 기능과 결합해서 매우 복잡하고 어려운 데이터 처리 작업을 쉽게 처리하도록 도와주는 것&lt;/b&gt;에 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1657955860719&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Integer[] intArr = new Integer[] {1,2,3,4,4,4,5,7,8,8,8,8,8};
List&amp;lt;Integer&amp;gt; numberList = Arrays.asList(intArr);

for(int i = 0; i &amp;lt; numberList.size(); i++) {
    System.out.println(numberList.get(i));
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드의 문제점은 인덱스 변수인 i를 사용한 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론, 초창기 방식이지만 여전히 보편적으로 많이 사용하는 방법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, &lt;b&gt;매번 반복되는 코드이면서도 명확성이 흐려지고, List의 끝지점을 알기 위해서는 항상 i가 List 크기와 비교하는 작업이 선행&lt;/b&gt;된다.&lt;/p&gt;
&lt;pre id=&quot;code_1657956045339&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;for(Iterator&amp;lt;Integer&amp;gt; iter = numberList.iterator(); iter.hasNext();) {
    System.out.println(iter.next());
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조금 깔끔해졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Iterator를 통해 별도로 변숫값을 증가 시키는 로직을 삭제하고, next 메서드를 활용하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, 매번 Iterator 객체를 생성하고 for 루프를 작성해야 하는 번거로움은 여전히 유사하게 남아있다.&lt;/p&gt;
&lt;pre id=&quot;code_1657956391241&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;for(Integer value : numberList) {
	System.out.println(value);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;for each 구문은 자바5에서 새롭게 도입된 것으로 훨씬 깔끔해졌다.&lt;/p&gt;
&lt;pre id=&quot;code_1657956417381&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;numberList.forEach(System.out::println);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 스트림 API를 통해 바로 결과를 출력하는 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단지 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;메서드 참조&lt;/b&gt;&lt;/span&gt;로 println을 전달하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;스트림을 이용한 컬렉션 프레임워크의 가장 큰 특징&lt;/b&gt;&lt;/span&gt;은 기존 컬렉션 프레임워크처럼 개발자가 정의한 외부 코드로 for 루프를 실행하는 것이 아니라 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;스트림 내부에서 개발자가 정의한 코드가 반복적으로 실행된다는 것&lt;/b&gt;&lt;/span&gt;을 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, 개발자가 별도로 for 루프 구문을 만들고 인덱스 변수를 처리하거나 Iterator 객체를 생성하는 반복적이고 에러 확률을 높이는 수고를 하지 않아도 된다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;스트림 인터페이스&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;java.util.stream에는 자바 8의 스트림에 대해 정의되어 있다. 대부분 interface로 되어 있고, 몇가지 Util성 클래스가 있는 걸 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;스트림 API가 주로 인터페이스로 구성되어 있는 이유&lt;/b&gt;&lt;/span&gt;는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;실질적인 구현체는 데이터의 원천에 해당하는 컬렉션 프레임워크 기반의 클래스에 위임하고 있기 때문&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 앞서 말했듯이 스트림은 람다 표현식이나 메서드 참조를 통해 구체적인 구현체를 전달받아 동작하기 때문에 함수형 인터페이스와 관련이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조금 세부적으로 들어가면, 스트림에서 가장 기본이 되는 인터페이스는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;BaseStream&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;선언문 부분만 간단히 보면, 다음과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1657980450536&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface BaseStream&amp;lt;T, S extends BaseStream&amp;lt;T, S&amp;gt;&amp;gt; extends AutoCloseable {
    Iterator&amp;lt;T&amp;gt; iterator(); // 스트림 항목에 대한 인덱스를 Iterator 객체로 리턴
    Spliterator&amp;lt;T&amp;gt; spliterator(); // 스트림이 포함하고 있는 항목들을 분할하기 위한 Spliterator 객체 리턴
    boolean isParallel(); // 스트림이 병렬로 실행되었는지 여부를 리턴
    S sequential(); // 절차적으로 처리 가능한 스트림을 리턴
    S parallel(); // 병렬 처리 가능한 스트림을 리턴
    S unordered(); // 데이터가 정렬되지 않은 스트림을 리턴
    @Override
    void close(); // 스트림 종료. 해당 스트림의 파이프라인과 연결되어 있는 모든 핸들러를 종료
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;T: 스트림에서 처리할 데이터의 타입 (요소의 타입)&lt;/li&gt;
&lt;li&gt;S: BaseStream을 구현한 스트림 구현체. 스트림을 자동으로 종료하기 위한 AutoCloseable도 구현되어야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BaseStream은 일반적으로 개발자가 쓰지 않고, 이를 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;상속한 Stream 인터페이스&lt;/b&gt;&lt;/span&gt;를 주로 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 자바 API 문서에는 이 Stream 인터페이스에 대한 내용은 설명이 많고, 제공하는 메서드도 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 중 대표적인 것만 먼저 보도록 하자.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.4186%; text-align: center;&quot;&gt;&lt;b&gt;메서드&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 85.5814%; text-align: center;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.4186%; text-align: center;&quot;&gt;&lt;b&gt;concat&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 85.5814%;&quot;&gt;입력 파라미터로 전달된 두 개의 스트림을 하나의 스트림으로 합친다. 합쳐진 스트림의 데이터는 첫번째 스트림을 먼저 처리하고 두번째 스트림을 뒤이어서 처리한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.4186%; text-align: center;&quot;&gt;&lt;b&gt;collect&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 85.5814%;&quot;&gt;스트림의 항목들을 컬렉션 프레임워크 기반의 객체로 리턴한다. 주로 List 객체로 리턴해서 많이 사용한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.4186%; text-align: center;&quot;&gt;&lt;b&gt;count&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 85.5814%;&quot;&gt;스트림에 포함된 항목의 수를 리턴한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.4186%; text-align: center;&quot;&gt;&lt;b&gt;distinct&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 85.5814%;&quot;&gt;중복된 항목을 제외하고 스트림 객체를 만들어서 리턴한다. 이 기능을 사용하기 위해서는 항목의 equals 메서드가 정확히 정의되어 있어야 한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.4186%; text-align: center;&quot;&gt;&lt;b&gt;filter&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 85.5814%;&quot;&gt;스트림 항목을 필터링한다. 필터 조건은 Function 인터페이스를 위한 람다 표현식 혹은 메서드 참조를 전달한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.4186%; text-align: center;&quot;&gt;&lt;b&gt;forEach&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 85.5814%;&quot;&gt;스트림 연산을 종료하고 최종 결과를 처리하기 위한 메서드다. 종료 연산의 일종이다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.4186%; text-align: center;&quot;&gt;&lt;b&gt;limit&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 85.5814%;&quot;&gt;특정 개수만큼만 항목을 처리한다. 제한된 개수 한도에서 새로 생성한 스트림을 리턴한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.4186%; text-align: center;&quot;&gt;&lt;b&gt;reduce&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 85.5814%;&quot;&gt;람다 표현식을 기반으로 데이터를 소모하고 그 결과를 리턴하는 최종 연산이다. 다른 메서드가 특정한 기능에 제한적으로 지원되는 반면, 이 메서드는 다양하게 활용될 수 있다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.4186%; text-align: center;&quot;&gt;&lt;b&gt;skip&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 85.5814%;&quot;&gt;스트림 처리중 특정한 숫자만큼 항목을 건너 뛴다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.4186%; text-align: center;&quot;&gt;&lt;b&gt;sorted&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 85.5814%;&quot;&gt;스트림에 포함된 항목을 정렬한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.4186%; text-align: center;&quot;&gt;&lt;b&gt;toArray&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 85.5814%;&quot;&gt;스트림의 항목들을 배열로 만들어서 리턴한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주의할 점은 &lt;b&gt;BaseStream 인터페이스와 Stream 인터페이스에 정의된 메서드들의 리턴 타입이 대부분 &lt;span style=&quot;color: #ee2323;&quot;&gt;Stream(정확히는 제네릭에서 정의한 Stream 인터페이스의 구현 객체)이거나 void&lt;/span&gt; 인 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리턴 타입이 Stream인 메서드들은 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;리턴 결과를 통해, 데이터를 중간에 변형하거나 필터링한 후 다시 Stream 객체를 만들어서 리턴&lt;/b&gt;&lt;/span&gt;한다. 이러한 작업을 반복적으로 할 수 있고, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;중간 연산 메서드&lt;/b&gt;&lt;/span&gt;라고 한다.&lt;/li&gt;
&lt;li&gt;리턴 타입이 void인 메서드들은 주로 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Stream을 이용해서 데이터를 최종적으로 소비&lt;/b&gt;&lt;/span&gt;한다. 이를 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;최종 연산 메서드&lt;/b&gt;&lt;/span&gt;라고 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 중요한 점은 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Stream 객체는 불변성이 특징&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;Stream 객체의 메서드 호출 결과로 리턴 받은 Stream 객체는 원천 데이터를 수정한 것이 아니라 완전히 새롭게 생성한 데이터&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 만들어진 이유는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;중간 연산 작업과 함께 병렬 처리가 가능하기 때문에 데이터 정합성을 확보하기 위해서&lt;/b&gt;&lt;/span&gt;이며, 스트림 API 뿐아니라, 자바8 이후에 소개된 대부분의 API에서 공통적으로 보이는 특징이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스트림 연산 파이프라인&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스트림의 중간 연산자와 최종 연산자는&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt; 함수형 인터페이스&lt;/b&gt;&lt;/span&gt;를 기반으로 하고 있어서, 개발자가 &lt;b&gt;람다 표현식으로 동작을 정의할 수 있다는 장점&lt;/b&gt;이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 이미지를 보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1640&quot; data-origin-height=&quot;539&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3stmu/btrHPKm5HMz/jfYdOtK2P5TSjKnDSwPcu0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3stmu/btrHPKm5HMz/jfYdOtK2P5TSjKnDSwPcu0/img.png&quot; data-alt=&quot;스트림 연산&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3stmu/btrHPKm5HMz/jfYdOtK2P5TSjKnDSwPcu0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3stmu%2FbtrHPKm5HMz%2FjfYdOtK2P5TSjKnDSwPcu0%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1640&quot; height=&quot;539&quot; data-origin-width=&quot;1640&quot; data-origin-height=&quot;539&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;스트림 연산&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;329&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cskG5I/btrHOS0dAPz/lUYK12UT3H2lIQlGMeXzZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cskG5I/btrHOS0dAPz/lUYK12UT3H2lIQlGMeXzZK/img.png&quot; data-alt=&quot;스트림 연산 파이프라인&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cskG5I/btrHOS0dAPz/lUYK12UT3H2lIQlGMeXzZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcskG5I%2FbtrHOS0dAPz%2FlUYK12UT3H2lIQlGMeXzZK%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1536&quot; height=&quot;329&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;329&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;스트림 연산 파이프라인&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스트림 API 기반의 연산 작업을 선호하는 이유는 리눅스의 파이프라인과 유사하게 &lt;b&gt;기능을 조합할 수 있다&lt;/b&gt;는 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, 그 과정에서 우리가 앞서 배운 함수형 인터페이스들이 기반이 되고 있는 것을 볼 수 있다.&lt;/p&gt;</description>
      <category>Programming/Java</category>
      <category>Java</category>
      <category>Stream</category>
      <category>스트림</category>
      <category>자바</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/54</guid>
      <comments>https://koocci-dev.tistory.com/54#entry54comment</comments>
      <pubDate>Sat, 16 Jul 2022 23:33:46 +0900</pubDate>
    </item>
    <item>
      <title>[java] Number of Islands</title>
      <link>https://koocci-dev.tistory.com/53</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;[참고문제] :&lt;span&gt;&lt;span&gt; &lt;a href=&quot;https://leetcode.com/problems/number-of-islands/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://leetcode.com/problems/number-of-islands/&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1657954049212&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Number of Islands - LeetCode&quot; data-og-description=&quot;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&quot; data-og-host=&quot;leetcode.com&quot; data-og-source-url=&quot;https://leetcode.com/problems/number-of-islands/&quot; data-og-url=&quot;https://leetcode.com/problems/number-of-islands/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/rVikX/hyO7w1NnKd/58X9TkvCu1vZvrrncxDnG1/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/number-of-islands/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://leetcode.com/problems/number-of-islands/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/rVikX/hyO7w1NnKd/58X9TkvCu1vZvrrncxDnG1/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Number of Islands - LeetCode&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;leetcode.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제 풀이&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DFS/BFS 문제이고, 연결된 구간의 갯수를 찾는 문제다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히나, 전형적인 문제라 BFS로 풀어보기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;생각의 흐름 -&amp;nbsp; 방문 여부는 누적되도 된다.&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전에 풀었던 문제는 중복적으로 체크하면 안되었기 때문에, 다시 돌려주는 방법을 사용했지만 이번에는 중복해서 활용해야만 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;생각의 흐름 - Count에 대한 분리를 잘하자.&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외딴 섬이 몇개인지 알아봐야 하므로, Count 측정 지점을 잘 체크해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 새로운 '1'이 나오면 count를 올리고, 인접한 상,하,좌,우에 '1'인 지점을 bfs로 모두 방문했다고 체크해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래야 외딴 섬의 갯수가 정확하게 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1656742664649&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution {
    public int numIslands(char[][] grid) {
        int m = grid.length;
        int n = grid[0].length;
        int count = 0;
        boolean[][] isVisited = new boolean[m][n];

        for(int i = 0; i &amp;lt; m; i++) {
            for(int j = 0; j &amp;lt; n; j++) {
                if(!isVisited[i][j] &amp;amp;&amp;amp; grid[i][j] == '1') {
                    count ++;
                    // BFS
                    Queue&amp;lt;Node&amp;gt; que = new LinkedList&amp;lt;&amp;gt;();
                    que.add(new Node(i,j));
                    while(!que.isEmpty()) {
                        Node tmp = que.poll();
                        if(isVisited[tmp.row][tmp.col] || grid[tmp.row][tmp.col] != '1')
                            continue;
                        isVisited[tmp.row][tmp.col] = true;
                        if(tmp.row != 0) {
                            que.add(new Node(tmp.row-1, tmp.col));
                        }
                        if(tmp.row != m-1) {
                            que.add(new Node(tmp.row+1, tmp.col));
                        }
                        if(tmp.col != 0) {
                            que.add(new Node(tmp.row, tmp.col-1));
                        }
                        if(tmp.col != n-1) {
                            que.add(new Node(tmp.row, tmp.col+1));
                        }
                    }
                }
            }
        }

        return count;
    }
    class Node {
        int row;
        int col;
        Node(int row, int col) {
            this.row = row;
            this.col = col;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm</category>
      <category>Algorithm</category>
      <category>leetcode</category>
      <category>Number of Islands</category>
      <category>알고리즘</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/53</guid>
      <comments>https://koocci-dev.tistory.com/53#entry53comment</comments>
      <pubDate>Sat, 16 Jul 2022 15:52:41 +0900</pubDate>
    </item>
    <item>
      <title>[java] Word Search</title>
      <link>https://koocci-dev.tistory.com/52</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;[참고문제] :&lt;span&gt;&lt;span&gt; &lt;a href=&quot;https://leetcode.com/problems/word-search/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://leetcode.com/problems/word-search/&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1657951305147&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Word Search - LeetCode&quot; data-og-description=&quot;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&quot; data-og-host=&quot;leetcode.com&quot; data-og-source-url=&quot;https://leetcode.com/problems/word-search/&quot; data-og-url=&quot;https://leetcode.com/problems/word-search/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/12Dhl/hyO5GdSV1V/CdkPiwLHSCeelU86g0oZU0/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260,https://scrap.kakaocdn.net/dn/b5C74d/hyO7BWj2ca/LwU7mFKaseIpmwogsovPn0/img.jpg?width=322&amp;amp;height=242&amp;amp;face=0_0_322_242,https://scrap.kakaocdn.net/dn/qHyhQ/hyO5LTNE2E/K1AfvaValVAGy25gSkRMa0/img.jpg?width=322&amp;amp;height=242&amp;amp;face=0_0_322_242&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/word-search/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://leetcode.com/problems/word-search/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/12Dhl/hyO5GdSV1V/CdkPiwLHSCeelU86g0oZU0/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260,https://scrap.kakaocdn.net/dn/b5C74d/hyO7BWj2ca/LwU7mFKaseIpmwogsovPn0/img.jpg?width=322&amp;amp;height=242&amp;amp;face=0_0_322_242,https://scrap.kakaocdn.net/dn/qHyhQ/hyO5LTNE2E/K1AfvaValVAGy25gSkRMa0/img.jpg?width=322&amp;amp;height=242&amp;amp;face=0_0_322_242');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Word Search - LeetCode&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;leetcode.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;figure id=&quot;og_1656742664648&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Container With Most Water - LeetCode&quot; data-og-description=&quot;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&quot; data-og-host=&quot;leetcode.com&quot; data-og-source-url=&quot;https://leetcode.com/problems/container-with-most-water/&quot; data-og-url=&quot;https://leetcode.com/problems/container-with-most-water/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bohbn4/hyOYqggcRu/EtodHWcre7oElG8mo2iD70/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260,https://scrap.kakaocdn.net/dn/c3A7Ll/hyOYncL4fh/Ghh5aTJMGcPzfHPonnkZ70/img.png?width=2104&amp;amp;height=2021&amp;amp;face=0_0_2104_2021,https://scrap.kakaocdn.net/dn/cnjvt5/hyOYpPbZol/QJLOKI4BKC9eqADkivZZR0/img.png?width=2104&amp;amp;height=2021&amp;amp;face=0_0_2104_2021&quot;&gt;&lt;/figure&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제 풀이&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전형적인 DFS 문제다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;생각의 흐름 - Recursive하게 풀어보자.&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DFS는 Stack을 사용하거나, Recursive로 풀면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 Stack을 사용하기 보단, 파라미터가 많아 Recursive하게 풀어주면 좀 더 편하게 풀 수 있을 것으로 생각했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;생각의 흐름 - 좌,우,상,하를 체크하자.&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좌,우,상,하 방향으로 갈 수 있으니 적절한 예외처리와 최종적으로 True가 반환되는 경우를 잘 체크해서 4가지 방향 중 한 방향으로라도 성공하면 True를 제공하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;생각의 흐름 - Visit 체크를 하자?&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방문 여부를 항상 체크해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;java에서는 Call By Value지만, 객체에 대한 주소위치값을 전달하기 때문에 주의해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 visit만 넘기게 되면, 이전에 지나갔던 기록도 고스란히 남아있게 된다. (다시 봐야 하는데 마치 이미 확인한 길인 것처럼)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, 들어갔다가 나올때는 다시 false를 해주자.&lt;/p&gt;
&lt;pre id=&quot;code_1656742664649&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution {
    public boolean exist(char[][] board, String word) {
        int M = board.length;
        int N = board[0].length;
        boolean result = false;

        boolean[][] isVisited = new boolean[M][N];

        for(int i = 0; i &amp;lt; M; i++) {
            for(int j = 0; j &amp;lt; N; j++) {
                if(word.charAt(0) == board[i][j])
                    result = result || dfs(isVisited, board,word.substring(1),i,j,M,N);
                if(result)
                    return true;
            }
        }
        return false;
    }
    
    public boolean dfs(boolean[][] isVisited, char[][] board, String word, int row, int col, int M, int N) {
        if(word.isEmpty())
            return true;
        isVisited[row][col] = true;
        boolean result = false;
        if(col != 0) {
            if(!isVisited[row][col-1] &amp;amp;&amp;amp; board[row][col-1] == word.charAt(0))
                result = result || dfs(isVisited,board, word.substring(1), row, col-1, M, N);
        }

        if(col != N-1) {
            if(!isVisited[row][col+1] &amp;amp;&amp;amp; board[row][col+1] == word.charAt(0))
                result = result || dfs(isVisited,board, word.substring(1), row, col+1, M, N);
        }

        if(row != 0) {
            if(!isVisited[row-1][col] &amp;amp;&amp;amp; board[row-1][col] == word.charAt(0))
                result = result || dfs(isVisited,board, word.substring(1), row-1, col, M, N);
        }

        if(row != M-1) {
            if(!isVisited[row+1][col] &amp;amp;&amp;amp; board[row+1][col] == word.charAt(0))
                result = result || dfs(isVisited,board, word.substring(1), row+1, col, M, N);
        }
        
        isVisited[row][col] = false;
        return result;
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm</category>
      <category>Algorithm</category>
      <category>leetcode</category>
      <category>Word Search</category>
      <category>알고리즘</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/52</guid>
      <comments>https://koocci-dev.tistory.com/52#entry52comment</comments>
      <pubDate>Sat, 16 Jul 2022 15:08:50 +0900</pubDate>
    </item>
    <item>
      <title>[java] Minimum Size Subarray Sum</title>
      <link>https://koocci-dev.tistory.com/51</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;[참고문제] :&lt;span&gt;&lt;span&gt; &lt;a href=&quot;https://leetcode.com/problems/minimum-size-subarray-sum/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://leetcode.com/problems/minimum-size-subarray-sum/&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1657947964039&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Minimum Size Subarray Sum - LeetCode&quot; data-og-description=&quot;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&quot; data-og-host=&quot;leetcode.com&quot; data-og-source-url=&quot;https://leetcode.com/problems/minimum-size-subarray-sum/&quot; data-og-url=&quot;https://leetcode.com/problems/minimum-size-subarray-sum/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/GzUrA/hyO7HIXBHq/UOK4NoS1mMcvktu0kiekd1/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/minimum-size-subarray-sum/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://leetcode.com/problems/minimum-size-subarray-sum/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/GzUrA/hyO7HIXBHq/UOK4NoS1mMcvktu0kiekd1/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Minimum Size Subarray Sum - LeetCode&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;leetcode.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제 풀이&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연속된 subArray를 어떻게 관리할지가 포인트인 문제다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;생각의 흐름 - 한번만 배열을 읽자&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 문제를 풀면서 달라질 수 있지만, 일단 주어진 nums배열은 한번만 읽는게 중요할 것으로 보였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;생각의 흐름 - SubArray를 어떻게 관리하지?&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 단지 배열에 저장하자고 생각했는데, sum을 계산한 배열이 필요할 거라 생각했다. 그래야 배열을 다시 읽어 합치는 과정을 안해도 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 최소 길이를 찾아야 하니, 시작과 끝 지점을 알아야 하는데, 처음에는 queue에 저장하고 길이를 알아볼까 했지만, 그러면 계산된 sum 처리가 어려워서 left, right 인덱스를 관리하자고 생각했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;생각의 흐름 - 언제 left와 right를 늘리거나 줄여주는가?&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;right는 자연스럽게 배열을 읽어나가면서 늘리면 된다. 내가 필요한건 결과값인 minLength이고, left와 right 둘다 길이 계산에서 필요한 값이기 때문에 minLength계산만 되면 어떻게 되든 상관없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;right가 문제가 아니라 left가 문제다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 sumArr에 대해, 현재까지 더해진 값에 left를 늘려주며 그 값을 빼면, 앞에서부터 left 까지 누적된 sumArr를 뺄 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 값을 통해, sum 값이 target보다 크거나 같게되는 지점을 찾는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1656742664649&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public int minSubArrayLen(int target, int[] nums) {
    int result = 0;
    int left = 0;
    int right = 0;
    int[] sumArr = new int[nums.length];
    Arrays.fill(sumArr, 0);
    int minLength = Integer.MAX_VALUE;

    for(int i = 0; i &amp;lt; nums.length; i++) {
        if(nums[i] &amp;gt;= target) {
            return 1;
        }

        if(i == 0) {
            sumArr[i] = nums[i];
        } else {
            sumArr[i] = sumArr[i-1] + nums[i];
        }
        right ++;

        if(sumArr[i] &amp;gt;= target) {
            while(left &amp;lt; right) {
                if((sumArr[i] - sumArr[left]) &amp;gt;= target) {
                    left ++;
                } else {
                    break;
                }
            }

            minLength = Math.min(minLength, right - left);
        }
    }

    if(minLength != Integer.MAX_VALUE)
        result = minLength;

    return result;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm</category>
      <category>Algorithm</category>
      <category>leetcode</category>
      <category>Minimum Size Subarray Sum</category>
      <category>알고리즘</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/51</guid>
      <comments>https://koocci-dev.tistory.com/51#entry51comment</comments>
      <pubDate>Sat, 16 Jul 2022 14:12:55 +0900</pubDate>
    </item>
    <item>
      <title>[java] Find Minimum in Rotated Sorted Array</title>
      <link>https://koocci-dev.tistory.com/50</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;[참고문제] :&lt;span&gt;&lt;span&gt; &lt;a href=&quot;https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1657806257219&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Find Minimum in Rotated Sorted Array - LeetCode&quot; data-og-description=&quot;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&quot; data-og-host=&quot;leetcode.com&quot; data-og-source-url=&quot;https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/&quot; data-og-url=&quot;https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/byBBjY/hyO5I2zc3s/bCYUEtvO0KyGl5BDfqwY01/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/byBBjY/hyO5I2zc3s/bCYUEtvO0KyGl5BDfqwY01/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Find Minimum in Rotated Sorted Array - LeetCode&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;leetcode.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제 풀이&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 정렬되어 있지만, Rotate되어있는 배열에 대해 최소값을 찾는 문제다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;생각의 흐름 - 양쪽에서 바라보자.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 정렬이 되어 있으니, 최소값을 찾는 것에만 집중해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 중에서도 양쪽에서 찾아 나가는 방법이 포인트라고 생각된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;값이 더이상 증가하지 않거나(왼쪽에서) 줄어들지 않는 곳(오른쪽에서)이 최소값이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;생각의 흐름 - 그런 부분이 없다면?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 당연히 첫번째 값이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1656742664649&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution {
    public int findMin(int[] nums) {
        int start = 0;
        int end = nums.length -1;
        while(start &amp;lt; end) {
            if(start+1 &amp;lt; nums.length) {
                if(nums[start] &amp;lt; nums[start+1]) {
                    start ++;
                } else {
                    return nums[start+1];
                }
            }
            
            if(end-1 &amp;gt;= 0) {
                if(nums[end-1] &amp;lt; nums[end]) {
                    end --;
                } else {
                    return nums[end];
                }
            }
        }
        return nums[0];
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm</category>
      <category>Algorithm</category>
      <category>Java</category>
      <category>leetcode</category>
      <category>알고리즘</category>
      <category>자바</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/50</guid>
      <comments>https://koocci-dev.tistory.com/50#entry50comment</comments>
      <pubDate>Thu, 14 Jul 2022 22:46:54 +0900</pubDate>
    </item>
    <item>
      <title>자바스크립트 기초부터 모던 자바스크립트까지 - 스코프편</title>
      <link>https://koocci-dev.tistory.com/49</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : 자바스크립트에서 스코프가 무엇인지 이해한다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 javascript라는 언어만 사용하다가, 어느 순간부터 공부를 하려고 하다보면, 언제나 맞닥드리는 부분이 스코프(Scope)다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;게다가 ES6에서 꽤 큰 변화가 있었기에, 그리고 javascipt만의&amp;nbsp; 동작이 어떻게 되는지 알고싶다면 반드시 알아야 할 개념이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스코프(Scope)가 뭐지?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://koocci-dev.tistory.com/43?category=1030064&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이전 포스팅&lt;/a&gt;에서 함수의 매개변수의 스코프에 대해 잠깐 다루었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매개변수를 참조할 수 있는 유효범위, 즉&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt; 매개변수&lt;/b&gt;&lt;/span&gt;의 스코프는 &lt;b&gt;함수의 몸체 내부&lt;/b&gt;로 한정된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;변수&lt;/b&gt;&lt;/span&gt;는 자신이 선언된 위치에 의해 자신이 유효한 범위, 즉 &lt;b&gt;다른 코드가 변수 자신을 참조할 수 있는 범위&lt;/b&gt;가 결정된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정리해 보면, &lt;b&gt;모든 식별자(변수 이름, 함수 이름, 클래스 이름 등)는 자신이 선언된 위치에 의해 다른 코드가 식별자 자신을 참조할 수 있는 유효 범위가 결정&lt;/b&gt;된다. 이를 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;스코프&lt;/b&gt;&lt;/span&gt;라 한다. 즉, 스코프는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;식별자가 유효한 범위&lt;/b&gt;&lt;/span&gt;를 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 예제를 보도록 하자.&lt;/p&gt;
&lt;pre id=&quot;code_1657038460966&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var x = 'global';

function foo() {
	var x = 'local';
    console.log(x); // 1
}

foo();

console.log(x); // 2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트 엔진은 스코프를 통해 &lt;b&gt;어떤 변수를 참조해야 할 것인지&lt;/b&gt; 결정한다. 또한 코드를 실행할때 &lt;b&gt;코드의 &lt;span style=&quot;color: #ee2323;&quot;&gt;context(문맥)&lt;/span&gt;&lt;/b&gt;을 고려한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&quot;코드가 어디서 실행되며 주변에 어떤 코드가 있는지?&quot;&lt;/i&gt;를 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;렉시컬 환경(lexical environment)&lt;/b&gt;&lt;/span&gt;라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 코드의 문맥(context)은 렉시컬 환경으로 이루어진다. 이를 구현한 것이 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;실행 컨텍스트(execution context)&lt;/b&gt;&lt;/span&gt;이며, 모든 컨텍스트에서 평가되고 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스코프의 종류&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드는 전역과 지역으로 나누어진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수는 자신이 선언된 위치(전역 혹은 지역)에 의해 자신의 유효 범위인 스코프가 결정된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;전역 변수는 어디서든지 참조할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 전역 지역에는 전역 스코프를 만들고, 지역에는 지역 스코프를 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전역은 코드의 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;가장 바깥 영역&lt;/b&gt;&lt;/span&gt;을 말하며, 지역은&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt; 함수 몸체 내부&lt;/b&gt;&lt;/span&gt;를 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지역 변수는 &lt;b&gt;자신의 지역 스코프와 하위 지역 스코프에서 유효&lt;/b&gt;하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스코프 체인&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중첩 함수(Nested Function)의 존재는 지역 스코프의 중첩과 이어진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 함수는 중첩될 수 있으므로, 함수의 지역 스코프도 중첩될 수 있다. 즉, 계층적 구조를 가질 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;스코프가 계층적으로 연결된 것&lt;/b&gt;&lt;/span&gt;을 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;스코프 체인&lt;/b&gt;&lt;/span&gt;이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수를 참조할 때 자바스크립트 엔진은 스코프 체인을 통해 &lt;b&gt;변수를 참조하는 코드의 스코프에서 시작&lt;/b&gt;하여 &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;상위 스코프 방향&lt;/span&gt;으로 이동하여 선언된 변수를 검색&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스코프 체인은 물리적인 실체로 존재한다. 자바스크립트 엔진은 코드(전역 코드와 함수 코드)를 실행하기에 앞서 렉시컬 환경을 실제로 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수 선언이 실행되면 변수 식별자가 이 자료구조(렉시컬 환경)에 키로 등록되고, 변수 할당이 일어나면 이 자료구조의 변수 식별자에 해당하는 값을 변경한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스코프 체인은 &lt;b&gt;실행 컨텍스트의 렉시컬 환경을 단방향으로 연결한 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전역 렉시컬 환경은 코드가 로드되면 곧바로 생성되고 함수의 렉시컬 환경은 함수가 호출되면 곧바로 생성된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, &lt;b&gt;상위 스코프에서 유효한 함수는 하위 스코프에서 자유롭게 참조가 가능하지만, 하위 스코프에서 유효한 변수를 상위 스코프에서는 참조할 수 없다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서, &lt;a href=&quot;https://koocci-dev.tistory.com/43?category=1030064&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이전 포스팅&lt;/a&gt;에서 &lt;b&gt;함수 생성 시점과 함수 호이스팅&lt;/b&gt;에 대해 알아보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 함수 선언문으로 함수를 정의하면 런타임 이전에 함수 객체가 생성된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트 엔진은 함수 이름과 동일한 이름의 식별자를 암묵적으로 선언하고 생성된 함수 객체를 할당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;함수 레벨 스코프&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지역 스코프를 설명할 때, 함수의 몸체 내부라고 설명하였다. 즉, &lt;b&gt;코드 블록이 아닌 &lt;span style=&quot;color: #ee2323;&quot;&gt;함수&lt;/span&gt;에 의해서만 지역 스코프가 생성된다는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C나 자바등의 언어는 함수 뿐 아니라, &lt;b&gt;모든 코드 블록(if, for, while 등)이 지역 스코프를 가진다&lt;/b&gt;. 이를 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;블록 레벨 스코프(Block Level Scope)&lt;/b&gt;&lt;/span&gt;라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;javascript 에서는&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt; var 키워드로 선언된 변수는 오로지 함수의 코드 블록(함수 몸체)만을 지역 스코프로 인정한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이를 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;함수 레벨 스코프&lt;/b&gt;&lt;/span&gt;라고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1657039925589&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var i  = 10;

for(var i = 0; i &amp;lt; 5; i++) {
	console.log(i); // 0 1 2 3 4
}

console.log(i); // 5&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;렉시컬 스코프&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1657040070192&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var x = 1;

//정의
function foo() {
	var x = 10;
    bar();
}

//정의
function bar() {
	console.log(x);
}

//정의된 곳의 x값이 출력된다.
foo(); // 1 (전역)
bar(); // 1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;얼핏 보면 조금 헤깔릴 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두가지 쟁점이 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;함수를 어디서 &lt;span style=&quot;color: #ee2323;&quot;&gt;호출&lt;/span&gt;&lt;/b&gt;했는지에 따라 함수의 상위 스코프를 결정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;함수를 어디서 &lt;span style=&quot;color: #ee2323;&quot;&gt;정의&lt;/span&gt;&lt;/b&gt;했는지에 따라 함수의 상위 스코프를 결정&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫번째 방식을 동적 스코프(dynamic scope)라고 한다. 함수를 정의할 때는 어디서 호출될지 모르므로, 호출되는 시점에 상위 스코프가 결정된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두번째는 정적 스코프 혹은 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;렉시컬 스코프(lexical Scope)&lt;/b&gt;&lt;/span&gt;라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트는 &lt;b&gt;렉시컬 스코프&lt;/b&gt;를 따른다. 즉, 함수의 호출위치는 상위 스코프 결정에 어떠한 영향도 주지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;함수의 상위 스코프는 언제나 자신이 정의된 스코프다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;함수 정의(함수 선언문 혹은 함수 표현식)가 실행되어 생성된 함수 객체는 이렇게 결정된 상위 스코프를 기억한다. (스코프 체인)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;변수의 생명 주기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스코프를 배워보았으니, 변수의 생명 주기를 한번 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;전역 변수&lt;/b&gt;&lt;/span&gt;의 생명 주기는 &lt;b&gt;애플리케이션의 생명 주기&lt;/b&gt;와 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;지역 변수&lt;/b&gt;&lt;/span&gt;의 생명 주기는 &lt;b&gt;함수의 생명 주기와 일치&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;호이스팅도 함수 내에서 일어난다&lt;/b&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 말해, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;호이스팅은 스코프를 단위로 일어난다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1657040472953&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var x = 'global';

function foo() {
	console.log(x);
    var x = 'local';
}

foo(); // undefined
console.log(x); // global&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전역 코드는 명시적인 호출 없이 실행된다. 즉, 특별한 진입점이 없고 코드가 로드되면 곧바로 해석되고 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 반환문이 없어, 마지막 문이 실행되면 종료된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;var 키워드로 선언한 전역 변수는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;전역 객체&lt;/b&gt;&lt;/span&gt;의 프로퍼티가 된다. 이는 전역 변수의 생명 주기가 전역 객체의 생명 주기와 일치한다는 것을 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;전역 객체&lt;/b&gt;&lt;/span&gt;는 &lt;b&gt;코드가 실행되기 이전 단계에 자바스크립트 엔진에 의해 어떤 객체보다도 먼저 생성되는 특수한 객체&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저에서는 window, Node.js에서는 global 객체다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;전역 변수의 문제점&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;암묵적 결합&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전역 변수를 선언한 의도는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;코드 어디서든 참조하고 할당할 수 있는 변수를 사용하겠다는 것&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 모든 코드가 전역 변수를 참조하고 변경할 수 있는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;암묵적 결합(implicit coupling)&lt;/b&gt;&lt;/span&gt;을 허용하는 것이다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;긴 생명 주기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;전역 변수는 생명 주기가 길다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, 메모리 리소스도 오랜기간 소비하고, 전역 변수의 상태를 변경할 수 있는 기간도 길고 기회도 많다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;스코프 체인 상에서 종점에 존재&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전역 변수는 스코프 체인 상에서 종점에 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 전역 변수가 가장 마지막에 검색된다. 따라서&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt; 전역 변수의 검색 속도가 가장 느리다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;네임스페이스 오염&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트의 가장 큰 문제점 중 하나는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;파일이 분리되어 있다 해도 하나의 전역 스코프를 공유한다&lt;/b&gt;&lt;/span&gt;는 점이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;전역 변수 사용을 억제하자.&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;즉시 실행 함수&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 코드를 즉시 실행함수로 감싸면 모든 변수는 즉시 실행 함수의 지역변수가 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1657124024901&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(function() {
    var foo = 10; // 즉시 실행 함수의 지역 변수
    // ...
}());

console.log(foo); // ReferenceError: foo is not defined&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;네임스페이스 객체&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전역에 네임스페이스 역할을 담당할 객체를 만들어 전역 변수로 사용할 객체를 따로 추가한다.&lt;/p&gt;
&lt;pre id=&quot;code_1657124132117&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var MYAPP = {}; // 전역 네임스페이스 객체
MYAPP.name = 'Lee';
console.log(MYAPP.name); // Lee

MYAPP.person = {
    name: 'Lee',
    address: 'Seoul'
};

console.log(MYAPP.person.name); // Lee&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;모듈 패턴&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈 패턴은 클래스를 모방해서 관련이 있는 변수와 함수를 모아 즉시 실행 함수로 감싸 하나의 모듈을 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈은 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;클로져&lt;/b&gt;&lt;/span&gt;를 기반으로 동작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클로져는 추후에 학습할 예정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체지향 프로그래밍 언어는 클래스를 구성하는 멤버에 대해 접근제한자(public, private, protected 등)를 통해 공개 범위를 한정한다. (캡슐화:정보은닉)&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;캡슐화(encapsulation)&lt;/b&gt;&lt;/span&gt;는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;객체의 상태(state)를 나타내는 프로퍼티와 프로퍼티를 잠조하고 조작할 수 있는 동작(behavior)인 메서드를 하나로 묶는 것&lt;/b&gt;&lt;/span&gt;이다. 캡슐화는 객체의 특정 프로퍼티나 메서드를 감출 목적으로 사용하기도 하는데 이를 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;정보 은닉(information hiding)&lt;/b&gt;&lt;/span&gt;이라 한다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만, 자바스크립트는 이런 접근 제한자가 없어, 정보 은닉을 한정적으로 구현하기 위해 모듈 패턴을 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1657124636429&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var Counter = (function() {
    //private 변수
    var num = 0;

    // 외부로 공개할 데이터나 메서드를 프로퍼티로 추가한 객체를 반환
    return {
        increase() {
            return ++num;
        },
        decrease() {
            return --num;
        }
    };
}());

// private 변수는 외부로 노출되지 않는다.
console.log(Counter.num); //undefined

console.log(Counter.increase()); // 1
console.log(Counter.increase()); // 2
console.log(Counter.increase()); // 3
console.log(Counter.decrease()); // 2
console.log(Counter.decrease()); // 1&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;ES6 모듈&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;ES6 모듈은 파일 자체의 독자적인 모듈 스코프를 제공한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 모듈 내에서 var 키워드로 선언한 변수는 더는 전역 변수가 아니며 window 객체(전역 객체)의 프로퍼티도 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;script 태그에 type=&quot;module&quot; 어트리뷰트를 추가하면 로드된 자바스크립트 파일은 모듈로서 동작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈의 파일 확장자는 mjs를 권장한다.&lt;/p&gt;
&lt;pre id=&quot;code_1657124929412&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script type=&quot;module&quot; src=&quot;lib.mjs&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script type=&quot;module&quot; src=&quot;app.mjs&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ES6 모듈은 IE를 포함한 구형 브라우저에는 동작하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저의 ES6 모듈 기능을 사용하더라도 트랜스파일링이나 번들링이 필요하기 때문에, 아직은 ES6 모듈 기능보다는 Webpack 등의 모듈 번들러를 사용하는 것이 일반적이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;let, const 키워드와 블록 레벨 스코프&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;var 키워드가 문제가 있으니, let과 const라는 키워드가 등장했을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서, 공부한 내용을 복습해보면 금방 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;변수 중복 선언 허용&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1657125290361&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var x = 1;
var y = 1;

// var 키워드 무시
var x = 100;
// 변수 선언 무시
var y;

console.log(x); // 100
console.log(y); // 1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;함수 레벨 스코프&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1657125329720&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var x = 1;
if(true) {
    var x = 100;
}

console.log(x); // 100&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1657125388003&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var i = 10;

for(var i = 0; i &amp;lt; 5; i++) {
    console.log(i); // 0,1,2,3,4
}

console.log(i); // 5&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;변수 호이스팅&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1657125494391&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 이미 foo는 선언되어 있음 (1. 선언 단계)
// foo는 undefined로 초기화 (2. 초기화 단계)
console.log(foo); // undefined

// 변수에 값을 할당(3. 할당 단계)
foo = 123;

console.log(foo); // 123

// 런타임 이전에 암묵적 실행
var foo;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;let 키워드&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 var의 단점들을 ES6에서 보완한 것이 let과 const이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;변수 중복 선언 금지&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1657125710591&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let bar = 123;
let bar = 234; // Uncaught SyntaxError: Identifier 'bar' has already been declared&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;블록 레벨 스코프&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1657125848547&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let foo = 1; // 전역 변수
{
    let foo = 2; // 지역 변수
    let bar = 3; // 지역 변수
{

console.log(foo); // 1
console.log(bar); // ReferenceError: bar is not defined&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;변수 호이스팅&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;var 키워드로 선언한 변수는 런타임 이전에 자바스크립트 엔진에 의해 암묵적으로 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;선언단계와 초기화 단계가 한번에 진행된다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 선언 단계에서 스코프에 변수 식별자를 등록해 자바스크립트 엔진에 변수의 존재를 알린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, 즉시 초기화 단계에서 undefined 변수를 초기화한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, &lt;b&gt;변수 선언문 이전에 변수에 접근해도 스코프에 변수가 존재하기 때문에 에러가 발생하지 않는다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;l&lt;b&gt;et 키워드로 선언한 변수는 &lt;span style=&quot;color: #006dd7;&quot;&gt;선언 단계와 초기화 단계가 분리되어 진행&lt;/span&gt;된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;let 키워드로 선언한 변수는&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt; 스코프의 시작 시점부터 초기화 단계 시작 지점(변수 선언문)까지 변수를 참조할 수 없다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스코프의 시작 지점부터 초기화 시작 지점까지 변수를 참조할 수 없는 구간을 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;일시적 사각지대(TDZ)&lt;/b&gt;&lt;/span&gt;라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, 마치 호이스팅이 발생하지 않는 것처럼 보인다.&lt;/p&gt;
&lt;pre id=&quot;code_1657126136556&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let foo = 1; // 전역

{
    console.log(foo); //ReferenceError
    let foo = 2; // 지역
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;변수 호이스팅이 발생하지 않는다면 전역 변수 foo 값을 출력해야 한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 let 키워드로 선언한 변수도 여전히 호이스팅이 발생하기 때문에, ReferenceError가 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;전역 객체와 let&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;var로 선언한 전역 변수와 전역 함수, 그리고 선언하지 않은 변수에 값을 할당한 암묵적 전역은 전역 객체 window의 프로퍼티가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;let 키워드로 선언한 전역 변수는 전역 객체의 프로퍼티가 아니라, 보이지 않는 개념적인 블록(전역 렉시컬 환경의 선언적 환경 레코드)내에 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;const 키워드&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;const 키워드는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;상수(constant)&lt;/b&gt;&lt;/span&gt;를 선언하기 위해 사용한다. 대부분은 let과 동일하다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;선언과 초기화&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;const 키워드로 선언한 변수는 선언과 동시에 초기화 해야한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;let과 마찬가지로 블록 레벨 스코프를 가지며, 변수 호이스팅이 발생하지 않는 것처럼 동작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;재할당 금지&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;const 키워드로 선언한 변수는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;재할당이 금지&lt;/b&gt;&lt;/span&gt;된다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;상수&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상수는 재할당이 금지된 변수다. const 키워드로 선언된 변수에 원시 값을 할당한 경우 원시 값은 변경할 수 없는 값이고, const 키워드에 의해 재할당이 금지되므로&lt;b&gt; 할당된 값을 변경할 방법이 없다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;const 키워드와 객체&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;const 키워드로 선언된 변수에 객체를 할당한 경우 값을 변경할 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변경 가능한 값인 객체는 재할당 없이도 직접 변경이 가능하기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;const 키워드는 재할당을 금지할 뿐 불변을 의미하지 않는다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/javascript</category>
      <category>const</category>
      <category>JavaScript</category>
      <category>Let</category>
      <category>블록 스코프</category>
      <category>스코프</category>
      <category>자바스크립트</category>
      <category>함수 스코프</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/49</guid>
      <comments>https://koocci-dev.tistory.com/49#entry49comment</comments>
      <pubDate>Thu, 7 Jul 2022 02:00:24 +0900</pubDate>
    </item>
    <item>
      <title>자바 기초부터 모던 자바까지 - 람다편</title>
      <link>https://koocci-dev.tistory.com/48</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : 람다가 필요한 이유와 자바에서 적용된 내용을 알아본다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;이전 &lt;a href=&quot;https://koocci-dev.tistory.com/41?category=1012334&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;함수형 프로그래밍 포스트&lt;/a&gt;에 이어서, 람다에 대해 하나씩 알아가볼 예정이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;자바에 람다와 함수형 프로그래밍이 왜 필요하지?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 정리해보고자 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이름 없는 함수를 선언할 수 있다. 메서드는 반드시 특정 클래스나 인터페이스 안에 포함되어야 하고 메서드의 이름이 있어야 하지만, 람다 표현식은 이러한 제약에서 벗어난다. 즉, &lt;b&gt;유연성이 생긴다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;소스 코드의 분량이 획기적으로 줄어들 수 있다.&lt;/b&gt; 반복적인 작업이 필요한 기존소스의 비효율성을 낮출 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;코드를 파라미터로 전달할 수 있다&lt;/b&gt;. 외부에서 동작을 정의해서 메서드에 전달할 때 편리하게 사용할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존의 자바에서 탈피하여 지금 우리가 람다를 공부하는 이유다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;람다 표현식을 조금더 구체적으로 알아보자.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;람다는 축약이 매우 많다. 따라서 한번에 이해하기가 어려울 수 있으니, 하나씩 차근히 바꾸어 나가보려고 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1656941870142&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static void main(String[] args) {
    //쓰레드를 생성한다.
    Thread thread = new Thread(new Runnable() {
        // run 메서드를 구현한다.
        @Override
        public void run() {
            System.out.println(&quot;Hello World&quot;);
        }
    });
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쓰레드 프로그래밍의 Runnable 인터페이스의 run 메서드다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;익명 클래스&lt;/b&gt;&lt;/span&gt;를 이용해서 내용을 구현하고 있는 것을 볼 수 있다. (Runnable)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터페이스를 생성자의 파라미터로 받거나 메서드의 파라미터로 받아서 처리할 때 유용하게 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때, 주요하게 봐야할 점은 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;패턴이 반복된다&lt;/b&gt;&lt;/span&gt;는 것이다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;메서드의 이름&lt;/li&gt;
&lt;li&gt;메서드에 전달되는 파라미터 목록&lt;/li&gt;
&lt;li&gt;메서드를 구현한 본문&lt;/li&gt;
&lt;li&gt;메서드의 리턴 타입&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 4가지는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;메서드의 필수 규격&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중요도로 따졌을 때, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;파라미터 목록, 그리고 본문&lt;/b&gt;&lt;/span&gt;이 제일 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 &lt;b&gt;리턴 타입&lt;/b&gt;이 중요하며 마지막으로 &lt;b&gt;이름&lt;/b&gt;은 제일 중요하지 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;람다에서는 리턴 타입과 이름을 과감히 생략해버린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;람다 표현식으로 전환해보자.&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1단계 : 익명 클래스 선언 부분 제거&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656942400381&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//쓰레드를 생성한다.
Thread thread = new Thread(
    // run 메서드를 구현한다.
    @Override
    public void run() {
        System.out.println(&quot;Hello World&quot;);
    }
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 동작하는 소스는 아니지만, new Runnable 부분을 삭제 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Thread 의 생성자 인수로 들어갈 수 있는 것 유일하게 Runnable 인터페이스 혹은 이를 구현한 클래스밖에 없으니 생략이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2단계 : 메서드 선언 부분 제거&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656942565015&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//쓰레드를 생성한다.
Thread thread = new Thread(
    () {
        System.out.println(&quot;Hello World&quot;);
    }
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 역시 실제로 동작하진 않지만, Override한 run 메소드 명과 메소드 리턴 타입을 없애버렸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;리턴 타입이 없다면, void고,&lt;/b&gt; &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;있다면 이미 정해져 있기 때문에&lt;/b&gt;&lt;/span&gt; 생략이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3단계 : 람다 문법으로 정리&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656942715542&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Thread thread = new Thread(() -&amp;gt; System.out.println(&quot;Hello World&quot;));&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단, 한줄로 정리되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감싸고 있던 중괄호를 없애고, 세미콜론을 정리해주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;람다에서는 파라미터 목록을 메서드의 본문으로 전달한다는 의미로 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;'-&amp;gt;'&lt;/b&gt;&lt;/span&gt;기호를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가적으로 알아야 할 것은 Runnable 인터페이스의 run 메서드의 경우 &lt;b&gt;입력 파라미터가 없지만, 이경우에도 ()를 남겨놔야 한다는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순서를 다시한번 정리하자.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;익명 클래스를 이용해서 메서드를 정의한다.&lt;/li&gt;
&lt;li&gt;익명 클래스를 생성하기 위해서 선언한 인터페이스 이름 부분을 삭제한다. 삭제 후에는 메서드 선언 부분만 남는다.&lt;/li&gt;
&lt;li&gt;메서드의 파라미터 목록과 구현한 바디 영역을 제외하고 리턴 타입, 메서드 명을 삭제한다. 삭제 후에는 파라미터 목록과 바디 영역만 남는다.&lt;/li&gt;
&lt;li&gt;람다 문법에 맞게 '-&amp;gt;'를 이용해서 문장을 완성한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;형식 추론&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한가지를 더 줄어보고자 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터페이스에 정의되어 있는 메서드의 파라미터 타입은 이미 정해져있거나, 제네릭을 통해 선언되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;굳이 데이터 타입을 전달할 필요가 없다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656943253902&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(String a) -&amp;gt; System.out.println(a);
(a) -&amp;gt; System.out.println(a); // String 생략&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 두가지는 동일한 람다 표현식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;람다 표현식과 변수&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지는 람다 표현식에서 내부에서 선언한 변수들만 사용해 왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나, 외부에서 생성한 변수도 참조해 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들면, 클래스에서 정의한 멤버 변수나 메서드 내부에서 생성한 로컬 변수를 참조할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1656947215242&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int threadNumber = 100;
list.stream().forEach((String s) -&amp;gt; System.out.println(s + &quot;, &quot; + threadNumber));&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단, 주의할 점은 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;외부 변수의 참조는 final 혹은 final과 유사한 조건&lt;/b&gt;&lt;/span&gt;이어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;final 키워드를 붙이지 않더라도 값이 할당된 이후에 변경될 가능성이 없다면 컴파일러는 final 변수와 동일하게 취급하며, 람다 표현식에서 활용하더라도 컴파일 오류가 발생하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;함수형 인터페이스&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://koocci-dev.tistory.com/41?category=1012334&quot;&gt;함수형 프로그래밍 포스트&lt;/a&gt; 에서 함수형 인터페이스에 대해 간단히 설명했었지만, 조금 더 구체적으로 배워보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;익명 클래스를 구현해야할 인터페이스는 통상적으로 여러개의 메서드를 포함하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그에 비해 람다 표현식은 이름이 없고 단지 파라미터와 리턴 타입만으로 식별하는데 어떻게 자바 컴파일러가 이를 인식하고 인터페이스의 구현체로 컴파일 할 수 있을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론은 람다 표현식을 쓸 수 있는 인터페이스는 &lt;b&gt;오직 public 메서드를 하나만 가지고 있는 인터페이스&lt;/b&gt;여야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;함수형 인터페이스&lt;/b&gt;&lt;/span&gt;라 부르며, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;함수형 인터페이스에서 제공하는 단 하나의 추상 메서드&lt;/b&gt;&lt;/span&gt;를 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;함수형 메서드&lt;/b&gt;&lt;/span&gt;라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(default, static 메서드는 있어도 상관없다)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 개발자 입장에서 람다 표현식을 쓰기 위해 매번 메서드가 하나뿐인 인터페이스를 제공해야 하는 번거로움을 없애기 위해, 가장 자주 사용할법한 패턴으로 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;java.util.function&lt;/b&gt;&lt;/span&gt; 패키지로 제공하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로, &lt;b&gt;@FunctionalInterface&lt;/b&gt; 어노테이션은 없어도 문제 없지만, 명시적으로 넣어주는 것이 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;함수형 인터페이스의 주요 패턴은 무엇이 있을까?&lt;/b&gt;&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 89px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;&lt;b&gt;인터페이스 명&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;&lt;b&gt;메서드 명&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;&lt;b&gt;내용&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;&lt;b&gt;Consumer&amp;lt;T&amp;gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;&lt;b&gt;void accept(T t)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;- 파라미터를 전달해서 처리한 후 결과를 리턴 받을 필요가 없을 때 사용한다.&lt;br /&gt;&lt;br /&gt;- 받기만 하고 리턴하지 않아서 Consumer(소비자)라는 이름을 사용한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 21px; text-align: center;&quot;&gt;&lt;b&gt;Function&amp;lt;T, R&amp;gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 21px; text-align: center;&quot;&gt;&lt;b&gt;R apply(T t)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 21px;&quot;&gt;- 전달할 파라미터를 다른 값으로 변환해서 리턴할 때 사용한다.&lt;br /&gt;&lt;br /&gt;- 주로 값을 변경하거나 매핑할 때 사용한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;&lt;b&gt;Predicate&amp;lt;T&amp;gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;&lt;b&gt;boolean test(T t)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;- 전달받은 값에 대해 true/false 값을 리턴할 때 사용한다.&lt;br /&gt;&lt;br /&gt;- 주로 데이터를 필터링하거나, 조건에 맞는지 여부를 확인하는 용도로 사용한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;&lt;b&gt;Supplier&amp;lt;T&amp;gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;&lt;b&gt;T get()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;- 파라미터 없이 리턴 값만 있는 경우 사용한다.&lt;br /&gt;&lt;br /&gt;- 받지는 않고 리턴만 하기 때문에 Supplier(공급자)라는 이름을 사용한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;위 4가지에 대해서는 반드시 기억해 두도록 하자&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;Consumer 인터페이스&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;앞서 설명한 대로 소비에만 집중하는 인터페이스다. 리턴 타입도&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt; void&lt;/b&gt;&lt;/span&gt;다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;제네릭 타입은 파라미터에 사용된다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656948325501&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class ConsumerExample {
    public static void excuteCunsumer(List&amp;lt;String&amp;gt; nameList, Consumer&amp;lt;String&amp;gt; consumer) {
        for(String name : nameList) {
            // 메서드의 두 번째 인수로 전달된 람다 표현식을 실행
            consumer.accept(name);
        }
    }
}

public static void main(String[] args) {
    List&amp;lt;String&amp;gt; nameList = new ArrayList&amp;lt;&amp;gt;();
    nameList.add(&quot;A&quot;);
    nameList.add(&quot;B&quot;);
    nameList.add(&quot;C&quot;);
    nameList.add(&quot;D&quot;);

    ConsumerExample.excuteCunsumer(nameList, new Consumer&amp;lt;String&amp;gt;() { // 람다 표현식 미사용
        @Override
        public void accept(String s) {
            System.out.println(s);
        }
    });
    ConsumerExample.excuteCunsumer(nameList, (String s) -&amp;gt; System.out.println(s));
    ConsumerExample.excuteCunsumer(nameList, s -&amp;gt; System.out.println(s)); // 형식 추론
    ConsumerExample.excuteCunsumer(nameList, System.out::println); // 참조 메소드
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조금 헤깔릴 수 있는 사항을 정리하고 가자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 식에서 excuteCunsumer는 두번 째 인수로 람다 표현식을 사용중이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;람다 표현식의 실행 결과를 메서드의 두번째 인수로 전달할 것이라고 생각해버릴 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;람다 표현식은 그 자체로 실행되는 것이 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;함수형 인터페이스에 포함되어 있는 함수형 메서드의 내부 코드를 정의하는 것&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 변환 소스를 보도록 하자.&lt;/p&gt;
&lt;pre id=&quot;code_1656948565049&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public Consumer&amp;lt;String&amp;gt; getExpression() {
    return (String name) -&amp;gt; System.out.println(name);
}

ConsumerExample.excuteCunsumer(nameList, getExpression());&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;getExpression의 리턴 타입은 Consumer 인터페이스이고, 람다 표현식을 리턴값으로 넣어주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 getExpression을 excuteConsumer의 두번째 인수로 넣었고 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;람다 표현식의 실행 결과가 리턴될 것이라 볼 경우가 있는데 그렇지 않다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;즉, 람다 표현식은 Consumer 인터페이스의 accept 메서드의 동작을 정의했을 뿐이다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;어떤 데이터가 넘어올지 모르지만, 이렇게 처리하겠다는 것이다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;Function 인터페이스&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Function 인터페이스는 두 개의 제네릭 타입을 정의해야 하고, T와 R이라는 이름을 갖는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;그리고 함수형 메서드에서는 &lt;b&gt;T를 인수로 받아서 R로 리턴하는 apply 메서드&lt;/b&gt;를 가지고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역할은 특정한 클래스를 파라미터로 받아서 처리하고 리턴하는 형태다.&lt;/p&gt;
&lt;pre id=&quot;code_1656949032366&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class FunctionExample {
    public static int executeFunction(String context, Function&amp;lt;String, Integer&amp;gt; function) {
        return function.apply(context);
    }
}

public static void main(String[] args) {
    FunctionExample.executeFunction(&quot;HELLO! WELCOME TO JAVA WORLD&quot;, (String context) -&amp;gt; context.length());
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;apply 메서드가 어떻게 정의될지 모르지만, 전달받은 첫 번째 context문장을 처리하고, 그 결과를 리턴하는 코드가 만들어졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, 그 로직은 main에서 설정되어 들어가게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주로 &lt;b&gt;데이터를 가공하거나 매핑하는 용도로 많이 사용하고, 비즈니스 로직에 대한 리턴 값이 필요할 때 자주 사용&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Predicate 인터페이스&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리턴 타입 중 특별히 참/거짓 중 하나를 선택하는 bool 타입을 필요로 할 때 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수형 메서드는 test다. 제네릭 타입으로 선언된 객체를 파라미터로 받아서 처리한 후 참/거짓 중 하나를 리턴한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;제네릭 타입은 파라미터에 사용된다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656949516051&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class PredicateExample {
    public static boolean isValid(String name, Predicate&amp;lt;String&amp;gt; predicate) {
        return predicate.test(name);
    }
}

public static void main(String[] args) {
    PredicateExample.isValid(&quot;&quot;, (String name) -&amp;gt; !name.isEmpty());
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Supplier 인터페이스&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 Supplier 인터페이스다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무것도 받지 않고, return만 존재하며, 함수형 메서드는 get이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;제네릭 타입은 리턴값에 사용된다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656949809323&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class SupplierExample {
    public static String executeSupplier(Supplier&amp;lt;String&amp;gt; supplier) {
        return supplier.get();
    }
}

public static void main(String[] args) {
    SupplierExample.executeSupplier(() -&amp;gt; {return &quot;HELLO WORLD&quot;});
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;java.util.function&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이외에도 많은 인터페이스가 있지만, 정말 대부분이 위 4가지를 응용했거나, 상속받아서 구현되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;박싱/언박싱의 비용을 이름으로서 구별하는 IntConsumer, DoubleToLongFunction 등도 있고, Operator 인터페이스는 Function 인터페이스를 상속받아 구현되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;메서드 참조&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;함수를 메서드의 파라미터로 전달하는 것&lt;/b&gt;&lt;/span&gt;을 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;메서드 참조&lt;/b&gt;&lt;/span&gt;라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매서드 참조는 람다 표현식과는 달리 코드를 여러 곳에서 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;재사용&lt;/b&gt;&lt;/span&gt;할 수 있고, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;직접 개발한 메서드도 사용&lt;/b&gt;&lt;/span&gt;할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 람다 표현식을 한번 더 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;축약&lt;/b&gt;&lt;/span&gt;할 수 있고, 코드의 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;가독성&lt;/b&gt;&lt;/span&gt;도 높일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메서드 참조는 함수형 인터페이스와 연관되어 있지만 &lt;b&gt;람다 표현식을 대체하기 위한 것은 아니며 상호 보완적&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;메서드 참조 역시 람다 표현식 처럼 결과가 아닌, 코드 자체를 전달하는 것이니 헤깔리지 말자.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1656950494026&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(String name) -&amp;gt; System.out.println(name) // 람다 표현식 구문
System.out::println // 메서드 참조 구문&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;System 클래스의 out 객체에 있는 println 메서드를 호출한다는 뜻이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당연히 출력해야 할 값이 파라미터로 전달되어야 하는데, 이 때 사용하는 값은 왼편에 생략된 String name이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1656950613186&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static void main(String[] args) {
    List&amp;lt;String&amp;gt; list = new ArrayList&amp;lt;&amp;gt;();

    ...

    for(String entity : list) {
        System.out.println(entity);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바7까지는 위 코드가 정석적이였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바 8부터는 컬렉션 프레임워크를 개선하기 위해 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;스트림&lt;/b&gt;&lt;/span&gt;이라는 개념을 도입했고, 스트림에는 람다 표현식과 메서드 참조를 사용할 수 있게 되었다.&lt;/p&gt;
&lt;pre id=&quot;code_1656950737551&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;list.stream().forEach((String entity) -&amp;gt; System.out.println(entity));
list.stream().forEach(System.out::println);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조금 더 심화 예시를 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1656951056228&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class MethodReferenceExample {
    public static MethodReferenceExample of() {
        return new MethodReferenceExample();
    }
    
    // 데이터 처리 로직 정의
    public static void executeMethod(String entity) {
        if(entity != null &amp;amp;&amp;amp; !&quot;&quot;.equals(entity)) {
            System.out.println(&quot;Contents : &quot; + entity);
            System.out.println(&quot;Length : &quot; + entity.length());
        }
    }
    
    // 대문자로 변경하는 코드
    public void toUpperCase(String entity) {
        System.out.println(entity.toUpperCase());
    }
    
    // 실행하는 예
    public static void main(String[] args) {
        List&amp;lt;String&amp;gt; list = new ArrayList&amp;lt;&amp;gt;();
        list.add(&quot;a&quot;);
        list.add(&quot;b&quot;);
        list.add(&quot;c&quot;);
        
        // 정적 메서드 참조
        list.stream().forEach(MethodReferenceExample::executeMethod);
        // 한정적 메서드 참조
        list.stream().forEach(MethodReferenceExample.of()::toUpperCase);
        // 비한정적 메서드 참조
        list.stream().map(String::toUpperCase).forEach(System.out::println);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예시에서 메서드 참조를 정의하는 문법은 두 가지다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클래스명::메서드명&lt;/li&gt;
&lt;li&gt;객체 변수명::메서드명&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 메서드 참조는 3가지로 구분된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정적 메서드 참조&lt;/li&gt;
&lt;li&gt;비한정적 메서드 참조&lt;/li&gt;
&lt;li&gt;한정적 메서드 참조&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;정적 메서드 참조&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;static으로 정의한 메서드를 참조&lt;/b&gt;&lt;/span&gt;할 때 사용하며 가장 일반적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;static 메서드는 호출할 때 객체를 생성하지 않기 때문에 명확히 확인해볼 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1657029883901&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Integer::parseInt
(String s) -&amp;gt; Integer.parseInt(s)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;비한정적 메서드 참조&lt;/b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;비한정적(unbound) 메서드 참조&lt;/b&gt;&lt;/span&gt;는 static 메서드를 참조하는 것과 유사하게 작성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비한정적이라는 표현은 &lt;b&gt;작성하는 구문 자체가 특정한 객체를 참조하기 위한 변수를 지정하지 않는다&lt;/b&gt;는 의미다.&lt;/p&gt;
&lt;pre id=&quot;code_1657030018996&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String::toUpperCase&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;String 클래스의 toUpperCase 메서드는&lt;b&gt; public 메서드이며 static이 아니기 때문에&lt;/b&gt; 반드시 String 클래스가 객체화되어야만 호출 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나, 마치 static 메서드를 참조하는 것처럼 정의하였다. 위 코드를 람다 표현식으로 보자.&lt;/p&gt;
&lt;pre id=&quot;code_1657030105769&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(String str) -&amp;gt; str.toUpperCase()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;풀어서 보면, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;객체의 생성을 파라미터로 받았다&lt;/b&gt;&lt;/span&gt;. 즉, &lt;b&gt;람다 표현식 내부에서 객체 생성이 일어났기 때문에 객체를 참조할만한 변수가 외부에 존재하지 않는다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약, 처리해야 하는 데이터가 여러개라면 조금 복잡해질 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;List에서 연속된 2개의 데이터를 뽑아서 크기를 구하는 방식을 작성하면 다음과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1657030238537&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;List&amp;lt;String&amp;gt; list = new ArrayList&amp;lt;&amp;gt;();

...
list.stream().sorted((String a, String b) -&amp;gt; a.compareTo(b));
list.stream().sorted(String::compareTo); // 위와 동일&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매우 함축적이라, 이해하고 해석하는데 어려울 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;한정적 메서드 참조&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한정적(bound)이라는 단어를 사용한 이유는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;참조하는 메서드가 특정 객체의 변수로 제한되기 때문&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;pre id=&quot;code_1657030388007&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Calendar.getInstance()::getTime

Calendar cal = Calendar.getInstance();
() -&amp;gt; cal.getTime()

Calendar cal = Calendar.getInstance(); // 객체 생성
cal::getTime // 메서드 참조 구문. cal 변수를 참조&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바8 이후 많은 클래스가 생성자를 이용한 객체 인스턴스화 보다는, of 와 같은 메서드로 생성하는 경향이 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 경우, 한 줄 소스로 메서드 참조를 정의할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 매번 instance를 만들 수 있으므로, 외부에 한번 생성하고, 재활용하는 경우가 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한정적 메서드 참조와 비한정적 메서드 참조의 차이는 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;한정적 메서드 참조&lt;/b&gt;&lt;/span&gt;는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;외부에서 정의한 객체의 메서드를 참조&lt;/b&gt;&lt;/span&gt;할 때 사용하며, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;비한정적 메서드 참조&lt;/b&gt;&lt;/span&gt;는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;람다 표현식 내부에서 생성한 객체의 메서드를 참조&lt;/b&gt;&lt;/span&gt;할 때 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;생성자 참조&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성자는 메서드와 엄연히 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;return이 없으며, 객체 생성 시에만 사용되고 객체 생성 시, 초기화의 개념을 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성자 참조는 아래 문법을 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;클래스명::new&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;람다 표현식 조합&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 한가지만 더 알아볼 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;람다 표현식은 예전 재귀 호출과 같은 작업으로 진행했던, 마치 파이프라인 명령어처럼 기능을 조합하고 연결할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Consumer 조합&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1657031273678&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Consumer&amp;lt;String&amp;gt; consumer = System.out::println;
Consumer&amp;lt;String&amp;gt; andThen = text -&amp;gt; System.out.println(&quot;text length : &quot; + text.length());
consumer.andThen(andThen).accept(&quot;JAVA&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JAVA &lt;br /&gt;text&amp;nbsp;length&amp;nbsp;:&amp;nbsp;4&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Consumer 인터페이스에 들어가보면, andThen이라는 &lt;b&gt;default 메서드&lt;/b&gt;가 있다. (함수형 메서드는 accept다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 실행 결과를 보면, &lt;b&gt;두가지 Consumer가 순차적으로 호출됨&lt;/b&gt;을 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;호출되고 처리되는 순서를 보도록 하자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;accept 메서드에 &quot;JAVA&quot; 문자열을 파라미터로 전달하여 함수형 인터페이스를 실행&lt;/li&gt;
&lt;li&gt;첫번째 람다 구문이 실행&lt;/li&gt;
&lt;li&gt;두번째 람다 구문이 실행&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Consumer 인터페이스의 함수형 메서드의 리턴타입이 void라서 그렇다&lt;/b&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;리턴값을 그대로 받아서 처리하지 않고, 마치 두개의 Consumer를 연속해서 실행한 것과 동일한 결과를 준다.&lt;/b&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Predicate 조합&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Predicate 인터페이스에도 Consumer의 andThen처럼 어떤 메서드들이 있는지 보면, &lt;b&gt;and/or&lt;/b&gt;와 같이 참/거짓 판별에 사용하는 메서드들이 있다. 즉, &lt;b&gt;여러 개의 참과 거짓에 대한 조건식을 합친다는 것이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1657032141991&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Person {
    private String name;
    private String sex;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

public class PredicateAndExample {
    public static Predicate&amp;lt;Person&amp;gt; isMale() {
        return (Person p) -&amp;gt; &quot;male&quot;.equals(p.getSex());
    }

    public static Predicate&amp;lt;Person&amp;gt; isAdult() {
        return (Person p) -&amp;gt; p.getAge() &amp;gt; 20;
    }
}

public static void main(String[] args) {
    Predicate&amp;lt;Person&amp;gt; isMan = PredicateAndExample.isMale();
    Predicate&amp;lt;Person&amp;gt; isAdult = PredicateAndExample.isAdult();
    Predicate&amp;lt;Person&amp;gt; isManNAdult = isMan.and(isAdult);

    Person p = new Person();
    p.setAge(21);
    p.setName(&quot;ASD&quot;);
    p.setSex(&quot;male&quot;);

    System.out.println(isManNAdult.test(p));

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫번째로, 람&lt;b&gt;다 표현식을 별도의 static 메서드로 정의해둔 것&lt;/b&gt;을 집중하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 형태의 개발 방향이 가독성을 높여준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두번째로, 람다 표현식의 조합은 반드시 지켜야 하는 규정이 있는데, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;두 함수형 인터페이스의 제네릭 타입이 동일해야 한다는 것이다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;따라서, &lt;b&gt;위 예제는 객체로 별도로 만들어 비교해둔 것이다.&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Function 조합&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Function 인터페이스에도 andThen 이 있지만, Consumer 인터페이스와는 많이 다르다.&lt;/p&gt;
&lt;pre id=&quot;code_1657037204247&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static void main(String[] args) {
    Function&amp;lt;String, Integer&amp;gt; parseIntFunction = (String str) -&amp;gt; Integer.parseInt(str) + 1;
    Function&amp;lt;Integer, String&amp;gt; intToStrFunction = (Integer i) -&amp;gt; &quot;String : &quot; + i;

    System.out.println(parseIntFunction.apply(&quot;1000&quot;));
    System.out.println(intToStrFunction.apply(1000));
    System.out.println(parseIntFunction.andThen(intToStrFunction).apply(&quot;1000&quot;));
}&lt;/code&gt;&lt;/pre&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1001 &lt;br /&gt;String&amp;nbsp;:&amp;nbsp;1000 &lt;br /&gt;String&amp;nbsp;:&amp;nbsp;1001&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;눈치 챘겠지만, andThen으로 연결되는 제네릭 타입 두가지에 대해, &lt;b&gt;파라미터, 리턴타입이 잘 연결될 수 있는 형태가 되어야 한다. (String -&amp;gt; Integer -&amp;gt; String)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또, Function이 지원하는&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt; compose&lt;/b&gt;&lt;/span&gt;라는 메서드가 있다.&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1657037334364&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static void main(String[] args) {
    Function&amp;lt;String, Integer&amp;gt; parseIntFunction = (String str) -&amp;gt; Integer.parseInt(str) + 1;
    Function&amp;lt;Integer, String&amp;gt; intToStrFunction = (Integer i) -&amp;gt; &quot;String : &quot; + i;

    System.out.println(parseIntFunction.apply(&quot;1000&quot;));
    System.out.println(intToStrFunction.apply(1000));
    System.out.println(intToStrFunction.compose(parseIntFunction).apply(&quot;1000&quot;));
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;compose는 뒤에서 앞으로 호출된다고 보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 포스팅에서는 본격적으로 스트림에 대해 알아볼 예정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 공부한 함수형 인터페이스가 자바에서 어떻게 쓰였는지 알아볼 수 있을 것이다.&lt;/p&gt;</description>
      <category>Programming/Java</category>
      <category>functional interface</category>
      <category>Interface</category>
      <category>Java</category>
      <category>lambda</category>
      <category>람다</category>
      <category>람다 표현식</category>
      <category>자바</category>
      <category>함수형 인터페이스</category>
      <category>함수형 참조</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/48</guid>
      <comments>https://koocci-dev.tistory.com/48#entry48comment</comments>
      <pubDate>Wed, 6 Jul 2022 01:09:59 +0900</pubDate>
    </item>
    <item>
      <title>[java] House Robber</title>
      <link>https://koocci-dev.tistory.com/47</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;[참고문제] :&lt;span&gt;&lt;span&gt; &lt;a href=&quot;https://leetcode.com/problems/house-robber/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://leetcode.com/problems/house-robber/&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/container-with-most-water/&quot; data-source-url=&quot;https://leetcode.com/problems/container-with-most-water/&quot;&gt;&amp;nbsp;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1657029416170&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;House Robber - LeetCode&quot; data-og-description=&quot;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&quot; data-og-host=&quot;leetcode.com&quot; data-og-source-url=&quot;https://leetcode.com/problems/house-robber/&quot; data-og-url=&quot;https://leetcode.com/problems/house-robber/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dbpk3y/hyOZAdpgIE/4PItnlTnOUKWC42TzA1PY1/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/house-robber/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://leetcode.com/problems/house-robber/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dbpk3y/hyOZAdpgIE/4PItnlTnOUKWC42TzA1PY1/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;House Robber - LeetCode&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;leetcode.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;figure id=&quot;og_1656742664648&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Container With Most Water - LeetCode&quot; data-og-description=&quot;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&quot; data-og-host=&quot;leetcode.com&quot; data-og-source-url=&quot;https://leetcode.com/problems/container-with-most-water/&quot; data-og-url=&quot;https://leetcode.com/problems/container-with-most-water/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bohbn4/hyOYqggcRu/EtodHWcre7oElG8mo2iD70/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260,https://scrap.kakaocdn.net/dn/c3A7Ll/hyOYncL4fh/Ghh5aTJMGcPzfHPonnkZ70/img.png?width=2104&amp;amp;height=2021&amp;amp;face=0_0_2104_2021,https://scrap.kakaocdn.net/dn/cnjvt5/hyOYpPbZol/QJLOKI4BKC9eqADkivZZR0/img.png?width=2104&amp;amp;height=2021&amp;amp;face=0_0_2104_2021&quot;&gt;&lt;/figure&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제 풀이&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DP 문제다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;점화식을 찾기 위해서 나열해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에도 꽤 많이 나열해보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;생각의 흐름 - 초깃값 찾기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에도 초깃값부터 찾아보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;arr[n] 부터 생각해보았으나, 역시 최초 1일때부터 고민하는 것이 나았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6번째 정도 적어보니, 이전에 적어둔 식들이 다시 쓰이기 시작했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 들어온 값과 2칸전에 확인한 MAX값을 더하거나, 1칸 전의 MAX값을 비교하는 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1657029571024&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public int rob(int[] nums) {
    int arr[] = new int[101];

    int len = nums.length;
    if(len == 1)
        return nums[0];
    else if(len == 2)
        return Math.max(nums[0], nums[1]);
    else if(len == 3)
        return Math.max(nums[0] + nums[2], nums[1]);
    else if(len == 4)
        return Math.max(Math.max(nums[0] + nums[2], nums[1] + nums[3]), nums[0] + nums[3]);
    arr[0] = nums[0];
    arr[1] = Math.max(nums[0], nums[1]);
    arr[2] = Math.max(nums[0] + nums[2], nums[1]);
    arr[3] = Math.max(Math.max(nums[0] + nums[2], nums[1] + nums[3]), nums[0] + nums[3]);

    for(int i = 4; i &amp;lt; len; i++) {
        arr[i] = Math.max(arr[i-2] + nums[i], arr[i-1]);
    }
    return arr[len-1];
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;수정&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게 많은 작업을 할 필요 없다.&lt;/p&gt;
&lt;pre id=&quot;code_1661775680360&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution {
    public int rob(int[] nums) {
        int[] dp = new int[nums.length];       
        if(nums.length == 1)
            return nums[0];
        else if(nums.length == 2) {
            return nums[0] &amp;gt; nums[1] ? nums[0]:nums[1];
        }
        else {
            dp[0] = nums[0];
            dp[1] = nums[0] &amp;gt; nums[1] ? nums[0]:nums[1];

            for(int i = 2; i &amp;lt; nums.length; i++) {
                dp[i] = Math.max(dp[i-1], dp[i-2] + nums[i]);
            }

            return dp[nums.length - 1]; 
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algorithm</category>
      <category>Algorithm</category>
      <category>House Robber</category>
      <category>Java</category>
      <category>leetcode</category>
      <category>알고리즘</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/47</guid>
      <comments>https://koocci-dev.tistory.com/47#entry47comment</comments>
      <pubDate>Tue, 5 Jul 2022 23:00:46 +0900</pubDate>
    </item>
    <item>
      <title>[java] Climbing Stairs</title>
      <link>https://koocci-dev.tistory.com/46</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;[참고문제] :&lt;span&gt;&lt;span&gt;&lt;a href=&quot;https://leetcode.com/problems/climbing-stairs/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://leetcode.com/problems/climbing-stairs/&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #555555;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1657028140255&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Climbing Stairs - LeetCode&quot; data-og-description=&quot;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&quot; data-og-host=&quot;leetcode.com&quot; data-og-source-url=&quot;https://leetcode.com/problems/climbing-stairs/&quot; data-og-url=&quot;https://leetcode.com/problems/climbing-stairs/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cOAlXP/hyOZCCe14P/SZkQ1lhU3KtultNNFaWiAk/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/climbing-stairs/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://leetcode.com/problems/climbing-stairs/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cOAlXP/hyOZCCe14P/SZkQ1lhU3KtultNNFaWiAk/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Climbing Stairs - LeetCode&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;leetcode.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;문제 풀이&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DP문제다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DP는 일단 규칙찾기, 점화식 찾기다. 못찾으면 끝나는 문제라고 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;생각의 흐름 - 초기값들을 찾자.&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제에서 보이듯, n = 1, n = 2, n = 3일 때를 보여주고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;점화식 문제처럼 초기값들을 먼저 설정해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;생각의 흐름 - 일단 적어보자.&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 안보이면, 난 일단 적어본다. 생각날 때까지 적다보면, 규칙이 보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에도 n=6정도까지 적어보니, 금방 규칙이 보였다.&lt;/p&gt;
&lt;pre id=&quot;code_1657028107423&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public int climbStairs(int n) {
    int[] arr = new int[45];

    arr[1] = 1;
    arr[2] = 2;
    if(n == 1) {
        return 1;
    }

    else if(n == 2) {
        return 2;
    }

    else {
        for(int i = 3; i &amp;lt;= n; i++) {
           arr[i] = arr[i-1] + arr[i-2];
        }
    }

   return arr[n];
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm</category>
      <category>algorighm</category>
      <category>Climbing Stairs</category>
      <category>Java</category>
      <category>leetcode</category>
      <category>알고리즘</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/46</guid>
      <comments>https://koocci-dev.tistory.com/46#entry46comment</comments>
      <pubDate>Tue, 5 Jul 2022 22:35:45 +0900</pubDate>
    </item>
    <item>
      <title>[java] Flood Fill</title>
      <link>https://koocci-dev.tistory.com/45</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;[참고문제] :&lt;a href=&quot;https://leetcode.com/problems/flood-fill/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://leetcode.com/problems/flood-fill/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1656940962962&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Flood Fill - LeetCode&quot; data-og-description=&quot;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&quot; data-og-host=&quot;leetcode.com&quot; data-og-source-url=&quot;https://leetcode.com/problems/flood-fill/&quot; data-og-url=&quot;https://leetcode.com/problems/flood-fill/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/jNg8D/hyOYe28Fwm/c70KTK6KrvRxWyEVEZGEb0/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260,https://scrap.kakaocdn.net/dn/cSaiF3/hyOYheqPGp/iwBFnNzkG0PLFKQaKN9PbK/img.jpg?width=613&amp;amp;height=253&amp;amp;face=0_0_613_253&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/flood-fill/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://leetcode.com/problems/flood-fill/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/jNg8D/hyOYe28Fwm/c70KTK6KrvRxWyEVEZGEb0/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260,https://scrap.kakaocdn.net/dn/cSaiF3/hyOYheqPGp/iwBFnNzkG0PLFKQaKN9PbK/img.jpg?width=613&amp;amp;height=253&amp;amp;face=0_0_613_253');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Flood Fill - LeetCode&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;leetcode.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;문제 풀이&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어려운 문제는 아니며, 기초를 다지기 위해 풀어보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;생각의 흐름 - 보자마자 떠올라야 한다.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BFS혹은 DFS 문제임을 알아야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이차원 배열과 queue, 그리고 적절한 Pair와 같은 자료구조가 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;java에서는 pair와 같은게 없기 때문에, Node라는 class를 만들어 써보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;생각의 흐름 - 조건을 명확히 보자&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;image[sr][sc] 로 인해 넘치는 부분들을 찾아나가야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;채우고자 하는 값(fill)을 명확히 하고, index 들의 제한 범위를 잘 고려하자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;생각의 흐름 - visited 체크가 필요하다.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 돌려보았더니, 갔던 길을 계속 다시 가는걸 발견했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 부분을 놓치는 경우가 많으니 항상 기초부터 다지도록 하자.&lt;/p&gt;
&lt;pre id=&quot;code_1656742664649&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public int[][] floodFill(int[][] image, int sr, int sc, int color) {
    int N = image.length;
    int M = image[0].length;
    Queue&amp;lt;Node&amp;gt; que = new LinkedList&amp;lt;&amp;gt;();
    int[][] isVisited = new int[N][M];
    int fill = image[sr][sc];
    que.add(new Node(sr,sc));
    while(!que.isEmpty()) {
        Node node = que.poll();
        if(isVisited[node.row][node.col] != -1) {
            isVisited[node.row][node.col] = -1;
            image[node.row][node.col] = color;
            if(node.row -1 &amp;gt;= 0 &amp;amp;&amp;amp; image[node.row -1][node.col] == fill)
                que.add(new Node(node.row -1, node.col));
            if(node.row+1 &amp;lt;= N -1 &amp;amp;&amp;amp;  image[node.row +1][node.col] == fill)
                que.add(new Node(node.row +1, node.col));
            if(node.col -1 &amp;gt;= 0 &amp;amp;&amp;amp; image[node.row][node.col-1] == fill)
                que.add(new Node(node.row, node.col-1));
            if(node.col+1 &amp;lt;= M -1 &amp;amp;&amp;amp;  image[node.row][node.col+1] == fill)
                que.add(new Node(node.row, node.col+1));
        }
    }
    return image;
}

class Node {
    int row;
    int col;
    Node(int row, int col) {
        this.row = row;
        this.col = col;
    };
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algorithm</category>
      <category>Algorithm</category>
      <category>Flood fill</category>
      <category>Java</category>
      <category>leetcode</category>
      <category>알고리즘</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/45</guid>
      <comments>https://koocci-dev.tistory.com/45#entry45comment</comments>
      <pubDate>Mon, 4 Jul 2022 22:26:52 +0900</pubDate>
    </item>
    <item>
      <title>[java] Longest Substring Without Repeating Characters</title>
      <link>https://koocci-dev.tistory.com/44</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;[참고문제] : &lt;a href=&quot;https://leetcode.com/problems/longest-substring-without-repeating-characters/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://leetcode.com/problems/longest-substring-without-repeating-characters/&lt;/a&gt;\&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1656936386604&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Longest Substring Without Repeating Characters - LeetCode&quot; data-og-description=&quot;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&quot; data-og-host=&quot;leetcode.com&quot; data-og-source-url=&quot;https://leetcode.com/problems/longest-substring-without-repeating-characters/&quot; data-og-url=&quot;https://leetcode.com/problems/longest-substring-without-repeating-characters/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/IEsLs/hyOYs1kJHB/5VxSx5rYUkJX57YOiaS4pK/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/longest-substring-without-repeating-characters/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://leetcode.com/problems/longest-substring-without-repeating-characters/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/IEsLs/hyOYs1kJHB/5VxSx5rYUkJX57YOiaS4pK/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Longest Substring Without Repeating Characters - LeetCode&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;leetcode.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제 풀이&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MAP을 써야 하는 문제라는 걸 인식했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;생각의 흐름 - MAP을 어떻게 구성할까?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인덱스를 갖고 있어야 한다고 생각했다. 똑같은게 나왔을 때, 기존 인덱스를 어떻게든 활용해야 한다고 생각했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;생각의 흐름 - 현재의 흐름과 최대값의 흐름을 별도로 가져가야 한다.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최대값은 반환값을 위해, 그리고 계산을 위해 현재 값도 갖고 가면서 비교해야 한다고 판단했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;생각의 흐름 - if문을 어떻게 구성할까?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MAP에 있는지 없는지를 비교하는건 자명했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MAP에 없을 때는 값을 넣어주어야 하고 현재 길이를 늘린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MAP에 있을 때가 주요한 것으로 보였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 MAP에 있다면 현재 크기와 최대값을 비교해서 저장해야 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면, 그 이후는 어디부터 계산해야할까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 계속 나가는 건 advdf 와 같은 예시에서 틀리기 마련이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 이전에 나온 위치. 즉, 앞서 고민했던 기존 인덱스 다음부터 계산을 했어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 어떻게 돌아가야 할까? i를 그냥 돌려버리면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;생각의 흐름 - return 값은?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;누락해버린 것이 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;currLen을 maxLen과 비교안해버리는 경우가 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 최종적으로 처리해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1656742664649&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public int lengthOfLongestSubstring(String s) {
    Map&amp;lt;Character, Integer&amp;gt; map = new HashMap&amp;lt;&amp;gt;();
    int maxLen = 0;
    int currLen = 0;
    int len = s.length();
    for(int i = 0; i &amp;lt; len; i++) {
        char curr = s.charAt(i);
        if(!map.containsKey(curr)) {
            map.put(curr, i);
            currLen ++;
        } else {
            maxLen = Math.max(maxLen, currLen);
            i = map.get(curr);
            currLen = 0;
            map.clear();
        }
    }
    return Math.max(maxLen, currLen);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algorithm</category>
      <category>Algorithm</category>
      <category>Java</category>
      <category>leetcode</category>
      <category>Longest Substring WIthout Repeating Characters</category>
      <category>알고리즘</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/44</guid>
      <comments>https://koocci-dev.tistory.com/44#entry44comment</comments>
      <pubDate>Mon, 4 Jul 2022 21:12:03 +0900</pubDate>
    </item>
    <item>
      <title>자바스크립트 기초부터 모던 자바스크립트까지 - 함수편</title>
      <link>https://koocci-dev.tistory.com/43</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : 자바스크립트의 함수에 대해 알아본다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트에서 가장 중요한 개념이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스코프, 실행 컨텍스트, 클로저, this, 프로토타입, 모듈화 등 모두 함수에서부터 시작된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그래밍 언어에서 함수는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;일련의 과정을 문(statement)으로 구현하고 코드 블록으로 감싸서 하나의 실행 단위로 정의한 것&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단히 용어를 정리해보자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;매개변수(parameter) : 함수 내부로 입력을 전달받는 변수&lt;/li&gt;
&lt;li&gt;인수 (argument) : 입력&lt;/li&gt;
&lt;li&gt;출력 (return value) : 출력&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1656852903631&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function add(x, y) { // parameter
	return x+y; // return value
}

add(2,5); // argument&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;함수 리터럴&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트의 함수는 &lt;b&gt;객체 타입의 값&lt;/b&gt;이다. 따라서 숫자 값을 숫자 리터럴로 생성하고 객체를 객체 리터럴로 생성하듯, 함수도 함수 리터럴로 생성할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1656852995032&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var f = function add(x, y) {
	return x+y;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예제를 보면 &lt;b&gt;함수 리터럴을 변수에 할당&lt;/b&gt;하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리터럴 정의는 &lt;a href=&quot;https://koocci-dev.tistory.com/33&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이전 포스팅&lt;/a&gt;에서 다루었다. 리터럴은 &lt;b&gt;값을 생성하기 위한 약속된 표기법&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 리터럴도 &lt;b&gt;평가되어 값을 생성하며, 이 값은 객체&lt;/b&gt;다. 즉,&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt; 함수는 객체&lt;/b&gt;&lt;/span&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 점은 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;일반 객체는 호출할 수 없지만, 함수는 호출할 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;함수 정의&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수를 정의하는 방법은 4가지가 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1656853292447&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 1. 함수 선언문
function add(x,y) {
	return x+y;
}

// 2. 함수 표현식
var add = function(x,y) {
	return x+y;
}

// 3. Function 생성자 함수
var add = new Function('x', 'y', 'return x+y');

// 화살표 함수 (ES6)
var add = (x,y) =&amp;gt; x+y;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;함수 선언문&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 선언문은 함수 리터럴과 형태가 동일하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단, 함수 리터럴은 함수 이름을 생략할 수 있으나 &lt;b&gt;함수 선언문은 함수 이름을 생략할 수 없다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 선언문은 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;표현식이 아닌 문(statement)&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://koocci-dev.tistory.com/33&quot;&gt;이전 포스팅&lt;/a&gt;&amp;nbsp;내용처럼 &lt;b&gt;값으로 평가할 수 있는 문이 표현식&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 값으로 평가할 수 없다는 것이다. 실제로, 위 함수 선언문을 개발자 환경에서 실행하면 undefined가 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;표현식이라면 그 값이 찍혀야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 조금 이상한 경우가 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1656853673408&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var add = function add(x,y) {
	return x+y;
}

console.log(add(3,5)); // 7&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분명 표현식이 아닌 문인데, 변수에 들어가는 것처럼 보인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 자바스크립트 엔진의 해석차이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔진에서 위 식을 함수 리터럴로 볼수도 있고, 표현식이 아닌 문으로 볼 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중이적인 표현이 된다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 위 예시에서는 함수 리터럴로 판단하였고, 정상적인 방식으로 정의 된 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1656854338493&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function foo() { console.log('foo')};
foo(); // foo

(function bar() { console.log('bar'); });
bar(); // ReferenceError: bar is not defined&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;foo는 함수 선언문으로 해석되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나, 그룹 연산자()안에 들어간 bar는 함수표현식으로 해석된 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그룹연산자에는 값으로 평가될 수 있는 표현식만 들어갈 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 함수 리터럴에서는 &lt;b&gt;함수명이 내부에서만 쓸수 있는 식별자&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외부에서는 함수 리터럴의 함수명을 호출 할 수 없다. 따라서, 외부에서는 bar라는 존재를 알지 못하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 foo를 호출할 수 있었던 이유는 무엇인가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 리터럴의 함수명은 외부에서 호출 할 수 없는데, 함수 선언문은 예외인것일까라고 생각할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;자바스크립트 엔진은 생성된 함수를 호출하기 위해 함수 이름과 동일한 이름의 식별자를 &lt;span style=&quot;color: #006dd7;&quot;&gt;암묵적으로 생성&lt;/span&gt;하고, 거기에 함수 객체를 할당한다.&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 우리는 함수 이름으로 호출하는 것처럼 보였지만 사실은&lt;b&gt; 함수 객체를 가리키는 식별자로 호출하는 것이다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656854663186&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var add = function add(x,y) { // 식별자add와 함수이름 add를 구분하자
	return x+y;
};

console.log(add(2,5)); // 7, 식별자 add다.&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;함수 표현식&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트 함수는 객체 타입의 값이라고 앞서 설명하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 값처럼 변수에 할당하거나 프로퍼티가 되거나 배열이 될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 값의 성질을 갖는 객체를 &lt;a href=&quot;https://koocci-dev.tistory.com/56&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;일급 객체&lt;/a&gt;라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;일급 객체&lt;/b&gt;&lt;/span&gt;이므로, 함수 리터럴로 생성한 함수 객체를 변수에 할당할 수 있다. 이런 함수 정의 방식을 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;함수 표현식&lt;/b&gt;&lt;/span&gt;이라 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 리터럴의 함수 이름은 생략할 수 있고, 이를 익명 함수라 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 표현식의 함수 리터럴은 함수 이름을 생략하는 것이 일반적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;함수 생성 시점과 함수 호이스팅&lt;/h4&gt;
&lt;pre id=&quot;code_1656855862297&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//함수 참조
console.dir(add); // f add(x,y)
console.dir(sub); // undefined

//함수 호출
console.log(add(2,5)); // 7
console.log(sub(2,5)); // TypeError

//함수 선언문
function add(x,y) {
	return x+y;
}

//함수 표현식
var sub = function(x,y) {
	return x-y;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예시의 특징을 분석해보면 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;함수 선언문으로 정의한 함수는 함수 선언문 이전에 호출할 수 있다.&lt;/li&gt;
&lt;li&gt;함수 표현식으로 정의한 함수는 함수 표현식 이전에 호출할 수 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;함수 선언문으로 정의한 함수와 함수 표현식으로 정의한 함수의 생성 시점이 다르다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 선언문도 다른 선언문(변수 선언 등)과 동일하게 코드가 한 줄씩 순차적으로 실행되는 시점인 런타임 이전에 자바스크립트 엔진에 의해 먼저 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;함수 선언문이 코드의 선두로 끌어올려진 것처럼 동작하는 자바스크립트 고유의 특징&lt;/b&gt;&lt;/span&gt;을 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;호이스팅&lt;/b&gt;&lt;/span&gt;이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단, 함수 호이스팅과 변수 호이스팅은 약간의 차이가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;var 키워드를 통한 변수 선언문과 함수 선언문은 런타임 이전에 엔진에 의해 먼저 실행되어 식별자를 생성하는 건 동일하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 var 키워드로 선언된 변수는 undefined로 초기화되고, 함수 선언문을 통해 암묵적으로 생성된 식별자는 함수 객체로 초기화된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉,&lt;b&gt; 함수 선언문으로 정의한 함수를 함수 선언문 이전에 호출하면 함수 호이스팅에 의해 호출이 가능&lt;/b&gt;하다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 표현식은 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;변수에 함수 리터럴이 할당되는 문&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수 할당문의 값은 할당문이 실행되는 시점, 즉 런타임에 평가되므로 함수 표현식의 함수 리터럴도 할당문이 실행되는 시점에 평가되어 함수 객체가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;함수 표현식으로 함수를 정의하면 함수 호이스팅이 발생하는 것이 아니라 변수 호이스팅이 발생&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Function 생성자 함수&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매개변수 목록과 함수 몸체를 문자열로 전달 받아 new로 생성이 가능하다. (new가 없어도 가능하다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;일반적이지도 않고, 바람직한 방법도 아니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추후 알아볼 클로저를 생성하지 않는 등, 앞서 알아본 것들과 다르게 동작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;화살표 함수&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ES6에 도입되었으며, 항상 익명함수로 정의한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;표현만 간략한게 아니라, 내부 동작 또한 간략화되어 있어 함수 선언문 혹은 함수 표현식을 완전히 대체하지는 못한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 특징을 간략히 알아보고, 추후에 다시한번 만나보도록 하자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;생성자 함수로 사용할 수 없다.&lt;/li&gt;
&lt;li&gt;기존 함수와 this 바인딩이 다르다.&lt;/li&gt;
&lt;li&gt;prototype 프로퍼티가 없다.&lt;/li&gt;
&lt;li&gt;arguments 객체를 생성하지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;함수의 호출&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;매개변수(parameter)와 인수(argument)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수가 호출되면 함수 몸체 내에 암묵적으로 매개변수가 생성되고 일반 변수와 마찬가지로 undefined로 초기화된 이후 인수가 순서대로 할당된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 별도로 알아보겠지만, 매개변수의 &lt;b&gt;스코프(유효 범위)&lt;/b&gt;는 함수 내부다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, &lt;b&gt;매개변수의 갯수와 인수의 갯수는 같은지 체크하지 않는다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매개변수가 인수보다 많다면, 할당되지 않은 매개변수에는 undefined가 들어가게 되며, 초과된 인수는 암묵적으로 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;arguments 객체&lt;/b&gt;&lt;/span&gt;의 프로퍼티로 보관된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입이 없는 자바스크립트에서는 어떤 타입이 파라미터로 전달되는지 알지 못한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 방지하기 위해 타입스크립트같은 정적 타입 선언 언어를 사용하기도 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;참조에 의한 전달과 외부 상태의 변경&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 파라미터로 객체를 받을 때 주의해야 할 점은 참조의 의한 전달이 있다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원시 타입은 변경이 불가능 하니, 파라미터에서 재할당을 통해 새로운 원시값으로 교체하여 기존 값의 변경이 되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 객체 타입으로 인수를 받는다면, 참조 값이 복사되어 원본에도 영향이 간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;다양한 함수의 형태&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;즉시 실행 함수&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수의 정의와 동시에 즉시 실행되는 함수다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단 한번만 호출되며 다시 호출할 수 없다.&lt;/p&gt;
&lt;pre id=&quot;code_1656857788925&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(function() {
    var a = 1;
    var b = 2;
    return a+b;
}());&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 이름없는 익명함수를 사용한다. (있어도, 사용할 수 없다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉시 실행함수는 반드시 그룹 연산자로 감싸야 한다. 그렇지 않으면 에러가 발생한다.&lt;/p&gt;
&lt;pre id=&quot;code_1656863285975&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function() { //Uncaught SyntaxError: Function statements require a function name
    var a = 1;
    var b = 2;
    return a+b;
}();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 에러가 나는 이유는 함수 정의가 함수 선언문에 맞지 않기 때문이다. (이름을 생략할 수 없다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이름을 넣어보자.&lt;/p&gt;
&lt;pre id=&quot;code_1656863343624&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function foo() { //Uncaught SyntaxError: Unexpected token ')'
    var a = 1;
    var b = 2;
    return a+b;
}();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러 내용이 바뀌었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트 엔진은 암묵적으로 수행하는 세미콜론 자동 삽입 기능으로, 함수 선언문 이후에 자동으로 세미콜론을 넣게 된다. (함수 코드 블록의 닫는 중괄호 뒤)&lt;/p&gt;
&lt;pre id=&quot;code_1656863427609&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function foo(){}(); // function foo(){};();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 선언문 뒤의 ()는 함수 호출 연산자가 아닌 그룹 연산자로 해석된다. 따라서, 그룹 연산자에 피연산자가 없어 에러가 나는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그룹 연산자의 피연산자는 값으로 평가되므로, 기명 또는 무명 함수를 그룹 연산자로 감싸면 함수 리터럴로 평가되어 함수 객체가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 그룹 연산자로 묶는 이유는 먼저 함수 리터럴을 평가해서 &lt;b&gt;함수 객체를 생성하기 위해서&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 함수 객체를 생성할 수 있으면, 다른 연산자를 사용해도 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1656863714993&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(function() {
	// ...
}());

(function() {
	// ...
})();

!function() {
	// ...
}();

+function() {
	// ...
}();&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;중첩 함수&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;함수 내부에 정의된 함수&lt;/b&gt;&lt;/span&gt;를 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;중첩 함수(Nested Function)&lt;/b&gt; &lt;/span&gt;또는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;내부 함수(Inner Function)&lt;/b&gt; &lt;/span&gt;이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중첩 함수는 외부 함수 내부에서만 호출 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 중첩 함수는 자신을 포함하는 외부 함수를 돕는 헬퍼 함수(Helper Function) 역할을 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1656864131604&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function outer() {
    var x = 1;

    // 중첩 함수
    function inner() {
        var y = 2;
        // 외부 함수의 변수를 참조할 수 있다.
        console.log(x+y); // 3
    }

    inner();
};

outer();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ES6부터 함수 정의는 문이 위치할 수 있는 문맥이면 어디든 가능하다. (if 문이나 for문 내에서도 가능하다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단, 호이스팅으로 혼란이 올 수 있으므로, if문이나 for 문 등의 코드 블록에서 함수 선언문을 통해 함수를 정의하는 것은 바람직하지 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중첩 함수는 이후 스코프나 클로져를 배울 때 한번 더 보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;콜백 함수&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;함수의 매개변수를 통해 다른 함수의 내부로 전달되는 함수&lt;/b&gt;를 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;콜백 함수&lt;/b&gt;&lt;/span&gt;라고 하며, &lt;b&gt;매개 변수를 통해 함수의 외부에서 콜백함수를 전달받는 함수&lt;/b&gt;를 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;고차 함수&lt;/b&gt;&lt;/span&gt;라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중첩 함수는 고정되어 있어 교체하기 곤란하지만, 콜백 함수는 함수 외부에서 고차 함수 내부로 주입하기 때문에, 자유로운 교체가 가능하다. 즉, &lt;b&gt;고차 함수는 콜백 함수를 자신의 일부분으로 합성한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;고차 함수는 매개변수를 통해 전달받은 콜백 함수의 호출 시점을 결정해 호출한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;즉, 고차함수에 의해 호출되며 이 때, 고차 함수는 필요에 따라 콜백 함수에 인수를 전달할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1656864573330&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function repeat(n, f) {
    for(var i = 0; i &amp;lt; n; i++) {
        f(i);
    }
};

var logAll = function(i) {
	console.log(i);
};

repeat(5, logAll);&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;순수 함수와 비순수 함수&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수형 프로그래밍에서 어떤 외부 상태에 의존하지도 않고 변경하지도 않는, 즉 부수 효과(Side Effect)가 없는 함수를 순수함수라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순수 함수는 동일한 입력이면 동일한 결과를 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수형 프로그래밍은 순수함수와 보조 함수의 조합을 통해 외부 상태를 변경하는 부수 효과를 최소화해서 불변성을 지향하는 프로그래밍 패러다임이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로직 내 존재하는 조건문과 반복문을 제거해서 복잡성을 해결하고, 변수 사용을 억제하거나 생명주기를 최소화해서 상태 변경을 피해 오류를 최소화하는 것을 목표로 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음에는 스코프에 대해 배워보도록 하자.&lt;/p&gt;</description>
      <category>Programming/javascript</category>
      <category>function</category>
      <category>JavaScript</category>
      <category>자바스크립트</category>
      <category>함수</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/43</guid>
      <comments>https://koocci-dev.tistory.com/43#entry43comment</comments>
      <pubDate>Mon, 4 Jul 2022 01:12:16 +0900</pubDate>
    </item>
    <item>
      <title>자바스크립트 기초부터 모던 자바스크립트까지 - 객체편</title>
      <link>https://koocci-dev.tistory.com/42</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : 자바스크립트의 객체가 무엇인지 알아본다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트의 이해를 위해 중요한 부분인 함수&amp;amp;스코프를 이해하기 위해서는 객체부터 들어가야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, 객체의 성질을 먼저 확인한 후 조금씩 확장해 보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;객체란?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;객체(Object)기반의 프로그래밍 언어&lt;/b&gt;&lt;/span&gt;이며, 자바스크립트를 구성하는 대의 대부분이 객체다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원시 값을 제외한 나머지 (함수, 배열, 정규 표현식 등) 모두 객체로 이루어져있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원론적인 개념이 아니라 자바스크립트에서 객체는 &lt;b&gt;다양한 타입의 값(원시 값 또는 다른 객체)을 하나의 단위로 구성하는 복합적인 &lt;span style=&quot;color: #ee2323;&quot;&gt;자료구조(Data Structure)&lt;/span&gt;&lt;/b&gt;다. (원시 값은 단 하나의 값만 나타낸다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;원시 값은 변경 불가능한 값이지만, 객체타입의 값, 즉 객체는 변경 가능한 값&lt;/b&gt;&lt;/span&gt;이다. (변수를 변경하지 못하는 것이 아니라, 값 자체를 의미한다. 변수는 재할당이 가능하다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;원시 값은 pass by value이지만, 객체타입은 pass by reference&lt;/b&gt;&lt;/span&gt; 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체는 0개 이상의 프로퍼티로 구성된 집합이고, 프로퍼티는 Key: Value로 이루어진다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로퍼티 : 객체의 상태를 나타내는 값(Data)&lt;/li&gt;
&lt;li&gt;메서드 : 프로퍼티(상태 데이터)를 참조하고 조작할 수 있는 동작(Behavior)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트에서 사용할 수 있는 모든 값은 프로퍼티 값이 될 수 있고, 자바스크립트의 함수는 &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;일급 객체&lt;/span&gt;&lt;/b&gt;이므로 값으로 취급이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 함수도 프로퍼티가 가능하다. 이 때, 프로퍼티로서의 함수는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;메서드&lt;/b&gt;&lt;/span&gt;라고 명명한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;객체의 생성&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스 기반의 다른 객체 지향 언어에서는 new와 같은 키워드를 통해 사전에 정의된 클래스의 생성자로 인스턴스를 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트는 객체 생성방법이 다양하며, 그 리스트는 아래와 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체 리터럴&lt;/li&gt;
&lt;li&gt;Object 생성자 함수&lt;/li&gt;
&lt;li&gt;생성자 함수&lt;/li&gt;
&lt;li&gt;Object.create 메서드&lt;/li&gt;
&lt;li&gt;클래스(ES6)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 대중적인 방법은 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;객체 리터럴&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체 리터럴은 중괄호 내에 0개 이상의 프로퍼티를 정의한다.&lt;/p&gt;
&lt;pre id=&quot;code_1656832995767&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var person = {
    name: 'Lee',
    sayHello: function() {
        console.log(`Hello: My name is ${this.name}.`);
    }
}

console.log(typeof person); // object
console.log(person); //{name: 'Lee', sayHello: f}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;몇가지 문법을 하기 예시로 대체한다.&lt;/p&gt;
&lt;pre id=&quot;code_1656833357864&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var person = {
    name: 'Lee',
    'last-name': 'foo', // 네이밍 규칙을 준수하지 않을 경우 사용 방법
    sayHello: function() {
        console.log(`Hello: My name is ${this.name}.`);
    }
}

console.log(person.name); // 접근 방법 1
console.log(person['name']); // 접근 방법 2

person.age = 20; // 동적 프로퍼티 생성
delete person.age; // 프로퍼티 삭제

//ES6
let x = 1, y = 2;
const obj = {x, y}; // 변수 이름과 프로퍼티 키가 동일할 때, 프로퍼티 키를 생략할 수 있다.
console.log(obj); // {x: 1, y: 2}

//ES5
var prefix = 'prop';
var i = 0;

var obj = {};

obj[prefix + '-' + ++i] = i;
obj[prefix + '-' + ++i] = i;
obj[prefix + '-' + ++i] = i;

console.log(obj); // {prop-1: 1, prop-2: 2, prop-3: 3}

//ES6
const prefix = 'prop';
let i = 0;

const obj = {
    [`${prefix}-${++i}`]: i,
    [`${prefix}-${++i}`]: i,
    [`${prefix}-${++i}`]: i
};

console.log(obj); // {prop-1: 1, prop-2: 2, prop-3: 3}

//ES6
var person = {
    name: 'Lee',
    sayHello() {
        console.log(`Hello: My name is ${this.name}.`);
    } // function을 축약하여 표현할 수 있다. 단, 다르게 동작하는 면이 있으므로, 추후에 알아보자
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체에 존재하지 않는 프로퍼티에 접근하면, undefined를 반환한다. 즉, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;ReferenceError가 발생하지 않으니 주의&lt;/b&gt;&lt;/span&gt;해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, delete는 없는 프로퍼티라도 에러를 뱉지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문자열&lt;/b&gt;의 경우는 조금 특이한 점이 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1656834033966&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var str = 'hello';
str = 'world';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;str은 변수이므로 재할당이 가능하다.(문자열 변경이 아니다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 문자열은 유사 배열 객체라고 하여 이터러블하여 배열과 유사하게 각 문자에 접근이 가능하다.&lt;/p&gt;
&lt;pre id=&quot;code_1656834182906&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var str = 'string';

console.log(str[0]); // s
console.log(str.length); // 6
console.log(str.toUpperCase()); // STRING

str[0] = 'S'; // 문자열 자체는 원시 타입으로 변경이 불가능 하다.
console.log(str); // string&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위처럼 원시타입이라 변경은 불가능하지만, 접근은 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;참조에 의한 전달&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서, 원시 값은 pass by value이며 객체는 pass by reference라고 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원시 값은 변경이 불가능하므로, 변수의 값을 변경하는 것은 재할당밖에 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 객체는 재할당 없이 변경이 가능하다. 동적 프로퍼티 추가나 갱신, 삭제가 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 공간을 만들고, 그곳을 바라보도록 재할당하는 원시타입과 달리, 메모리에 저장된 객체를 직접 수정할 수 있다는 것으로, 변수에 할당된 변수의 참조 값은 변경되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;여러 개의 식별자가 하나의 객체를 공유할 수 있다는 것&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, 얕은 복사, 깊은 복사 문제가 나오기도 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1656835056280&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const o = {x : {y: 1}};

const c1 = { ...o };
console.log(o === c1); // false;
console.log(o.x === c1.x); // true; // 같은 것을 바라본다. (얕은 복사)

var person = {
	name: 'Lee'
}

var copy = person;

console.log(copy === person); // true
copy.name = 'foo';
person.address = 'Seoul'; // 프로퍼티 추가

console.log(copy); // {name: 'foo', address: 'Seoul'}
console.log(person); // {name: 'foo', address: 'Seoul'}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/javascript</category>
      <category>es6</category>
      <category>JavaScript</category>
      <category>객체</category>
      <category>자바스크립트</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/42</guid>
      <comments>https://koocci-dev.tistory.com/42#entry42comment</comments>
      <pubDate>Sun, 3 Jul 2022 17:04:21 +0900</pubDate>
    </item>
    <item>
      <title>자바 기초부터 모던 자바까지 - 함수형 프로그래밍 편</title>
      <link>https://koocci-dev.tistory.com/41</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : 자바에서의 함수형 프로그래밍에 대해 알아본다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;왜 함수형 프로그래밍이 도입되기 시작했을까?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체 지향 프로그래밍의 정수였던 java에서 왜 새로운 패러다임을 도전하게 된 것일까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국에는&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt; 애플리케이션의 요구 조건 변경에 대응하는 절차&lt;/b&gt;&lt;/span&gt;였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 그 흐름을 따라가 보도록 하자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여행 정보를 조회하는 클래스가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;국가명을 통해 조회하며, 그 결과를 리스트로 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SearchTravel&lt;/b&gt; 이라는 이 클래스에는 &lt;b&gt;searchTravelInfo(String country)&lt;/b&gt; 라는 메소드로 이를 제공하고 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 요구사항이 등장했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;국가명도 제공해야하지만, 도시명으로도 제공해야했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그에 따라 2가지 변경 방안이 등장하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;도시 정보를 파라미터로 받아서 처리할 수 있는 메서드를 추가한다.
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;searchTravelInfo를, searchTravelInfoByCountry로 변경한다.&lt;/li&gt;
&lt;li&gt;searchTravelInfoByCity를 추가한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;기존 메서드에 파라미터를 추가한다.
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;searchTravelInfo(String country)를 searchTravelInfo(String searchType, String searchValue) 로 변경해, 로직으로 구분한다.&lt;/li&gt;
&lt;li&gt;함수 내부에서 searchType에 따라, 국가명 혹은 도시명을 검색하도록 한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제점은 동일하게 등장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 요구사항이 등장할 때 마다, 메소드를 늘리거나, 논리적 구분 소스를 추가해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 AND 요건 OR 요건 등에 따라 결국 또다른 문제가 등장하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;인터페이스로 대응&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AND 조건 등이 등장함에 따라 결국에는 이리저리 유지보수하면서 개발할 수는 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 유연한 대처를 위해 전체 소스를 변경하기로 하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검색 메서드를 인터페이스로 노출하고, 실제 실행 결과는 별도로 분리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여행 상품을 관리하는 클래스와 상품을 조회하는 로직을 분리하겠다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 너무나 다양하게 요청되는 조&lt;b&gt;회 조건 및 처리 메서드는 인터페이스로 분리해 외부에서 정의&lt;/b&gt;하고, 여행사 소프트웨어는 &lt;b&gt;상품을 관리하고 요청에 대응하는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1656829649426&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface TravelInfoFilter {
    public boolean isMatched(TravelInfoVO travelInfo);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;딱 한개의 메소드만 가진 인터페이스를 구현하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래에 다시한번 설명하겠지만, 자바8부터 한개의 메소드를 정의한 것을 함수형 인터페이스라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 searchTravelInfo 메소드를 변경해보도록 하자.&lt;/p&gt;
&lt;pre id=&quot;code_1656829875768&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class SearchingTravel {
    private List&amp;lt;TravelInfoVO&amp;gt; travelInfoList = new ArrayList&amp;lt;&amp;gt;();
    public List&amp;lt;TravelInfoVO&amp;gt; searchTravelInfo(TravelInfoFilter searchCondition) {
        List&amp;lt;TravelInfoVO&amp;gt; returnValue = new ArrayList&amp;lt;&amp;gt;();
        
        for(TravelInfoVO travelInfo : travelInfoList) {
            if(searchCondition.isMatched(travelInfo)) {
                returnValue.add(travelInfo);
            }
        }
        return returnValue;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매개변수로 인터페이스를 받아서, 인터페이스의 메소드를 통해 isMatched를 비교하는 로직으로 변경하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 해당 인터페이스로 구현된 클래스는 외부에게 맞기는 것으로 변경한 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1656830029482&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Main {
    public static void main(String[] args) {
        SearchingTravel st = new SearchingTravel();
        
        List&amp;lt;TravelInfoVO&amp;gt; searchTravel = st.searchTravelInfo(new TravelInfoFilter() {
            @Override
            public boolean isMatched(TravelInfoVO travelInfo) {
                if(travelInfo.getCountry().equals(&quot;vietnam&quot;)) {
                    return true;
                }
                return false;
            }
        })
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 클래스를 호출하는 로직을 구현하였다. (익명 클래스를 활용하였다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 람다 표현식으로 조금씩 바꿔보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;람다 표현식으로 코드 함축&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;익명 클래스를 활용하면 코드의 중복이 매우 심해질 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서는 베트남 하나였지만, 한국, 중국, 일본 등 추가할 때마다 변화는 적은데 코드는 매우 많이 늘어난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 람다 표현식으로 함축하면 다음과 같아진다.&lt;/p&gt;
&lt;pre id=&quot;code_1656830315099&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;List&amp;lt;TravelInfoVO&amp;gt; searchTravel = st.searchTravelInfo((TravelInfoVo travelInfo) -&amp;gt; travelInfo.getCountry().equals(&quot;vietnam&quot;));&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;꽤 많은 것이 함축되었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한가지 더 알아보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;메서드 참조&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바 7까지 변수 혹은 메서드의 파라미터로 전달할 수 있는 것은 객체나 기본 데이터뿐이였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바 8부터는 메서드 자체를 넘길 수 있게 되었고, 이를 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;메서드 참조(Method Reference)&lt;/b&gt;&lt;/span&gt;라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;익명 함수로 소스 코드 중복은 줄일 수 있을지 몰라도, 재사용성을 줄어들었는데, 이렇게 함수 자체를 넘길 수 있다면 재사용성 역시 개선될 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1656830637913&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static boolean isVietnam(TravelInfoVO travelInfo) {
    if(travelInfo.getCountry().equals(&quot;vietnam&quot;)) {
        return true;
    }
    return false;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 함수를 SearchTravel 클래스에 추가한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 메인 함수는 이렇게 변경될 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1656830707483&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;List&amp;lt;TravelInfoVO&amp;gt; searchTravel = st.searchTravelInfo(SearchingTravel::isVietnam);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파라미터조차 적지 않는 방식을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 포스팅 부터는 람다 표현식으로 변경하는 방법을 이제 알아볼 예정인데, 그 전에 한번 용어를 정리하고 가도록 하자.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;용어 정리&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;함수형 프로그래밍&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 간단히 알아본 람다를 공부하려면 가장 먼저&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;함수형 프로그래밍&lt;/b&gt;&lt;/span&gt;을 알아야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 람다라는 용어는 자바에서만 사용하는 것도 아니며 다른 언어(자바스크립트 등)에서 활용하는 것을 보았을 때, 사용법은 달라도 메소드 명까지 동일하게 활용되는 경우가 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수형 프로그래밍은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;순수 함수(pure function)&lt;/b&gt;&lt;/span&gt;를 구현하고 호출함으로써 외부 자료에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;부수적인 영향(Side Effect)&lt;/b&gt;&lt;/span&gt;를 주지 않도록 구현하는 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;순수 함수(pure function)&lt;/b&gt;&lt;/span&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;매개변수만을 사용하여 만드는 함수&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;함수 내부에서 함수 외부에 있는 변수를 사용하지 않아 함수가 수행되더라도 외부에는 영향을 주지 않는다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 말은 함수의 기능이 데이터에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;독립적&lt;/b&gt;&lt;/span&gt;임을 보장하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 동일한 데이터에 대해 동일한 결과를 보장하고, 다양한 데이터에 대해 같은 기능을 수행한다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, 병렬 처리에 안정성과 확장성을 제공하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;람다식&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;람다식은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;자바에서 함수형 프로그램을 구현한 방식&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수형 인터페이스를 선언하며 클래스를 호출하지 않고 메소드만 호출하여 기능을 수행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;몇 가지 특징들을 예시와 함께 알아보도록 하자.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;매개 변수가 하나인 경우 생략이 가능하다.&lt;/li&gt;
&lt;li&gt;중괄호 안의 구현부가 1문장이면 중괄호를 생략할 수 있다.&lt;/li&gt;
&lt;li&gt;중괄호 안 구현부가 1문장이더라도, return 문이라면 생략할 수 없다.&lt;/li&gt;
&lt;li&gt;만약 반환문 1개라면, return과 중괄호 모두 생략할 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1656828166329&quot; class=&quot;rust&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;str -&amp;gt; {System.out.println(str);}; // 1번
str -&amp;gt; System.out.println(str); // 2번
str -&amp;gt; return str.length(); // 3번 에러
str -&amp;gt; str.length(); // 4번
(x,y) -&amp;gt; x+y; // 4번&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;함수형 인터페이스&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;람다식을 선언하기 위한 인터페이스다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;익명 함수와 매개 변수만으로 구현되므로, 단 하나의 메서드만을 선언해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(두개 이상의 메서드가 생성되면, 어떤 메서드를 호출할지 애매해진다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;@FunctionalInterface&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;어노테이션을 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1656828166331&quot; class=&quot;angelscript&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@FunctionalInterface
public interface MyNumber {
    int getMax(int num1, int num2);
}

public class Main {
    public static void main(String[] args) {
        MyNumber max = (x,y) -&amp;gt; x&amp;gt;=y? x:y;
        System.out.println(max.getMax(10,20));
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;람다식을 구현하면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;익명 내부 클래스&lt;/b&gt;가 만들어지고, 이를 통해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;익명 객체&lt;/b&gt;가 생성된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://koocci-dev.tistory.com/39&quot;&gt;앞선 포스팅&lt;/a&gt;에 익명 내부 클래스를 알아보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/Java</category>
      <category>Java</category>
      <category>람다</category>
      <category>자바</category>
      <category>함수형 인터페이스</category>
      <category>함수형 프로그래밍</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/41</guid>
      <comments>https://koocci-dev.tistory.com/41#entry41comment</comments>
      <pubDate>Sun, 3 Jul 2022 15:55:54 +0900</pubDate>
    </item>
    <item>
      <title>자바 기초부터 모던 자바까지 - 인터페이스 편</title>
      <link>https://koocci-dev.tistory.com/40</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : 자바의 인터페이스에 대해 알아본다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;인터페이스&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터페이스가 무엇인지 그에 대한 개념을 설명하지는 않겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바는 다중상속을 지원하지 않는다거나, 추상화에 대한 내용을 모른다면 잘 정리된 다른 포스팅을 찾아 보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바8부터 람다와 함수형 프로그래밍을 적용하기 위해 인터페이스를 활용하기 시작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 기존의 인터페이스에는 무슨 문제점이 있었고, 어떻게 진화해 온 것인지 먼저 알아보려 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;인터페이스의 문제점&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터페이스는 주로 &lt;b&gt;여러 개의 구현체를 통일화한 명세서로 정의하기 위해 사용&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 인터페이스를 구현한 클래스들은 동일한 메소드 명으로 통일성을 확보하고, 구현 방법에 상관없이 자신이 원하는 메서드를 호출해 목적을 이룰 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나, 가장 치명적인 단점은&amp;nbsp; 명세서기 때문에 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;수정이 어렵다&lt;/b&gt;&lt;/span&gt;는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;딱 메소드 2개의 아래 인터페이스를 보자.&lt;/p&gt;
&lt;pre id=&quot;code_1656747677668&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface EncryptionIF {
    public byte[] encrypt(byte[] bytes) throws Exception;
    public byte[] decrypt(byte[] bytes) throws Exception;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;암호화 알고리즘 인터페이스로, 위 2가지 메소드 명세서를 만들어 배포했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수십개의 팀이 이 인터페이스를 활용해 잘 사용하고 있었는데, 기능을 추가해야하는 경우가 생겼다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;몇몇 팀이 파라미터로 들어온 값이 암호화 알고리즘으로 암호화된 것인지 확인하는 기능이었다.&lt;/p&gt;
&lt;pre id=&quot;code_1656747765849&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface EncryptionIF {
    public byte[] encrypt(byte[] bytes) throws Exception;
    public byte[] decrypt(byte[] bytes) throws Exception;
    public boolean isEncoded(byte[] bytes) throws Exception;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 수정/배포하면 다음과 같은 문제점들이 속출한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;인터페이스 배포 후 해당 인터페이스를 구현한 모든 클래스에서 컴파일 에러가 발생한다.&lt;/li&gt;
&lt;li&gt;구현한 클래스가 너무 많아 이를 모두 한번에 수정하는 것이 어렵다.&lt;/li&gt;
&lt;li&gt;내부에서 사용하는 인터페이스가 아니라 외부 노출되는 오픈된 규격이였다.&lt;/li&gt;
&lt;li&gt;클래스를 수정하지 않고 인터페이스를 컴파일하여 배포하면 NoSuchMethod 에러가 발생한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 그 다음으로 고민하는 과정은 버져닝이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;업그레이드가 아닌 새로운 규격을 내는 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1656747953576&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface EncryptionChecker {
    public boolean isEncoded(byte[] bytes) throws Exception;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;임시 방편은 될 수 있지만, 매번 수정이 일어날 때마다 인터페이스를 새롭게 제공할 수는 없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 사고가 자바에서 제공하는 API 중 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;컬렉션 프레임워크&lt;/b&gt;&lt;/span&gt;에서 발생했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바의 버전이 올라갈 수록 새로운 환경(멀티 쓰레드 등)에 대응하고자 하는 자료 구조는 계속 생겨나는데, 컬렉션 프레임워크의 핵심 인터페이스는 수정을 못하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;인터페이스의 진화&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 인터페이스의 기능을 대대적으로 변경하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 핵심이 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;디폴트(default) 메서드&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최초의 자바 버전(1.x)에서는 인터페이스 제약이 다음과 같았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;상수를 선언할 수 있다.&lt;/b&gt; 해당 상수는 반드시 값이 할당되어 있어야 하며 변경하지 못한다. 명시적으로 final처리를 안해도 final로 인식한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;메서드는 반드시 추상(abstract)메서드여야 한다.&lt;/b&gt; 즉, 구현체가 아니라 메서드 명세만 정의되어야 한다.&lt;/li&gt;
&lt;li&gt;인터페이스를 구현한 클래스는 인터페이스에서 정의한 메서드를 구현하지 않았다면 반드시 추상 클래스로 선언되어야 한다.&lt;/li&gt;
&lt;li&gt;인터페이스에 선언된 상수와 메서드에 public을 선언하지 않더라도 public으로 인식한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바 버전 1.2부터는 몇가지 추가가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;중첩(Nested) 클래스를 선언할 수 있다. 선언은 내부(Inner)클래스 같지만, 실제로는 중첩 클래스로 인식한다.&lt;/li&gt;
&lt;li&gt;중첩(Nested)인터페이스를 선언할 수 있다.&lt;/li&gt;
&lt;li&gt;위의 중첩 클래스와 중첩 인터페이스는 모두 public과 static이어야 하며 생략 가능하다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;b&gt;&lt;a href=&quot;https://koocci-dev.tistory.com/39&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이전 포스팅&lt;/a&gt;에서 내부 클래스를 설명할 때도 설명했지만, 현재 참고중인 자료에는 중첩 클래스와 내부 클래스를 구분하고 있다.&lt;/b&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;b&gt;중첩 클래스는 클래스나 인터페이스 내부에 static으로 선언된 클래스임을 확인하자.&lt;/b&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중첩클래스를 통해 인터페이스 내부에서 세부 동작에 대해 상세히 규정할 수 있고, 개발자가 구현할 필요 없이 인터페이스 차원에서 제어할 수 있게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바 버전 5부터는 새로운 기능인 &lt;b&gt;제네릭, Enum, 어노테이션&lt;/b&gt;이 인터페이스에 영향을 주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;중첩(Nested) 열거형(Enum)을 선언할 수 있다.&lt;/li&gt;
&lt;li&gt;중첩(Nested) 어노테이션을 선언할 수 있다 (위의 중첩 열거형과 중첩 어노테이션은 모두 public과 static이어야 하며 생략가능하다)&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제네릭의 등장으로 인터페이스 선언문과 메서드 선언에 모두 타입 파라미터를 사용할 수 있게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단, 타입파라미터로 변수나 상수를 선언할 수 없고, 오직 메서드의 리턴 타입과 인수 타입에만 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, 자바 8부터는 또다시 2가지가 추가된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;실제 코드가 완성되어 있는 static 메서드를 선언할 수 있다.&lt;/li&gt;
&lt;li&gt;실제 코드가 완성되어 있는 default 메서드를 선언할 수 있다. (위의 static 메서드와 default 메서드는 모두 public 메서드로 인식하며 public 선언은 생략할 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 중요한 변화는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;실제 구현된 코드&lt;/b&gt;&lt;/span&gt;를 정의할 수 있다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론, static메서드나 default 둘 중 하나가 전제 조건이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 클래스에서도 별도로 정의할 필요가 없다. 이를 통해 굳이 &lt;b&gt;메서드를 사용하는 클래스에서 구현하지 않아도 컴파일 에러가 나지 않는다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 변화는 8버전부터 Collection 인터페이스에 메서드를 추가하게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바 9버전 부터는 또 한가지가 추가된다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;private 메서드를 선언할 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에는 public 메소드만 가능했고, 접근자를 선언하지 않고 메서드를 정의해도 public으로 인식했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 변화는 클래스의 외부에는 공개되지 않더라도 인터페이스 내부의 static 메서드와 default 메서드의 로직을 공통화하고 재사용하는데 유용해졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단, private 메서드는 실제 동작하는 소스 코드까지 구현해야한다는 제약이 있다. 즉, 자바 8의 static 혹은 default 메서드와 동일한 개념을 가진 기능의 발전이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정리해보면 현재 인터페이스에는 총 9가지를 선언할 수 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;상수&lt;/li&gt;
&lt;li&gt;추상 메서드&lt;/li&gt;
&lt;li&gt;중첩 클래스&lt;/li&gt;
&lt;li&gt;중첩 인터페이스&lt;/li&gt;
&lt;li&gt;중첩 열거형&lt;/li&gt;
&lt;li&gt;중첩 어노테이션&lt;/li&gt;
&lt;li&gt;static 메서드&lt;/li&gt;
&lt;li&gt;default 메서드&lt;/li&gt;
&lt;li&gt;private 메서드&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;클래스와의 차이점과 제약 조건&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터페이스가 구현이 되게 된다면, 클래스와의 차이는 어떻게 될 것인가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추상클래스와 인터페이스의 차이점은 하기와 같다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;추상 클래스는 멤버 변수를 가질 수 있지만 인터페이스는 멤버 변수를 가질 수 없다. static으로 정의된 변수를 내부적으로 선언할 수 있지만 멤버 변수는 선언할 수 없다.&lt;/li&gt;
&lt;li&gt;클래스를 구현할 때 오직 하나의 클래스만을 상속받을 수 있는 반면에 인터페이스는 여러 개를 상속받거나 구현할 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 가장 큰 차이점은 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;멤버 변수의 선언 유무&lt;/b&gt;&lt;/span&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멤버변수는 &lt;b&gt;그 객체의 속성을 담아두기 위한 용도&lt;/b&gt;인데, 인터페이스에서 멤버 변수가 없다는 것은 &lt;b&gt;인터페이스 자체를 객체화 할 수 없다는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바는 다중 상속이 허용되지 않지만, 인터페이스를 통해 여러 인터페이스를 구현할 수는 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마치 상속과 비슷하게 default 메서드, private, static 메서드의 기능을 이어 받을 수 있게 되었고 특히 default 메서드는 &lt;b&gt;오버라이드&lt;/b&gt;도 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1656826056391&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface HouseAddress {
    public static final String DefaultCountry = &quot;Korea&quot;;
    
    public String getPostCode();
    default public String getCountryCode() {
        return getDefaultCountryCode();
    }
    
    private String getDefaultCountryCode() {
        return HouseAddress.DefaultCountry;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 인터페이스를 구현한 클래스를 보자.&lt;/p&gt;
&lt;pre id=&quot;code_1656826162305&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class KoreaHouseAddress implements HouseAddress {
    private String postCode;

    @Override
    public String getPostCode() {
        return null;
    }

    @Override
    public String getCountryCode() {
        return HouseAddress.super.getCountryCode();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분 super 키워드를 통해 상위 클래스의 메서드 혹은 속성에 접근하는데, 당연히 인터페이스다 보니 Object 클래스가 연결된다.&lt;/p&gt;
&lt;pre id=&quot;code_1656826250248&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;HouseAddress.super.getCountryCode();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, 자바 8부터는 위와 같은 방법으로 상위 인터페이스의 메소드로 연결지을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;다중 상속 관계&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바에서는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;다중 상속을 지원하지 않는다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복잡성이 높아져 버그가 많이 발생하고 유지보수가 어려워진다는 것이 그 이유다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 인터페이스의 default의 등장은 조금 난감한 이슈가 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;private 메서드&lt;/b&gt;&lt;/span&gt;는 자바의 접근 규칙에 따라, &lt;b&gt;하위 클래스로 상속되지 않는다&lt;/b&gt;. 즉, private 메서드가 인터페이스에 있더라도 문제가 되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;static 메서드&lt;/b&gt;&lt;/span&gt;도 인터페이스 레벨 혹은 클래스 레벨로 정의되므로(컴파일 타임에 생성되는 사항이라 상속이 불가하다)&amp;nbsp;&lt;b&gt;메서드 오버라이드의 범위에 속하지 않는다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 default 메소드는 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, 흔히 다중 상속의 문제점인 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;다이아몬드 상속&lt;/b&gt;&lt;/span&gt;과 같은 문제가 발생한다.&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;514&quot; data-origin-height=&quot;378&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/diXQwJ/btrGhVL2fef/6uK3d8nYgUCbVJmBMdvvIK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/diXQwJ/btrGhVL2fef/6uK3d8nYgUCbVJmBMdvvIK/img.png&quot; data-alt=&quot;다이아몬드 상속&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/diXQwJ/btrGhVL2fef/6uK3d8nYgUCbVJmBMdvvIK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdiXQwJ%2FbtrGhVL2fef%2F6uK3d8nYgUCbVJmBMdvvIK%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;514&quot; height=&quot;378&quot; data-origin-width=&quot;514&quot; data-origin-height=&quot;378&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;다이아몬드 상속&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Worker 입장에서 default 메소드로 만들어진 성별을 가져오려고 하면, Duplicate 에러가 날 수 밖에 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 클래스에서 받아야 할지 모호하기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 피하기 위해서는 결국 Worker에서 오버라이드를 필수적으로 해야한다. (앞서 확인한 super 키워드를 통해서도 가능하다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, 만약에 &lt;b&gt;Man이 Abstract 클래스라면&lt;/b&gt; 어떻게 될 것인가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성별을 가져오는 getSex() 메소드가 있을 때, Person에서는 default로 구현되었을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Man이라는 클래스에서는 이를 Abstract 클래스로 가져왔고, Woman은 인터페이스로 가져왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 없다. 다만, &lt;b&gt;Worker에서 오버라이드를 하지 않아도 에러가 나지 않는다는 것이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때는 &lt;b&gt;클래스가 우선적으로 적용&lt;/b&gt;된다. 즉, Man에 적용된 getSex()메소드가 호출되는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요약하면 다음과 같다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;클래스가 인터페이스에 대해 우선순위를 가진다. 동일한 메서드가 인터페이스와 클래스에 둘 다 있다면 클래스가 우선이다.&lt;/li&gt;
&lt;li&gt;위의 조건을 제외하고 상속관계에 있을 경우 하위 클래스/인터페이스가 상위 클래스/인터페이스보다 우선된다.&lt;/li&gt;
&lt;li&gt;위의 두가지 조건을 제외하고 메서드 호출 시 어떤 메서드를 호출해야할지 모호할 경우, 컴파일 에러가 발생할 수 있으며, 명확한 지정이 필요하다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;하나 신경써야 할 것은 버전이 올라갈 수록 인터페이스 기능이 많아졌다고 하여, 남용하는 것은 좋지 않다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;본연의 인터페이스 역할에 충실하고 영향을 최소화하도록 구현하는 것이 가장 명확한 해답이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/Java</category>
      <category>default</category>
      <category>Interface</category>
      <category>Java</category>
      <category>인터페이스</category>
      <category>자바</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/40</guid>
      <comments>https://koocci-dev.tistory.com/40#entry40comment</comments>
      <pubDate>Sun, 3 Jul 2022 15:04:21 +0900</pubDate>
    </item>
    <item>
      <title>자바 기초부터 모던 자바까지 - 내부&amp;amp;중첩 클래스편</title>
      <link>https://koocci-dev.tistory.com/39</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : 자바의 내부&amp;amp;중첩 클래스에 대해 알아본다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Inner Class&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스에 전반적인 내용을 모두 적진 않을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체 지향의 거대한 3요소인 &lt;b&gt;상속, 다형성, 캡슐화&lt;/b&gt; 등에 대해서는 너무나도 많은 자료가 있으니 별도로 알아보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금 알아볼 것은 Class안의 Class의 동작에 대해 알아볼 에정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Inner Class(내부 클래스)&lt;/b&gt;&lt;/span&gt;는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;중첩 클래스&lt;/b&gt;&lt;/span&gt;라고도 표현하는 사람도 많지만, 약간 다르게 설명하는 경우도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;중첩 클래스는 클래스나 인터페이스 내부에 static으로 선언된 클래스다.&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;b&gt;포스팅을 위해 참고한 자료에서도 중첩 클래스는 내부 클래스와 동일 시하여 표현하고 있어, 하기 내용이 조금 헤깔릴 수 있으나 명확하게 구분하는 사람도 있으니 참고하도록 하자.&lt;/b&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스 내부에 선언한 클래스로 이 클래스를 감싸고 있는 외부 클래스와 밀접한 연관이 있는 경우가 많고, 다른 외부 클래스에서 사용할 일이 거의 없는 경우에 내부 클래스로 선언해서 사용하기도 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 종류로는 4가지 정도로 구분될 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인스턴스 내부 클래스&lt;/li&gt;
&lt;li&gt;정적(static) 내부 클래스&lt;/li&gt;
&lt;li&gt;지역(local) 내부 클래스&lt;/li&gt;
&lt;li&gt;익명(anonymous) 내부 클래스&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한가지씩 알아보도록 하자.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;인스턴스 내부 클래스&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내부적으로 사용할 클래스를 선언하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내부적으로 사용하다 보니, private로 선언하는 것을 권장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외부 클래스가 생성된 후에 생성되며, public으로 선언하면 외부 클래스에서도 호출을 할 수 있게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래에 예시 코드는 static 변수나 메서드를 함께 확인해볼 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 차이가 있는지 비교해보면서 보도록 하자.&lt;/p&gt;
&lt;pre id=&quot;code_1656742373179&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class OuterClass {
    private int num = 10;
    private static int sNum = 20;
    private InnerClass innerClass;

    public OuterClass(){
        innerClass = new InnerClass(); // 내부 클래스 생성
    }
    class InnerClass {
        int inNum = 100;
        //        static int staticInNum = 200; // 에러남
        void inTest() {
            System.out.println(&quot;OuterClass num = &quot; + num + &quot;(외부 클래스의 인스턴스 변수)&quot;);
            System.out.println(&quot;OuterClass sNum = &quot; + sNum + &quot;(외부 클래스의 스태틱 변수)&quot;);
            System.out.println(&quot;InnerClass inNum = &quot; + inNum + &quot;(내부 클래스의 인스턴스 변수)&quot;);
        }
    }

    public void usingClass() {
        innerClass.inTest();
    }
}


public class Main {
    public static void main(String[] args) {
        OuterClass outClass = new OuterClass();
        outClass.usingClass(); // inClass의 inTest가 실행

        // private가 아니면 외부 실행 가능
        OuterClass.InnerClass inner = outClass.new InnerClass(); // 만들 수 있지만, 사용하길 지양해야 함
        inner.inTest();

    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 결과는 아래와 같이 출력된다&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OuterClass&amp;nbsp;num&amp;nbsp;=&amp;nbsp;10(외부&amp;nbsp;클래스의&amp;nbsp;인스턴스&amp;nbsp;변수)&lt;br /&gt;OuterClass&amp;nbsp;sNum&amp;nbsp;=&amp;nbsp;20(외부&amp;nbsp;클래스의&amp;nbsp;스태틱&amp;nbsp;변수)&lt;br /&gt;InnerClass&amp;nbsp;inNum&amp;nbsp;=&amp;nbsp;100(내부&amp;nbsp;클래스의&amp;nbsp;인스턴스&amp;nbsp;변수)&lt;br /&gt;OuterClass&amp;nbsp;num&amp;nbsp;=&amp;nbsp;10(외부&amp;nbsp;클래스의&amp;nbsp;인스턴스&amp;nbsp;변수)&lt;br /&gt;OuterClass&amp;nbsp;sNum&amp;nbsp;=&amp;nbsp;20(외부&amp;nbsp;클래스의&amp;nbsp;스태틱&amp;nbsp;변수)&lt;br /&gt;InnerClass&amp;nbsp;inNum&amp;nbsp;=&amp;nbsp;100(내부&amp;nbsp;클래스의&amp;nbsp;인스턴스&amp;nbsp;변수)&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예시에서 보면, InnerClass내의 static 변수는 선언할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 말했지만, OuterClass가 먼저 생성되고 InnerClass가 생성되게 된다. (생성자로 InnerClass를 생성해야 한다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;static 변수는 OuterClass랑 상관없이 사용하게 되버린다. (메소드도 마찬가지다) (&lt;a title=&quot;앞선 포스팅&quot; href=&quot;https://koocci-dev.tistory.com/32&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;앞선 포스팅을 확인하자&lt;/a&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;정적 내부 클래스 (Static Inner Class)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내부 클래스 선언에 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;static&lt;/b&gt;&lt;/span&gt;을 붙여보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외부 클래스와 무관하게 사용할 수 있다. (static 변수, static 메소드 사용)&lt;/p&gt;
&lt;pre id=&quot;code_1656743420789&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class OuterClass {
    private int num = 10;
    private static int sNum = 20;

    static class InnerStaticClass {
        int inNum = 100;
        static int sInNum = 200;

        void inTest() {
//            num ++; // 에러남
            sNum ++;
            inNum ++;
            sInNum ++;
//            System.out.println(&quot;OuterClass num = &quot; + num + &quot;(외부 클래스의 인스턴스 변수)&quot;); // 에러남
            System.out.println(&quot;OuterClass sNum = &quot; + sNum + &quot;(외부 클래스의 스태틱 변수)&quot;);
            System.out.println(&quot;InStaticClass inNum = &quot; + inNum + &quot;(내부 클래스의 인스턴스 변수 사용)&quot;);
            System.out.println(&quot;InStaticClass sInNum = &quot; + sInNum + &quot;(내부 클래스의 스태틱 변수 사용)&quot;);
        }

        static void sTest() {
            //num += 10;   // 외부 클래스의 인스턴스 변수는 사용할 수 없음.
            //inNum += 10; // 내부 클래스의 인스턴스 변수는 사용할 수 없음.
            sInNum += 10;

//            System.out.println(&quot;OuterClass num = &quot; + num + &quot;(외부 클래스의 인스턴스 변수)&quot;); // 에러남
            System.out.println(&quot;OuterClass sNum = &quot; + sNum + &quot;(외부 클래스의 스태틱 변수)&quot;);
//            System.out.println(&quot;InStaticClass inNum = &quot; + inNum + &quot;(내부 클래스의 인스턴스 변수 사용)&quot;); // 에러남
            System.out.println(&quot;InStaticClass sInNum = &quot; + sInNum + &quot;(내부 클래스의 스태틱 변수 사용)&quot;);
        }
    }
}

public class Main {
    public static void main(String[] args) {
        //외부 클래스 생성하지 않고 바로 정적 내부 클래스 생성
        OuterClass.InnerStaticClass sInClass = new OuterClass.InnerStaticClass();
        System.out.println(&quot;정적 내부 클래스 일반 메서드 호출&quot;);
        sInClass.inTest();
        System.out.println();
        System.out.println(&quot;정적 내부 클래스의 스태틱 메소드 호출&quot;);
        OuterClass.InnerStaticClass.sTest();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정적&amp;nbsp;내부&amp;nbsp;클래스&amp;nbsp;일반&amp;nbsp;메서드&amp;nbsp;호출&lt;br /&gt;OuterClass&amp;nbsp;sNum&amp;nbsp;=&amp;nbsp;21(외부&amp;nbsp;클래스의&amp;nbsp;스태틱&amp;nbsp;변수)&lt;br /&gt;InStaticClass&amp;nbsp;inNum&amp;nbsp;=&amp;nbsp;101(내부&amp;nbsp;클래스의&amp;nbsp;인스턴스&amp;nbsp;변수&amp;nbsp;사용)&lt;br /&gt;InStaticClass&amp;nbsp;sInNum&amp;nbsp;=&amp;nbsp;201(내부&amp;nbsp;클래스의&amp;nbsp;스태틱&amp;nbsp;변수&amp;nbsp;사용)&lt;br /&gt;&lt;br /&gt;정적&amp;nbsp;내부&amp;nbsp;클래스의&amp;nbsp;스태틱&amp;nbsp;메소드&amp;nbsp;호출&lt;br /&gt;OuterClass&amp;nbsp;sNum&amp;nbsp;=&amp;nbsp;21(외부&amp;nbsp;클래스의&amp;nbsp;스태틱&amp;nbsp;변수)&lt;br /&gt;InStaticClass sInNum = 211(내부 클래스의 스태틱 변수 사용)&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;static 이라는 용어의 성질을 알면 에러나는 이유를 유추할 수 있을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;언제 메모리에 로드되는지 잘 생각해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외부의 멤버 변수는 당연히 호출할 수 없고, 자신의 멤버변수라고 하더라도, static 메소드에서는 호출 할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;지역 내부 클래스&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지역 변수와 같이 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;메서드 내부&lt;/b&gt;&lt;/span&gt;에서 정의한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메서드의 호출이 끝나면 메서드에 사용된 지역변수의 유효성은 사라진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메서드 호출 이후에도 사용해야 하는 경우가 있을 수 있으므로 지역 내부 클래스에서 사용하는 메서드의 지역 변수나 매개 변수는&lt;/p&gt;
&lt;p data-sourcepos=&quot;174:1-174:18&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;final&lt;/b&gt;&lt;/span&gt;로 선언된다.&lt;/p&gt;
&lt;p data-sourcepos=&quot;174:1-174:18&quot; data-ke-size=&quot;size16&quot;&gt;하기의 Runnable을 활용한 예시를 보도록 하자.&lt;/p&gt;
&lt;pre id=&quot;code_1656744088898&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class OuterClass {
    private int outNum = 10;
    private static int sNum = 20;

    Runnable getRunnable(int i) {
        int num = 100; // 로컬 변수 = stack 메모리

        class MyRunnable implements Runnable {
            int localNum = 10; // 클래스 멤버 변수

            @Override
            public void run() {
//                num = 200; // 에러남. 지역변수는 상수로 바뀐다.
//                i = 100; // 에러남. 매개 변수 역시 지역변수처럼 상수로 바뀐다.
                outNum ++;
                sNum ++;

                System.out.println(&quot;i = &quot; + i);
                System.out.println(&quot;num = &quot; + num);
                System.out.println(&quot;localNum = &quot; + localNum);

                System.out.println(&quot;outNum = &quot; + outNum + &quot;(외부 클래스 인스턴스 변수)&quot;);
                System.out.println(&quot;sNum = &quot; + OuterClass.sNum + &quot;(외부 클래스 정적 변수)&quot;);
            }
        }
        return new MyRunnable();
    }

}

public class Main {
    public static void main(String[] args) {
        OuterClass out = new OuterClass();
        Runnable runner = out.getRunnable(10);
        runner.run();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;i&amp;nbsp;=&amp;nbsp;10&lt;br /&gt;num&amp;nbsp;=&amp;nbsp;100&lt;br /&gt;localNum&amp;nbsp;=&amp;nbsp;10&lt;br /&gt;outNum&amp;nbsp;=&amp;nbsp;11(외부&amp;nbsp;클래스&amp;nbsp;인스턴스&amp;nbsp;변수)&lt;br /&gt;sNum&amp;nbsp;=&amp;nbsp;21(외부&amp;nbsp;클래스&amp;nbsp;정적&amp;nbsp;변수)&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;getRunnable함수 자체는 생성되고 사라지지만, run함수는 다시 호출될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;stack메모리에 잡히면 쓸 수 없으므로, final처리가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;익명 내부 클래스&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름이 없는 클래스다. (위 지역 내부 클래스의 MyRunnable 클래스 이름은 실제로 호출되는 경우가 없다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스의 이름을 생략하고 주로 하나의 인터페이스나 하나의 추상 클래스를 구현하여 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터페이스나 추상 클래스 자료형의 변수에 직접 대입하여 클래스를 생성하거나 지역 내부 클래스의 메서드 내부에서 생성하여 반환 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안드로이드 widget의 이벤트 핸들러에 활용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1656744775350&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class OuterClass {
    private int outNum = 10;
    private static int sNum = 20;

    Runnable getRunnable(int i) {
        int num = 100; // 로컬 변수 = stack 메모리

        return new Runnable() {
            int localNum = 10; // 클래스 멤버 변수

            @Override
            public void run() {
//                num = 200; // 에러남. 지역변수는 상수로 바뀐다.
//                i = 100; // 에러남. 매개 변수 역시 지역변수처럼 상수로 바뀐다.
                outNum ++;
                sNum ++;

                System.out.println(&quot;i = &quot; + i);
                System.out.println(&quot;num = &quot; + num);
                System.out.println(&quot;localNum = &quot; + localNum);

                System.out.println(&quot;outNum = &quot; + outNum + &quot;(외부 클래스 인스턴스 변수)&quot;);
                System.out.println(&quot;sNum = &quot; + OuterClass.sNum + &quot;(외부 클래스 정적 변수)&quot;);
            }
        };
    }

    Runnable runner = new Runnable() {
        @Override
        public void run() {
            System.out.println(&quot;Runnable 이 구현된 익명 클래스 변수&quot;);
        }
    };

}

public class Main {
    public static void main(String[] args) {
        OuterClass out = new OuterClass();
        Runnable runnable = out.getRunnable(10);
        runnable.run();
        out.runner.run();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;i&amp;nbsp;=&amp;nbsp;10&lt;br /&gt;num&amp;nbsp;=&amp;nbsp;100&lt;br /&gt;localNum&amp;nbsp;=&amp;nbsp;10&lt;br /&gt;outNum&amp;nbsp;=&amp;nbsp;11(외부&amp;nbsp;클래스&amp;nbsp;인스턴스&amp;nbsp;변수)&lt;br /&gt;sNum&amp;nbsp;=&amp;nbsp;21(외부&amp;nbsp;클래스&amp;nbsp;정적&amp;nbsp;변수)&lt;br /&gt;Runnable&amp;nbsp;이&amp;nbsp;구현된&amp;nbsp;익명&amp;nbsp;클래스&amp;nbsp;변수&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 inner class에 대해 간단히 알아보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/Java</category>
      <category>inner class</category>
      <category>Java</category>
      <category>내부클래스</category>
      <category>자바</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/39</guid>
      <comments>https://koocci-dev.tistory.com/39#entry39comment</comments>
      <pubDate>Sat, 2 Jul 2022 15:57:46 +0900</pubDate>
    </item>
    <item>
      <title>자바 기초부터 모던 자바까지 - 객체 편</title>
      <link>https://koocci-dev.tistory.com/38</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : 자바의 객체의 개론을 알아본다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Object&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체가 무엇인지를 정의하고자 한다기 보다, 내가 아는 내용을 정리하고자 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세상 모든 것을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;개체&lt;/b&gt;&lt;/span&gt;라고 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개체 중에서 내가 관심을 가지는 영역을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;객체&lt;/b&gt;&lt;/span&gt;로 바라보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, 그 객체의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;성격과 행동, 서로간의 소통&lt;/b&gt;&lt;/span&gt;들을 정의해나갈 수 있을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 그 객체에 대해 내가 관심이 있고, 다루고자 하는 영역들을 성격과 행동이라는 용어로 정리하다 보면 특정해 나갈 수 있게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 클래스라는 용어로 불러본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사람이라는 객체가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;철학적인 물음으로 사람이란 무엇인가?에 대해서 대답하고자 하는건 아니다. (나라는 것은 무엇인가? 라는 질문으로 넘어가면 철학과 과학의 오묘한 결합이 나오게 된다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇지만 우리가 원하는 어떠한 결과물을 위해서는 원하는 바를 정리해보며 사람을 만들어가야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;눈이 있고, 코가 있고, 귀가 있으며, 옆 사람과 대화할 수 있는 것&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이라고 먼저 정의했다고 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 사람이라는 것의 특징은 눈, 코, 귀가 있다는 것. 그리고 옆 사람과 대화를 한다는 행동을 정의할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1656745000847&quot; class=&quot;angelscript&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Person {
    private Eye eye;
    private Nose nose;
    private Ear ear;

    public void conversation(Person person) {
    
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아주 간단한 클래스가 만들어졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;민수, 철수, 영희 모두 사람이라고 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스를 통해 민수를 만들고, 철수, 영희를 만들면 그것이 인스턴스라는 용어로 통용될 수 있게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;심지어, 대화도 할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1656745000848&quot; class=&quot;haxe&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Person minsoo = new Person();
Person chulsoo = new Person();
Person younghee = new Person();

minsoo.conversation(chulsoo);
minsoo.conversation(younghee);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성격 혹은 특징(속성)은 클래스의 멤버 변수(Member Variable)로 표현했으며, 그 행동은 메서드(Method)를 통해 만들어 주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;붕어빵과 붕어빵 틀이라는 유명한 비유가 있다. (위 사람과도 비교해보자)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비유는 모든 것을 설명하지 못하지만, 이해력을 높여주는 좋은 도구다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;붕어빵이라는 것에 내가 관심이 있고, 그 관심에 대한 성격과 행동, 소통들을 정의해 나가다보면 하나의 틀이 만들어진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;붕어빵 사장님은 관심사들을 찍어내기 위해 붕어빵 틀이라는 것을 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 붕어빵들을 열심히 찍어낼 수 있게 되는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;프로그램도 결국 내가 관심을 가지는 영역을 프로그램 언어로서 성격을 규정하고, 행동, 소통들을 정의해 원하고자 하는 바를 구현한 결과물이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조금 다른 용어로 이를 정의해보면,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;클래스&lt;/span&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;객체의 청사진(BluePrint&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;)&lt;/span&gt;라고 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Object Class&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 객체라는 용어에 대해 정리해보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java에서도 모든 객체의 최상위 클래스는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Object 클래스&lt;/b&gt;&lt;/span&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;굳이, import하지 않아도 자동으로 import되며, 모든 클래스는 Object에서 상속받고, Object 클래스의 메서드 중 일부는 재정의해서 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 자동으로 extends Object가 되는 것이라 보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, Object의 메소드 중 가장 많이 쓰는 것은 toString(), equals(), hashCode()가 있을 것이다.&lt;/p&gt;</description>
      <category>Programming/Java</category>
      <category>Java</category>
      <category>object</category>
      <category>객체</category>
      <category>자바</category>
      <category>클래스</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/38</guid>
      <comments>https://koocci-dev.tistory.com/38#entry38comment</comments>
      <pubDate>Sat, 2 Jul 2022 15:57:07 +0900</pubDate>
    </item>
    <item>
      <title>[java] Remove Nth Node From End of List</title>
      <link>https://koocci-dev.tistory.com/35</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;[참고문제] : &lt;a href=&quot;https://leetcode.com/problems/remove-nth-node-from-end-of-list/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://leetcode.com/problems/remove-nth-node-from-end-of-list/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1656736229098&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Remove Nth Node From End of List - LeetCode&quot; data-og-description=&quot;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&quot; data-og-host=&quot;leetcode.com&quot; data-og-source-url=&quot;https://leetcode.com/problems/remove-nth-node-from-end-of-list/&quot; data-og-url=&quot;https://leetcode.com/problems/remove-nth-node-from-end-of-list/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/btTClM/hyOYr0yDT4/QUygXJimoCQ9rMH2NQGAYk/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/remove-nth-node-from-end-of-list/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://leetcode.com/problems/remove-nth-node-from-end-of-list/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/btTClM/hyOYr0yDT4/QUygXJimoCQ9rMH2NQGAYk/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Remove Nth Node From End of List - LeetCode&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;leetcode.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제 풀이&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자체적인 자료구조를 제공하고 푸는 문제다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바는 Call By Value지만, 그 주소값(정확히는 주소를 가리키는 값)을 가지므로 마치 Call By Reference처럼 동작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 문장에 가끔 Deep Copy, Shallow Copy의 개념을 흔들 때가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;생각의 흐름 - 일단 전체 길이부터 구하자.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체 길이를 제공하지 않는다. 별도 함수를 만들어 Count를 먼저 알아보기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;생각의 흐름 - 마지막에서 N번째라면 Step이 어떻게 계산될 수 있을지 생각하자.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;몇번이나 Next로 넘어가야 하는지를 알아야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체 Count했으니, 거기서 N을 빼면 몇번째인지 알 수 있고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Next값을 바꿔주면 될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 Head를 가지고 Next를 계산하면, 당연히 안된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 Tmp변수에 Head를 할당시키면 문제 없을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내부 값을 변경시키는 거면, 당연히 문제가 된다. Tmp의 주소값이 결국 Head의 주소값이기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇지만, Tmp도 결국 변수기 때문에, Tmp에 Head.next를 대입시킨다는 개념이면 문제가 되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ListNode가 5개라고 가정하면,&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1656&quot; data-origin-height=&quot;614&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tzrh4/btrGfUzlr5u/TwRaM5n51pp00SQMjtxYX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tzrh4/btrGfUzlr5u/TwRaM5n51pp00SQMjtxYX1/img.png&quot; data-alt=&quot;ListNode 1&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tzrh4/btrGfUzlr5u/TwRaM5n51pp00SQMjtxYX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ftzrh4%2FbtrGfUzlr5u%2FTwRaM5n51pp00SQMjtxYX1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1656&quot; height=&quot;614&quot; data-origin-width=&quot;1656&quot; data-origin-height=&quot;614&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ListNode 1&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 주소값(100~104)들을 가지는 Node가 5개 있다고 가정하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Head는 100이라는 주소값에 위치한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tmp = Head라고 했을 때, Tmp도 Head와 동일한 주소값을 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇지만, Tmp = Tmp.next로 변화시키는 것은 Head에 영향을 주지 않는다. (tmp가 100에서 101을 보게 되는 것 뿐이며, Head는 여전히 100을 바라본다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론, Tmp.value 를 변경시키면 Head.value도 영향을 가지게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 두가지를 적절히 혼합시켜야 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1656&quot; data-origin-height=&quot;772&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eclBLT/btrGgsJNJNr/BsV0pkBzi9wM05CqHm8ynk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eclBLT/btrGgsJNJNr/BsV0pkBzi9wM05CqHm8ynk/img.png&quot; data-alt=&quot;ListNode 2&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eclBLT/btrGgsJNJNr/BsV0pkBzi9wM05CqHm8ynk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeclBLT%2FbtrGgsJNJNr%2FBsV0pkBzi9wM05CqHm8ynk%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1656&quot; height=&quot;772&quot; data-origin-width=&quot;1656&quot; data-origin-height=&quot;772&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ListNode 2&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1656&quot; data-origin-height=&quot;772&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXXkOR/btrGhVdaO6K/xpA5H3MmbZyWjvWWnidTZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXXkOR/btrGhVdaO6K/xpA5H3MmbZyWjvWWnidTZk/img.png&quot; data-alt=&quot;ListNode 3&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXXkOR/btrGhVdaO6K/xpA5H3MmbZyWjvWWnidTZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXXkOR%2FbtrGhVdaO6K%2FxpA5H3MmbZyWjvWWnidTZk%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1656&quot; height=&quot;772&quot; data-origin-width=&quot;1656&quot; data-origin-height=&quot;772&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ListNode 3&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Prev라는 변수를 만들어, Head와 동일 시 시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tmp를 Next시키면서, Prev 변수에는 Next이전 값을 계속 가지게 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 Step이 마무리 되었을 때 (위의 경우 tmp가 3번의 Step을 넘어간 후 103번에 위치한 경우),&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Prev.next = Tmp.next 로 동일하게 만들면, 102번의 next는 104번으로 변경이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 Head에서 next로 가다보면, 100 -&amp;gt; 101 -&amp;gt; 102 -&amp;gt; 104 로 변경되는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;생각의 흐름 - Step이 0이 나온다면?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;움직이지 않는다가 아니라, 첫 시작이 바뀐다는 것을 캐치해야 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Head를 Head.next로 대치해야 했다.&lt;/p&gt;
&lt;pre id=&quot;code_1656737668639&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public ListNode removeNthFromEnd(ListNode head, int n) {
    int count = chkCount(head);
    ListNode tmp = head;
    ListNode prev = head;
    int step = count - n;
    if(step == 0) {
        head = head.next;
    } else {
        while(step &amp;gt; 0) {
            prev = tmp;
            tmp = tmp.next;
            step --;
        }
        prev.next = tmp.next;
    }
    return head;
}

public int chkCount(ListNode head) {
    ListNode tmp = head;
    int count = 1;
    while(tmp.next != null) {
        tmp = tmp.next;
        count ++;
    }
    return count;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algorithm</category>
      <category>Algorithm</category>
      <category>leetcode</category>
      <category>Remove Nth Node From End of List</category>
      <category>알고리즘</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/35</guid>
      <comments>https://koocci-dev.tistory.com/35#entry35comment</comments>
      <pubDate>Sat, 2 Jul 2022 13:55:59 +0900</pubDate>
    </item>
    <item>
      <title>[java] Container With Most Water</title>
      <link>https://koocci-dev.tistory.com/34</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;[참고문제] :&lt;span&gt; &lt;a href=&quot;https://leetcode.com/problems/container-with-most-water/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://leetcode.com/problems/container-with-most-water/&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1656733991877&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Container With Most Water - LeetCode&quot; data-og-description=&quot;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&quot; data-og-host=&quot;leetcode.com&quot; data-og-source-url=&quot;https://leetcode.com/problems/container-with-most-water/&quot; data-og-url=&quot;https://leetcode.com/problems/container-with-most-water/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bohbn4/hyOYqggcRu/EtodHWcre7oElG8mo2iD70/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260,https://scrap.kakaocdn.net/dn/c3A7Ll/hyOYncL4fh/Ghh5aTJMGcPzfHPonnkZ70/img.png?width=2104&amp;amp;height=2021&amp;amp;face=0_0_2104_2021,https://scrap.kakaocdn.net/dn/cnjvt5/hyOYpPbZol/QJLOKI4BKC9eqADkivZZR0/img.png?width=2104&amp;amp;height=2021&amp;amp;face=0_0_2104_2021&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/container-with-most-water/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://leetcode.com/problems/container-with-most-water/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bohbn4/hyOYqggcRu/EtodHWcre7oElG8mo2iD70/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260,https://scrap.kakaocdn.net/dn/c3A7Ll/hyOYncL4fh/Ghh5aTJMGcPzfHPonnkZ70/img.png?width=2104&amp;amp;height=2021&amp;amp;face=0_0_2104_2021,https://scrap.kakaocdn.net/dn/cnjvt5/hyOYpPbZol/QJLOKI4BKC9eqADkivZZR0/img.png?width=2104&amp;amp;height=2021&amp;amp;face=0_0_2104_2021');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Container With Most Water - LeetCode&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;leetcode.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제 풀이&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단히 2중 포문으로 풀 수 있겠지만, Time 제한에 걸릴게 뻔해보였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;생각의 흐름 - 일단 2중 포문으로는 잘 구현되는지 보자.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이중포문을 구현했지만 역시나 시간 이슈가 생겼다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;생각의 흐름 - 양쪽에서 줄여나가자.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;늘 그렇듯, 이런 문제는 양쪽에서 줄여나갈 필요가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;left, right 인덱스를 설정하고 총량을 계산해, MAX를 비교하고자 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;생각의 흐름 - 언제 left와 right를 늘리거나 줄여주는가?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;while문은 left와 right가 같지 않을때로 설정하면 될 것으로 보였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나, 언제 left를 늘리고, 언제 right를 줄이는지 제한이 있어야 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시 문제를 통해 볼 때, 중간에 매우 긴 벽이 있을수도 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;left와 right를 비교해야만 할 것으로 보였고, width를 같이 고민했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;width가 줄어드는 것보다 더 이득일 경우에만 늘려야 한다고 판단했으나, 그러면 이중 포문과 다를 것이 없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 약간 Greedy하게 보기로 했다. 당장 left와 right중 작은게 결국 문제가 될 것이고, 작은걸 변화시키자고 생각했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;left와 right를 비교했을 때 더 작은 것을 변화시켰다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1656734300969&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public int maxArea(int[] height) {
    int left = 0;
    int right = height.length - 1;
    int maxMount = 0;

    while(left != right) {
        int width = right - left;
        maxMount = Math.max(width*(Math.min(height[left], height[right])), maxMount);
        if(height[left] &amp;gt; height[right]) {
            right --;
        } else {
            left ++;
        }
    }
    return maxMount;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm</category>
      <category>Algorithm</category>
      <category>Container With Most Water</category>
      <category>leetcode</category>
      <category>알고리즘</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/34</guid>
      <comments>https://koocci-dev.tistory.com/34#entry34comment</comments>
      <pubDate>Sat, 2 Jul 2022 12:59:32 +0900</pubDate>
    </item>
    <item>
      <title>자바스크립트 기초부터 모던 자바스크립트까지 - 기초편</title>
      <link>https://koocci-dev.tistory.com/33</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : 자바스크립트의 가장 기초적인 내용부터 알아본다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;변수&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 값을 저장하기 위해 확보한 메모리 공간 자체 또는 그 메모리 공간을 식별하기 위해 붙인 이름&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;변수 선언&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수를 생성하는 것&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;값을 저장하기 위한 메모리 공간을 확보하고, 변수 이름과 확보된 메모리 공간의 주소를 연결하여 값을 저장할 수 있게 준비하는 것&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;변수를 사용하려면 반드시 선언이 필요하며, &lt;span style=&quot;color: #ee2323;&quot;&gt;var, let, const&lt;/span&gt; 키워드를 사용한다.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;선언 단계
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;변수 이름을 등록해서 자바스크립트 엔진에 변수의 존재를 알린다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;초기화 단계
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;값을 저장하기 위한 메모리 공간을 확보하고 암묵적으로 undefined를 할당해 초기화한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;변수 선언의 실행 시점과 변수 호이스팅&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1656691504895&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;console.log(score) // undefined
var score; // 변수 선언&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;변수 선언이 소스코드가 한 줄씩 순차적으로 실행되는 시점, 즉 런타임이 아니라 그 이전 단계에서 먼저 실행된다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;자바스크립트 엔진은 소스코드를 한 줄씩 실행하기 전에 먼저 소스코드의 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;평가, 실행&lt;/b&gt;&lt;/span&gt; 두 가지로 진행이 되며&lt;b&gt;, 평가 과정에서 변수 선언을 포함한 모든 선언문(변수, 함수 등)을 소스코드의 어디에 있든 상관없이 먼저 실행&lt;/b&gt;한다.&lt;/li&gt;
&lt;li&gt;변수 선언(선언 + 초기화)이 소스코드가 순차적으로 실행되는 런타임 이전 단계에서 먼저 실행된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;변수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 자바스크립트 고유 특징&lt;/b&gt;을 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;변수 호이스팅&lt;/b&gt;&lt;/span&gt;이라고 한다.&lt;/li&gt;
&lt;li&gt;변수 뿐만이 아니라, &lt;b&gt;var, let, const, function, function*, class&lt;/b&gt; 키워드를 사용해 선언하는 모든 식별자(변수, 함수, 클래스 등)은 호이스팅된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;값의 할당 &amp;amp; 재할당&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1656691709731&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var score; // 선언
score = 80; // 할당&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;변수 선언&lt;/b&gt;&lt;/span&gt;은 소스코드가 순차적으로 실행되는 시점인 &lt;b&gt;런타임 이전에 먼저 실행&lt;/b&gt;되지만, &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;할당&lt;/span&gt;&lt;/b&gt;은 소스코드가 순차적으로 실행되는 시점인 &lt;b&gt;런타임에 실행&lt;/b&gt;된다.&lt;/p&gt;
&lt;pre id=&quot;code_1656725515789&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var score = 80; // 변수 선언과 값의 할당
score = 90; // 재할당&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;var 키워드로 선언한 변수는 선언과 동시에 undefined로 초기화되기 때문에 엄밀히 말하면 변수에 처음 값을 할당하는 것도 재할당이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;재할당&lt;/b&gt;&lt;/span&gt;은 &lt;b&gt;변수에 저장된 값을 다른 값으로 변경&lt;/b&gt;한다. 그래서 변수라고 하며, &lt;b&gt;만약 값을 재할당할 수 없어서 변수에 저장된 값을 변경할 수 없다면 변수가 아니라&lt;span style=&quot;color: #006dd7;&quot;&gt; 상수(constant)&lt;/span&gt;라 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 상수는 단 한번만 할당할 수 있는 변수다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;표현식과 문&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;값&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;식(표현식: expression)이 평가(evaluate)되어 생성된 결과&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656725765917&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 10 + 20은 평가되어 숫자 값 30을 생성한다.
10 + 20; // 30&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;리터럴&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;사람이 이해할 수 있는 문자 또는 약속된 기호를 사용해 값을 생성하는 표기법(notation)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;자바스크립트 엔진은 코드가 실행되는 시점인 런타임에 리터럴을 평가해 값을 생성한다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 266px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px; text-align: center;&quot;&gt;&lt;b&gt;리터럴&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px; text-align: center;&quot;&gt;&lt;b&gt;예시&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px; text-align: center;&quot;&gt;&lt;b&gt;비고&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;정수 리터럴&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;100&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;부동소수점 리터럴&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;10.5&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;2진수 리터럴&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;0b0100001&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;0b로 시작&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;8진수 리터럴&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;0o101&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;ES6에서 도입, 0o로 시작&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;16진수 리터럴&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;0x41&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;ES6에서 도입, 0x로 시작&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;문자열 리터럴&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;'hello'&lt;br /&gt;&quot;hello&quot;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;불리언 리터럴&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;true&lt;br /&gt;false&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;null 리터럴&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;null&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;undefined 리터럴&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;undefined&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;객체 리터럴&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;{ name : 'Lee', address: 'Seoul' }&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;배열 리터럴&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;[ 1, 2, 3]&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;함수 리터럴&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;function() {}&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;정규 표현식 리터럴&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;/[A-Z]+/g&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;표현식&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1656726236253&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var score = 100;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1656726240976&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var score = 50 + 50;
score; // 100&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;값으로 평가될 수 있는 문(statement)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;표현식이 평가되면 새로운 값을 생성하거나 기존값을 참조한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;리터럴 역시 값으로 평가되므로, 표현식 중 하나&lt;/b&gt;다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;문&lt;/b&gt;&lt;/h4&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;프로그램을 구성하는 기본 단위이자 최소 실행 단위 &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;문의 집합으로 이뤄진 것이 프로그램이며&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;문을 작성하고 순서에 맞게 나열하는 것이 프로그래밍이다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;문은 여러 토큰으로 이루어진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;토큰&lt;/span&gt;: &lt;/span&gt;&lt;span&gt;문법적인 의미를 가지며&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;/b&gt;&lt;span&gt;&lt;b&gt;문법적으로 나눌 수 없는 코드의 기본 요소&lt;/b&gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;키워드&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;식별자&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;연산자&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;리터럴&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;세미콜론이나 마침표 등 특수 기호는 문법적인 의미를 가지므로 모두 토큰이다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;문은 명령문이라고도 한다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;즉&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;컴퓨터에 내리는 명령이다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;&lt;/span&gt;&lt;span&gt;선언문&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;할당문&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;조건문&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;반복문 등으로 구분이 된다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;데이터 타입&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;데이터 타입 종류&lt;/b&gt;&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 24.4961%; text-align: center;&quot;&gt;&lt;b&gt;구분&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 26.7053%; text-align: center;&quot;&gt;&lt;b&gt;데이터 타입&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 48.7985%; text-align: center;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 24.4961%;&quot; rowspan=&quot;6&quot;&gt;원시타입(primitive type)&lt;/td&gt;
&lt;td style=&quot;width: 26.7053%;&quot;&gt;숫자(number) 타입&lt;/td&gt;
&lt;td style=&quot;width: 48.7985%;&quot;&gt;숫자, 정수와 실수 구분없이 하나의 숫자 타입만 존재&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 26.7053%;&quot;&gt;문자열(string) 타입&lt;/td&gt;
&lt;td style=&quot;width: 48.7985%;&quot;&gt;문자열&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 26.7053%;&quot;&gt;불리언(boolean) 타입&lt;/td&gt;
&lt;td style=&quot;width: 48.7985%;&quot;&gt;논리적 참(true)과 거짓(false)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 26.7053%;&quot;&gt;undefined 타입&lt;/td&gt;
&lt;td style=&quot;width: 48.7985%;&quot;&gt;var 키워드로 선언된 변수에 암묵적으로 할당되는 값&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 26.7053%;&quot;&gt;null 타입&lt;/td&gt;
&lt;td style=&quot;width: 48.7985%;&quot;&gt;값이 없다는 것을 의도적으로 명시할 때 사용하는 값&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 26.7053%;&quot;&gt;심벌 타입&lt;/td&gt;
&lt;td style=&quot;width: 48.7985%;&quot;&gt;ES6에서 추가된 7번째 타입&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 51.2014%;&quot; colspan=&quot;2&quot;&gt;객체 타입&lt;/td&gt;
&lt;td style=&quot;width: 48.7985%;&quot;&gt;객체, 함수, 배열 등&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자는 명확한 의도를 가지고 타입을 구별해서 값을 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트 엔진은 타입을 구별해서 값을 취급한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;숫자 타입&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트는 정수&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;실수를 구분하지 않고 하나의 숫자 타입을 갖는다&lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ECMAScript &lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;사양에 따르면&lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;, 64&lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;비트 부동소수점 형식 을 따른다&lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;모든 수를 실수로 처리하며&lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;정수만은 따로 취급하지 않는다&lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656726708225&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;console.log(1 === 1.0) // true&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가적으로 세 가지 특별한 값도 표현할 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Infinity : 양의 무한대&lt;/li&gt;
&lt;li&gt;-Infinity : 음의 무한대&lt;/li&gt;
&lt;li&gt;NaN: 산술 연산 불가(Not a Number)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단, 자바스크립트는 대소문자를 구별하므로 &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;NAN, Nan, nan은 하나의 식별자로 해석한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;문자열 타입&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;텍스트 데이터를 나타낼 때 사용하고&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;, 0&lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;개 이상의 &lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;16&lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;비트 유니코드 문자&lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;(UTF-16)&lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;의 집합으로 전 세계 대부분의 문자를 표현할 수 있다&lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;자바스크립트는 문자열은 원시 타입이며&lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;변경 불가능한 값&lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;(Immutable) &lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;이다&lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;. (C&lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;는 배열이며&lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;자바는 객체로 표현한다&lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;.)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;템플릿 리터럴&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;백틱&lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;(`))&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;&lt;b&gt;은 런타임에 문자열로 변경&lt;/b&gt;된다&lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;템플릿 리터럴&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ES6 &lt;/span&gt;&lt;span&gt;부터 새로운 문자열 표기법이 도입되었다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;템플릿 리터럴은 멀티라인 문자열, 표현식 삽입, 태그드 템플릿등 편리한 문자열 처리 기능을 제공한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;런타임에 일반 문자열로 변환된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;단 줄바꿈 등의 공백을 표현하려면 백슬래시를 활용해야 한다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656727148085&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 멀티라인 문자열
var str = `Hello
world.`;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;pre id=&quot;code_1656727165778&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//표현식 삽입
 var first = 'Hello';
 var last = 'world';
 console.log(`first is ${first}, last is ${world}`);
 console.log(`1 + 2 = ${1+2}`);&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;불리언 타입&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논리적 참과 거짓을 나타내는 true, false뿐이다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;undefined 타입&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;undefined타입의 값은 undefined가 유일하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서, &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;변수를 선언한 이후 값을 할당하지 않은 변수를 참조하면 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;undefined&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;가 반환되는 점을 배웠다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;즉, 개발자는 undefined로 초기화하는 것을 지양하고, null로 표현하는 것이 좋다. (명시적으로 값이 없다는 것을 알려줄 때)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;null 타입&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;null타입의 값은 null이 유일하다. &lt;/span&gt;&lt;span&gt;(Null, NULL&lt;/span&gt;&lt;span&gt;은 해당하지 않는다&lt;/span&gt;&lt;span&gt;.) &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;의도적으로 변수에 값이 없다는 것을 명시할 때 사용한다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;이는 이전에 할당되어 있던 값에 대한 참조를 명시적으로 제거하는 것이고&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;자바스크립트 엔진은 누구도 참조하지 않은 메모리 공간에 대해 가비지 콜렉션을 수행한다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;함수가 유효한 값을 반환할 수 없는 경우 명시적으로 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;을 반환하기도 한다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;심벌 타입&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;심벌(Symbol)&lt;/b&gt;&lt;/span&gt;은 ES6에서 추가된 7번째 타입으로, &lt;b&gt;변경 불가능한 원시 타입의 값&lt;/b&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;심벌 값은 &lt;b&gt;다른 값과 중복되지 않는 유일무이한 값&lt;/b&gt;이다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;주로&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;이름이 충돌할 위험이 없는 객체의 유일한 프로퍼티 키를 만들 때 사용한다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;다른 원시 값은 리터럴을 통해 생성하지만&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;심벌은 &lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;Symbol &lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;함수&lt;/b&gt;&lt;/span&gt;를 통해 생성한다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;이 때&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;생성된 심벌값은 외부에 노출되지 않고&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;다른 값과 절대 중복되지 않는 유일한 값이다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656727675172&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//심벌 값 생성
var key = Symbol('key');
console.log(typeof key); // symbol

//객체 생성
var obj = {};

//이름이 충돌할 위험이 없는 유일무이한 값이 심벌을 프로퍼티 키로 사용한다.
obj[key] = 'value';
console.log(obj[key]); // value&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;객체 타입&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트는 가장 크게 타입을 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;원시타입&lt;/b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;과&lt;/span&gt; &lt;b&gt;객체타입&lt;/b&gt;&lt;/span&gt;으로 구분한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근본적으로 다르다고 할 수 있고, &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;b&gt;자바스크립트를 이루고 있는 거의 모든 것이 객체&lt;/b&gt;이다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;객체 타입은 방대하므로, 이후에 별도로 정리하도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;데이터 타입의 필요성&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;값을 저장할 때 확보해야 하는 메모리 공간의 크기를 결정하기 위해&lt;/li&gt;
&lt;li&gt;값을 참조할 때 한번에 읽어야 하는 메모리 공간의 크기를 결정하기 위해&lt;/li&gt;
&lt;li&gt;메모리에서 읽어들인 2진수을 어떻게 해석할지 결정하기 위해 &lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;동적 타이핑&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;정적 타입 언어는 변수 타입을 변경할 수 없고&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;변수에 선언한 타입에 맞는 값만 할당 가능하다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;정적 타입 언어는 컴파일 시점에서 타입 체크를 수행한다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;타입 체크를 통과하지 못하면 에러를 발생시키고 실행을 막는다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;자바스크립트는 &lt;b&gt;변수를 선언할 때 타입을 선언하지 않는다&lt;/b&gt;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;. &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;다만 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;var, let, const &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;키워드를 통해 변수를 선언할 뿐이다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;자바스크립트에서는 &lt;b&gt;값을 할당하는 시점에 변수의 타입이 동적으로 결정되고 변수의 타입을 언제든지 자유롭게 변경할 수 있다&lt;/b&gt;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;자바스크립트의 변수는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;선언이 아닌 &lt;/b&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;할당에&lt;/span&gt; 의해 타입이 결정&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;타입 추론&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;) &lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;된다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;그리고 재할당에 의해 변수의 타입은 언제든지 동적으로 변할 수 있다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;. &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;즉 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;동적 타이핑&lt;/b&gt;&lt;/span&gt;이 된다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;동적 타입 언어는 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;유연성은 높지만 신뢰성은 떨어진다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;연산자&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;연산자에 대해서는 기초적인 내용이라, 별도로 정리하진 않는다.&lt;/span&gt;&lt;b&gt;&lt;/b&gt;&lt;b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;단, 새로운 개념이 등장하는 부분은 정리하고 넘어가자.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;b&gt;단축 평가&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;단축 평가 표현식&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;평가 결과&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;true || anything&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;false || anything&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;anything&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;true &amp;amp;&amp;amp; anything&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;anything&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;false &amp;amp;&amp;amp; anything&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;false&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;논리 연산자를 사용한 단축 평가 시, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;무엇을 반환하는지&lt;/b&gt;&lt;/span&gt;를 알아볼 필요가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논리곱 연산자는 두 개의 피연사자가 모두 true 로 평가될 때, true를 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;평가 결과가 불리언 값이 아닐 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656729646156&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;'Cat' &amp;amp;&amp;amp; 'Dog' // -&amp;gt; &quot;Dog&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좌항부터 우항으로 평가가 진행되며, &lt;b&gt;우항까지 평가가 되었을 때 평가 결과가 결정되므로, &lt;span style=&quot;color: #ee2323;&quot;&gt;두번째 피연산자를 반환&lt;/span&gt;한다(Dog)&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656729773749&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;'Cat' || 'Dog' // -&amp;gt; &quot;Cat&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;논리합 연산자는 &lt;b&gt;하나만 true여도 true를 반환하므로, &lt;span style=&quot;color: #ee2323;&quot;&gt;첫번째 피연산자를 반환&lt;/span&gt;한다. (Cat)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;여기서, 논리곱(&amp;amp;&amp;amp;)연산자와 논리합(||)연산자는 &lt;b&gt;논리 연산의 결과를 결정하는 피연산자를 타입 변환하지 않고 그대로 반환&lt;/b&gt;한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;단축 평가는 다음 같은 상황에서 유용하게 사용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;객체를 가리키기를 기대하는 변수가 null 또는 undefined가 아닌지 확인하고 프로퍼티를 참조할 때&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656730140998&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var elem = null;
var value = elem.value; // TypeError: Cannot read property 'value' of null&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1656730195507&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var elem = null;
// elem이 null이나 undefined와 같은 Falsy 값이면 elem으로 평가되고
// elem이 Truthy값이면 elem.value로 평가된다.
var value = elem &amp;amp;&amp;amp; elem.value; // null&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;함수 매개변수에 기본값을 설정할 때&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;함수를 호출할 때 인수를 전달하지 않으면 매개변수에는 undefined가 할당된다. 이때 단축 평가를 사용해 매개변수의 기본값을 설정하면 undefined로 인해 발생할 수 있는 에러를 방지할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656730390790&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 단축 평가를 사용한 매개변수의 기본값 설정
function getStringLength(str) {
  str = str || '';
  return str.length;
}

// ES6의 매개변수 기본값 설정
function getStringLength(str = '') {
  return str.length;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;옵셔널 체이닝 연산자&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;ES11에서 도입된 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;옵셔널 체이닝 연산자&lt;/b&gt;&lt;/span&gt; &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;?.&lt;/b&gt;&lt;/span&gt;는 &lt;b&gt;좌항의 피연산자가 null 또는 undefined인 경우 undefined를 반환하고, 그렇지 않으면 우항의 프로퍼티 참조를 이어간다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656730598824&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var elem = null;

var value = elem?.value;
console.log(value); // undefined&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 논리곱 연산자로 판단한것과 유사하지만, 논리 연산자 &amp;amp;&amp;amp;은 &lt;b&gt;좌항 피연산자가 false로 평가되는 값 (false, undefined, null, &lt;span style=&quot;color: #006dd7;&quot;&gt;0&lt;/span&gt;, -0, NaN,&lt;span style=&quot;color: #006dd7;&quot;&gt; ''&lt;/span&gt;)이면 좌항 피연산자를 그대로 반환&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나, 옵셔널 체이닝 연산자는 null 또는 undefined가 아니면 우항의 프로퍼티 참조를 이어간다.&lt;/p&gt;
&lt;pre id=&quot;code_1656730757034&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var str = '';

var length = str?.length;
console.log(length); // 0&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;null 병합 연산자&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;ES11에서 도입된 null 병합 연산자 ??는 &lt;b&gt;좌항의 피연산자가 null 또는 undefined인 경우 우항의 피연산자를 반환하고, 그렇지 않으면 좌항의 피연산자를 반환&lt;/b&gt;한다.&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656730844970&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var foo = null ?? 'default string';
console.log(foo); // default string&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;이 역시, 변수 기본값 설정에 유용하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;논리합 연산자도 위 논리곱 연산자와 같은 이유가 있으며, null 병합 연산자는 옵셔널 체이닝과 같은 이유로 null / undefined만 판단한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656730951466&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var foo = '' || 'default string';
console.log(foo); // default string

var boo = '' ?? 'default string';
console.log(boo); // ''&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;제어문&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;제어문 역시 기초적인 내용으로, 별도 정리하지 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;별도 사이트를 참고하도록 하자&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ko.javascript.info/intro&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://ko.javascript.info/intro&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1656729104818&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;자바스크립트란?&quot; data-og-description=&quot;&quot; data-og-host=&quot;ko.javascript.info&quot; data-og-source-url=&quot;https://ko.javascript.info/intro&quot; data-og-url=&quot;https://ko.javascript.info/intro&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cupMRN/hyOYmkAJpJ/21w3fgbDeUEjb2VGQgk77k/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bGxooY/hyOWYMqVFY/YxylqFaTkpaYeB1TDknZDK/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512&quot;&gt;&lt;a href=&quot;https://ko.javascript.info/intro&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ko.javascript.info/intro&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cupMRN/hyOYmkAJpJ/21w3fgbDeUEjb2VGQgk77k/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bGxooY/hyOWYMqVFY/YxylqFaTkpaYeB1TDknZDK/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트란?&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ko.javascript.info&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후에는 객체부터 알아볼 것이며, 스코프, 실행컨텍스트 등을 알아볼 예정이다.&lt;/p&gt;</description>
      <category>Programming/javascript</category>
      <category>JavaScript</category>
      <category>기초</category>
      <category>자바스크립트</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/33</guid>
      <comments>https://koocci-dev.tistory.com/33#entry33comment</comments>
      <pubDate>Sat, 2 Jul 2022 12:03:46 +0900</pubDate>
    </item>
    <item>
      <title>자바 기초부터 모던 자바까지 - 기초편</title>
      <link>https://koocci-dev.tistory.com/32</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : 자바의 가장 기초적인 내용부터 알아본다.&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;java만큼 아직 대중적인 프로그래밍 언어는 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;점차 포스팅으로 모던 자바에 대해 정리하겠지만, 알았으면서도 오랜만에 보면 새로울 수 있는 포인트들이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수가 무엇인지, 자료형이 무엇인지 이런 내용은 아니지만, 조금은 익숙해져야 할 내용으로 작성하려 한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;상수와 리터럴이 뭐지?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;상수(constant)&lt;/b&gt;&lt;/span&gt;는 알다 시피, &lt;b&gt;변하지 않는 수&lt;/b&gt;를 말하고 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;final&lt;/b&gt;&lt;/span&gt;이라는 키워드를 쓴다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;final을 쓰면, 변수는 상수가 되고, 상수는 변할 수 없다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;리터럴(literal)&lt;/b&gt;&lt;/span&gt;은 &lt;b&gt;프로그램에서 사용하는 모든 숫자, 값, 논리 값&lt;/b&gt; (ex&amp;gt; 10, 3.14, 'A', true)을 의미 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 중에서 리터럴은 상수풀(constant pool) 영역에 저장되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수는 해당 리터럴이 상수풀에 있는지 확인하고 사용하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;switch문이 바뀌고 있다?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에 사용하던 switch 문은 다음과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1655917055282&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;switch (today) {
    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
        System.out.println(&quot;today is Weekday&quot;);
        break;
    case 6:
    case 7:
        System.out.println(&quot;today is Weekend&quot;);
        break;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 java 버전이 업그레이드 되면서 다음과 같은 기능이 생겼다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;쉼표로 구분이 가능하다.&lt;/li&gt;
&lt;li&gt;식으로 표현하여 반환 값을 받을 수 있고, 리턴이 없으면 오류
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;switch라는 함수명을 가지고, 파라미터로 비교대상을 받는 형태로 가능하다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;break를 안쓰고 괄호로 묶을 수 있다. 또한, -&amp;gt; 수식을 쓴다.&lt;/li&gt;
&lt;li&gt;switch case에서 yield 문으로 반환이 가능하다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1655917327478&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int day = switch(month) {
	case 1,3,5,7,8,10,12 -&amp;gt; 31;
    case 2 -&amp;gt; 28;
    case 4,6,9,11 -&amp;gt; 30;
    default -&amp;gt; {
    	System.out.println(&quot;x&quot;);
        yield -1; // 수행과 반환이 같이 쓰여서, yield를 써서 반환함을 알려주어야 한다.
    }
}; // day의 끝이므로 세미콜론 필요&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Public 클래스는 하나다.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바 파일 하나에 여러 개의 클래스가 존재할 수는 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단, public 클래스는 하나이고, public 클래스와 자바 파일 이름은 동일해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;접근 제어 지시자(Access Modifier)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스 외부에서 클래스의 멤버 변수, 메서드, 생성자를 사용할 수 있는지 여부를 지정하는 키워드다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;private&lt;/b&gt;&lt;/span&gt; : 같은 클래스 내부만 접근 가능 (외부 클래스, 상속 관계 클래스라도 접근 불가)&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;default&lt;/b&gt; &lt;/span&gt;: 같은 패키지 내부에서만 접근 가능 (상속 관계라도 패키지가 다르면 접근 불가)&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;protected&lt;/b&gt;&lt;/span&gt; : 같은 패키지나 상속관계의 클래스에서 접근 가능하고 그 외 외부에서는 접근할 수 없음.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;public&lt;/b&gt;&lt;/span&gt; : 클래스 외부 어디서나 접근 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Call by Value VS Call by Reference&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;java는 Call By Value밖에 없다. Object의 경우 주소값을 넘기는 Call By Value이기 때문에 헤깔리지만 염두해두자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;static 변수, static 메서드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 인스턴스가 공통으로 사용하는 변수를 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;static 변수&lt;/b&gt;&lt;/span&gt;라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;인스턴스가 생성될 때가 아닌, 처음 프로그램이 메모리에 로딩될 때 메모리를 할당하는 변수&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인스턴스 생성과 상관 없이 사용가능하여, 클래스 이름으로 직접 참조한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;static 메서드&lt;/b&gt;&lt;/span&gt;는 클래스 메서드라고도 하며, 멤버변수를 사용할 수 없는 메서드다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 역시, 클래스 이름으로 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;인스턴스 생성 전에 호출 될 수 있으므로, static 메서드 안에는 인스턴스 변수를 사용할 수 없다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;싱글톤 패턴&lt;/span&gt;에서 주로 사용하는 방법이다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656084479716&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;static class Singleton {
	private static Singleton instance;
    
    private Singleton() {}
    public static Singleton getInstance() {
    	if(instance == null) {
        	instance = new Singleton();
        } 
        return instance;
    }

}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1656339315152&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class ExampleClass {

    //private construct
    private ExampleClass() {}

    private static class InnerInstanceClazz() {
        private static final ExampleClass instance = new ExampleClass();
    }

    public static ExampleClass getInstance() {
        return InnerInstanceClazz.instance;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;형변환은 왜 이렇게 쓰고 있을까 ?&lt;/h3&gt;
&lt;pre id=&quot;code_1656085293145&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Customer c = new VIPCustomer();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 형태를 자주 볼 것이며, 업캐스팅하여 형 변환한 케이스다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 예시처럼, 상속된 구조에서 사용할 수 있는 부분으로 VIPCustomer 클래스의 모든 멤버 변수에 대한 메모리는 생성되지만, 변수 타입이 Customer이므로 &lt;b&gt;실제로 접근 가능한 변수나 메서드는 Customer의 변수와 메서드가 된다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656085242101&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Customer {
    private String customerId;
    private String name;
    public String getCustomerId() {
        return customerId;
    }
}

class VIPCustomer extends Customer {
    private String vipId;
    public String getVipId() {
        return vipId;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;오버라이딩&lt;/b&gt;&lt;/span&gt;이 되면 &lt;b&gt;인스턴스 타입&lt;/b&gt;을 따라가게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;java는 항상 인스턴스의 메서드가 호출된다 (가상 메서드 원리)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바의 모든 메서드는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;가상 메서드 (virtual method)&lt;/b&gt;&lt;/span&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;인터페이스&lt;/b&gt;&lt;/span&gt;를 구현한 클래스는 &lt;b&gt;인터페이스 형으로 선언한 변수로 형 변환할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 역시 인터페이스에 선언된 메서드만 사용가능하다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;가상 메서드(virtual method) 간단하게 알아보면?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메서드의 이름은 주소값을 나타낸다. (메서드는 명령어의 set이고 프로그램이 로드되면 메서드 영역(코드영역)에 명령어 set이 위치한다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메서드가 호출되면 명령어 set이 있는 주소를 찾아 명령어가 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메서드 변수들은 stack에 위치하게 될 것이고,&amp;nbsp; 인스턴스 변수는 힙 메모리에 있을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메서드는 메서드 영역에 있으니 처음 한번만 호출된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;final 예약어를 정리해보자.&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-sourcepos=&quot;97:1-98:0&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-sourcepos=&quot;97:1-98:0&quot;&gt;final 변수 : 값이 변경될 수 없는 상수&lt;/li&gt;
&lt;li data-sourcepos=&quot;97:1-98:0&quot;&gt;final 메서드 : 하위 클래스에서 재정의 할 수 없는 메서드&lt;/li&gt;
&lt;li data-sourcepos=&quot;97:1-98:0&quot;&gt;final 클래스 : 상속할 수 없는 클래스&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;String의 선언은 달라질 수 있다.&lt;/h3&gt;
&lt;pre id=&quot;code_1656087180660&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String str1 = new String(&quot;AAA&quot;);
String str2 = &quot;AAA&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 힙메모리에 인스턴스를 생성한 경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 상수 풀(constant pool)에 있는 주소를 참조&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;힙 메모리는 매번 다른 주소지만, 상수 풀의 문자열은 모두 같은 주소를 가진다.&lt;/p&gt;
&lt;pre id=&quot;code_1656087266094&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String str1 = new String(&quot;abc&quot;);
String str2 = new String(&quot;abc&quot;);

System.out.println(str1 == str2); // false

String str3 = &quot;abc&quot;;
String str4 = &quot;abc&quot;;

System.out.println(str3 == str4); // true&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;String 도 하나의 Wrapper Class이고, Reference 타입이므로 주소값(참조값)을 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상수 풀에 있는 주소를 참조하여 생성했을 때 == 연산자가 정상인 것처럼 보일 떄도 있겠지만, equal 연산자를 쓰는게 옳다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;String은 Immutable(불변)한다?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한번 생성된 String은 변하지 않는다. 즉, String을 연결하면 기존 String에 연결되는게 아니라, &lt;b&gt;완전 새로운 문자열이 생성된다.&lt;/b&gt; (메모리 낭비가 생길 수 있다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;StringBuilder, StringBuffer&lt;/b&gt;&lt;/span&gt; 가 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특징은 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 내부적으로 가변적인 char[]를 가지고 있다. (새로운 인스턴스를 생성하지 않고, char[]를 변경한다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. StringBuffer는 멀티 쓰레드 프로그래밍에서 동기화(Synchronization)을 보장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 단일 쓰레드 프로그램에서는 StringBuilder 사용을 권장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. toString()메서드로 String을 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;제네릭(Generic) 프로그래밍&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. &lt;b&gt;클래스에서 사용하는 변수의 자료형이 여러개일 수 있고, 그 기능(메서드)은 동일한 경우 클래스의 자료형을 특정하지 않고 추후 해당 클래스를 사용할 수 있게 지정할 수 있도록 선언&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 실제 사용되는 자료형 변환은 컴파일러에 의해 검증된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. Collection 프레임워크에서 많이 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1656685148307&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class GenericPrinter&amp;lt;T&amp;gt; {
	private T material;
	
	public void setMaterial(T material) {
		this.material = material;
	}
	
	public T getMaterial() {
		return material;
	}
	
	public String toString(){
		return material.toString();
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;자료형 매개변수 T(type parameter)&lt;/b&gt; &lt;/span&gt;: 이 클래스를 사용하는 시점에 실제 사용할 자료형을 지정, static 변수는 사용할 수 없음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;T라는 자리에 Powder, Plastic 과 같은 다른 클래스가 들어갈 수 있다. 즉, Object로도 취환해서 class를 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, 그렇게 안하는 이유는 &lt;b&gt;형 변환을 결국 해야하기 때문.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656685214655&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class ThreeDPrinter{

	private Object material;
	
	public void setMaterial(Object material) {
		this.material = material;
	}
	
	public Object getMaterial() {
		return material;
	}
}

//

ThreeDPrinter printer = new ThreeDPrinter();

Powder powder = new Powder();
printer.setMaterial(powder);

Powder p = (Powder)printer.getMaterial();&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;제네릭 메서드는 또 뭐지?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;자료형 매개 변수&lt;/b&gt;&lt;/span&gt;를 &lt;b&gt;메서드의 매개변수&lt;/b&gt;나 &lt;b&gt;반환 값&lt;/b&gt;으로 가지는 메서드는 자료형 매개 변수가 하나 이상인 경우도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;꼭 제네릭 클래스가 아니어도 내부에 제네릭 메서드는 구현 가능하다.&lt;/p&gt;
&lt;pre id=&quot;code_1656685564370&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Point&amp;lt;T, V&amp;gt; {
	T x;
	V y;
	
	Point(T x, V y){
		this.x = x;
		this.y = y;
	}
	
	public  T getX() {
			return x;
	}

	public V getY() {
		return y;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포인트를 만드는 간단한 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;제네릭 클래스&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 활용하는 &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;제네릭 메서드&lt;/span&gt;&lt;/b&gt;도 만들어 보자.&lt;/p&gt;
&lt;pre id=&quot;code_1656685644379&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class GenericMethod {

	public static &amp;lt;T, V&amp;gt; double makeRectangle(Point&amp;lt;T, V&amp;gt; p1, Point&amp;lt;T, V&amp;gt; p2) {
		double left = ((Number)p1.getX()).doubleValue();
		double right =((Number)p2.getX()).doubleValue();
		double top = ((Number)p1.getY()).doubleValue();
		double bottom = ((Number)p2.getY()).doubleValue();
		
		double width = right - left;
		double height = bottom - top;
		
		return width * height;
	}
	
	public static void main(String[] args) {
		
		Point&amp;lt;Integer, Double&amp;gt; p1 = new Point&amp;lt;Integer, Double&amp;gt;(0, 0.0);
		Point&amp;lt;Integer, Double&amp;gt; p2 = new Point&amp;lt;&amp;gt;(10, 10.0);
		
		double rect = GenericMethod.&amp;lt;Integer, Double&amp;gt;makeRectangle(p1, p2);
		System.out.println(&quot;두 점으로 만들어진 사각형의 넓이는 &quot; + rect + &quot;입니다.&quot;);
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;makeRectangle이라는 함수로 그 형태를 확인해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;public&lt;/span&gt; static &lt;span style=&quot;color: #f89009;&quot;&gt;&amp;lt;T, V&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt; double&lt;/span&gt; &lt;span style=&quot;color: #009a87;&quot;&gt;makeRectangle&lt;/span&gt;(&lt;span style=&quot;color: #006dd7;&quot;&gt;Point&amp;lt;T, V&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: #8a3db6;&quot;&gt;p1&lt;/span&gt;, &lt;span style=&quot;color: #006dd7;&quot;&gt;Point&amp;lt;T, V&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: #8a3db6;&quot;&gt;p2&lt;/span&gt;)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: #f89009;&quot;&gt;&amp;lt;자료형 매개 변수&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: #f3c000;&quot;&gt;반환형&lt;/span&gt; &lt;span style=&quot;color: #009a87;&quot;&gt;메서드 이름&lt;/span&gt;(&lt;span style=&quot;color: #006dd7;&quot;&gt;자료형&lt;/span&gt; &lt;span style=&quot;color: #8a3db6;&quot;&gt;매개변수&lt;/span&gt;.....) { }&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메서드의 매개변수로 T,V라는 Type Parameter(자료형 매개변수)를 사용하였기 때문에, Generic Method로 볼수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 으로는 컬렉션, 람다, 스트림 등 jdk 1.8 이후에 격변한 내용들을 알아보려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, 그 내용을 조금 간단히 먼저 알아보고, 하나씩 조금 심화해서 볼 예정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/Java</category>
      <category>Java</category>
      <category>기초</category>
      <category>모던자바</category>
      <category>자바</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/32</guid>
      <comments>https://koocci-dev.tistory.com/32#entry32comment</comments>
      <pubDate>Fri, 1 Jul 2022 23:34:47 +0900</pubDate>
    </item>
    <item>
      <title>[java] Rotate Array</title>
      <link>https://koocci-dev.tistory.com/31</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;[참고문제] : &lt;a href=&quot;https://leetcode.com/problems/rotate-array/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://leetcode.com/problems/rotate-array/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1656081953088&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Rotate Array - LeetCode&quot; data-og-description=&quot;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&quot; data-og-host=&quot;leetcode.com&quot; data-og-source-url=&quot;https://leetcode.com/problems/rotate-array/&quot; data-og-url=&quot;https://leetcode.com/problems/rotate-array/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bEfUW8/hyOSVU4soa/AcJr1tqPKLoQ3cmg7ctn61/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/rotate-array/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://leetcode.com/problems/rotate-array/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bEfUW8/hyOSVU4soa/AcJr1tqPKLoQ3cmg7ctn61/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Rotate Array - LeetCode&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;leetcode.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제 풀이&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;생각의 흐름 - Circular Linked List 다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보자마자, Circular Linked List로 구현하면 될 것이란 건 알았다. 다만, 자료구조를 만드는게 목표가 아니니 list로 처리하기로 함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;생각의 흐름 - 어디부터 끊어지는 지 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;k는 받지만, 모듈러 연산은 해야겠다고 판단.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;생각의 흐름 - 끊어지는 부분 앞을 그냥 뒤에 추가하고, 거기부터 읽어내자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;List에 넣어두고, 앞부분을 그냥 반복해서 넣어주고, 읽을 때 끊어졌던 부분 부터 읽자고 판단.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1656082282377&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution {
    public void rotate(int[] nums, int k) {
        k %= nums.length;
        List&amp;lt;Integer&amp;gt; arr = Arrays.stream(nums).boxed().collect(Collectors.toList());
        List&amp;lt;Integer&amp;gt; arr2 = arr.subList(nums.length - k, nums.length);
        arr2.addAll(arr.subList(0, nums.length - k));
        for(int i = 0; i &amp;lt; nums.length; i++) {
            nums[i] = arr2.get(i);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm</category>
      <category>Algorithm</category>
      <category>leetcode</category>
      <category>Rotate Array</category>
      <category>알고리즘</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/31</guid>
      <comments>https://koocci-dev.tistory.com/31#entry31comment</comments>
      <pubDate>Fri, 24 Jun 2022 23:51:54 +0900</pubDate>
    </item>
    <item>
      <title>[java] Median of Two Sorted Arrays</title>
      <link>https://koocci-dev.tistory.com/30</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;[참고문제] : &lt;a href=&quot;https://leetcode.com/problems/median-of-two-sorted-arrays/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://leetcode.com/problems/median-of-two-sorted-arrays/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1655993538329&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Median of Two Sorted Arrays - LeetCode&quot; data-og-description=&quot;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&quot; data-og-host=&quot;leetcode.com&quot; data-og-source-url=&quot;https://leetcode.com/problems/median-of-two-sorted-arrays/&quot; data-og-url=&quot;https://leetcode.com/problems/median-of-two-sorted-arrays/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cxWGHo/hyORHDesnG/0Co15m8wc2CT2EG2K3GZI1/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/median-of-two-sorted-arrays/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://leetcode.com/problems/median-of-two-sorted-arrays/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cxWGHo/hyORHDesnG/0Co15m8wc2CT2EG2K3GZI1/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Median of Two Sorted Arrays - LeetCode&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;leetcode.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제 풀이&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;생각의 흐름 - 이미 정렬되어 있다.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 정렬이 되어 있으니, 각각의 배열에서 계속 더 작은 수를 확인한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;생각의 흐름 - 중앙값 까지만 확인해도 된다.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어짜피 필요한 건 중앙값이고, 중앙값까지만 확인하면 계산할 수 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;생각의 흐름 - 한쪽만 완료될 수 있다.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;작은 수가 한쪽에만 있을 수도 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이미 끝의 인덱스까지 확인했으면 다른 한 쪽만 확인하자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1655995213366&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public double findMedianSortedArrays(int[] nums1, int[] nums2) {
    int n = nums1.length;
    int m = nums2.length;
    int len = n + m;
    int nIndex = 0;
    int mIndex = 0;
    double result = 0.0;
    List&amp;lt;Integer&amp;gt; arr = new ArrayList&amp;lt;&amp;gt;();
    while(nIndex &amp;lt;= n &amp;amp;&amp;amp; mIndex &amp;lt;= m) {
        if(nIndex + mIndex == (len / 2) + 1) {
            if(len % 2 == 0) {
                result = (arr.get((len / 2) - 1) + (double)arr.get((len / 2))) / 2;
            } else {
                result = arr.get((len / 2));
            }
            break;
        } else {

            if(nIndex != n &amp;amp;&amp;amp; mIndex == m) {
                arr.add(nums1[nIndex]);
                nIndex ++;
            }

            else if(nIndex == n &amp;amp;&amp;amp; mIndex != m) {
                arr.add(nums2[mIndex]);
                mIndex ++;
            } else {
                if(nums1[nIndex] &amp;lt;= nums2[mIndex]) {
                    arr.add(nums1[nIndex]);
                    nIndex ++;
                } else {
                    arr.add(nums2[mIndex]);
                    mIndex ++;
                }
            }
        }
    }
    return result;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm</category>
      <category>Algorithm</category>
      <category>leetcode</category>
      <category>Median of Two Sorted Arrays</category>
      <category>알고리즘</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/30</guid>
      <comments>https://koocci-dev.tistory.com/30#entry30comment</comments>
      <pubDate>Thu, 23 Jun 2022 23:41:06 +0900</pubDate>
    </item>
    <item>
      <title>[java] Longest Substring Without Repeating Characters</title>
      <link>https://koocci-dev.tistory.com/29</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;[참고 문제] : &lt;a href=&quot;https://leetcode.com/problems/longest-substring-without-repeating-characters/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://leetcode.com/problems/longest-substring-without-repeating-characters/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1655912221266&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Longest Substring Without Repeating Characters - LeetCode&quot; data-og-description=&quot;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&quot; data-og-host=&quot;leetcode.com&quot; data-og-source-url=&quot;https://leetcode.com/problems/longest-substring-without-repeating-characters/&quot; data-og-url=&quot;https://leetcode.com/problems/longest-substring-without-repeating-characters/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/crPBUf/hyOQqvDSId/5ShNwkcgrgqseruMfJ3Gpk/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/longest-substring-without-repeating-characters/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://leetcode.com/problems/longest-substring-without-repeating-characters/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/crPBUf/hyOQqvDSId/5ShNwkcgrgqseruMfJ3Gpk/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Longest Substring Without Repeating Characters - LeetCode&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;leetcode.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제 풀이&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생각의 흐름 - 저장하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필요한 건 가장 긴 길이가 무엇이냐? 그리고 이 문자가 나왔는가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 2가지를 저장할 필요가 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 긴 길이 여부는 max 계산을 하고, 이 문자가 이미 나왔는지 여부는 Map에 저장하자고 판단.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생각의 흐름 - 언제 초기화를 하는가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Loop를 돌면서, map이 가지고 있는지 확인한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, 없으면 현재 길이를 늘리면서, map에 저장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;있다면, 1. max 여부를 판단, 2. 현재 길이 초기화, 3. map 초기화&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생각의 흐름 - 어디부터 다시 확인해야 하는가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 긴 길이를 확인할 때, 이미 나왔던 문자가 다시 나왔다면, 어디부터 시작해야하는지 고민해야 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 문자가 처음 나온곳부터 계산하면 되겠다고 판단, Map의 Value에 Index를 저장하기로 판단.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생각의 흐름 - 초기화를 항상 하는가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막 문자까지 간 경우도 고민해주어야 하기에, return 시에 한번 더 max 체크하는 로직을 넣었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1655912627824&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public int lengthOfLongestSubstring(String s) {
    int max = 0;
    int currLen = 0;
    Map&amp;lt;Character, Integer&amp;gt; map = new HashMap&amp;lt;&amp;gt;();
    for(int i = 0; i &amp;lt; s.length(); i++) {
        if(map.containsKey(s.charAt(i))) {
            max = Math.max(max, currLen);
            currLen = 0;
            i = map.get(s.charAt(i));
            map.clear();
        } else {
            map.put(s.charAt(i), i);
            currLen ++;
        }
    }
    return Math.max(currLen, max);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algorithm</category>
      <category>Algorithm</category>
      <category>leetcode</category>
      <category>Longest Substring WIthout Repeating Characters</category>
      <category>알고리즘</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/29</guid>
      <comments>https://koocci-dev.tistory.com/29#entry29comment</comments>
      <pubDate>Thu, 23 Jun 2022 00:45:10 +0900</pubDate>
    </item>
    <item>
      <title>자바스크립트는 무엇일까?</title>
      <link>https://koocci-dev.tistory.com/28</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목표 : 자바스크립트가 무엇인지, 생김새(?) 를 알아보자!&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트로 처음 개발을 시작해보았으니, 거의 10년 가까이 보고 지낸 언어다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼에도 제대로 공부한건 불과 얼마 안되었기에, 한번 기초이론을 정리해보고자 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트는 기본적으로 &lt;b&gt;웹페이지의 보조적인 기능(생동감을 불어주는)&lt;/b&gt;을 수행하기 위해 만들어졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 여러 파생 언어들이 나와, 호환이 완결적이지 않은 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;크로스 브라우징&lt;/b&gt;&lt;/span&gt; 이슈가 발생하기 시작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그로 인해, 꾸준히 발전하며 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;ECMAScript&lt;/b&gt;&lt;/span&gt;라는 표준 고유 명세를 가지게된 언어다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;어떻게 성장해왔을까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최초에는 앞서 말한 대로, 웹페이지의 보조역할을 하였고 대부분 웹 서버로직 + HTML/CSS &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;랜더링&lt;/span&gt;&lt;/b&gt; 수준이었다.&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;랜더링 : HTML, CSS, 자바스크립트로 작성된 문서를 해석하여 브라우저에 시각적으로 출력하는 것&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;때로는 서버에서 데이터를 HTML로 변환하여 브라우저에 전달하는 과정(SSR: Server Side Rendering)을 말하기도 한다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Ajax&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버와 브라우저가 비동기 방식으로 데이터를 교환할 수 있는 통신 기능인 Ajax(Asynchronous Javascript And XML)가 등장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에 완전한 HTML을 전송받고, 전체를 랜더링하던 방식으로 화면이 전환되면 전체 웹페이지를 처음부터 렌더링하던 방식에서 &lt;b&gt;필요한 부분의 데이터만 전송받아 변경&lt;/b&gt;하는 한정적 랜더링 방식이 가능해졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;jQuery&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직도 너무나 보편적인 라이브러리다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;jQuery의 가장 큰 역할은 다소 번거롭던 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;DOM(Document Object Model)&lt;/b&gt;&lt;/span&gt;을 좀 더 쉽게 제어할 수 있게 되고, 크로스 브라우징 이슈가 어느정도 해소될 수 있게 도와준 라이브러리다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;자바스크립트 엔진&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트는 브라우저뿐만 아니라 서버에서도 실행할 수 있다. 그 외에도 자바스크립트 엔진이 있으면 동작이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저는 자바스크립트 가상 머신이라 불리는 엔진이 내장되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔진의 종류는 다양한데, 특유의 코드네임을 가지고 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;V8 - 구글에서 개발하고 Chrome과 Opera에서 쓰인다.&lt;/li&gt;
&lt;li&gt;SpiderMonkey - Firefox에서 쓰인다.&lt;/li&gt;
&lt;li&gt;IE - 버전에 따라, Trident, Chakra 등이 쓰인다.&lt;/li&gt;
&lt;li&gt;Edge - ChakraCore 가 쓰인다.&lt;/li&gt;
&lt;li&gt;Safari - SquirrelFish가 쓰인다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 엔진마다 지원 기능의 차이가 있을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 V8 엔진과 같은 엔진의 등장은 과거 웹 서버가 담당하던 로직들을 클라이언트(브라우저)로 이동했고, 이로 인해 웹 애플리케이션에서 프런트엔드 영역이 주목받게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Node.js&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Node.js&lt;/b&gt;&lt;/span&gt;는 V8엔진으로 빌드된 &lt;b&gt;자바스크립트 런타임 환경&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조금 더 자세히 말하면 &lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;브라우저의 자바스크립트 엔진에서만 동작하던 자바스크립트를 브라우저 이외의 환경에서도 동작할 수 있도록 자바스크립트 엔진을 브라우저에서 독립시킨 자바스크립트 실행 환경&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Node.js는 모듈, 파일 시스템, HTTP 등 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;빌트인(built-in, 내장)&lt;/b&gt;&lt;/span&gt; API를 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Node.js는 서버 환경에서도 자주 사용하기에, 백엔드와 클라이언트가 동일한 언어를 사용할 수 있어, 별도의 언어 학습없이 시작할 수 있는 좋은 길이기도 하다. (내가 그러한 경우다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;비동기I/O&lt;/b&gt;&lt;/span&gt;를 지원하며 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;단일 쓰레드&lt;/b&gt; &lt;b&gt;이벤트 루프 기반&lt;/b&gt;&lt;/span&gt;으로 동작해, 요청 처리 기능이 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 데이터를 실시간으로 처리하기 위해, I/O가 빈번히 일어나는 SPA(Single Page Application)에 적합하지만, CPU 사용률이 높다면 권장되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU 사용률 : 한 컴퓨터 프로그램이 CPU를 차지하여 일을 한 시간의 양&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Single Thread 이므로, 하나의 CPU를 오래 점유하면 그만큼 전체 퍼포먼스는 내려간다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;SPA 프레임워크&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모던 웹 애플리케이션은 데스크톱 애플리케이션과 비교해도 손색없는 성능과 사용자 경험을 제공하는 것이 필수가 되었다. 즉, 개발 규모와 복잡도도 상승했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전의 개발 방식으로는 복잡해진 개발 과정을 수행하기 어려워 지면서, 변경이 유연하고 확장이 쉬운 아키텍처를 요구하게 되고, 프레임워크가 등장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그에 따라, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;CBD(Component Based Development)&lt;/b&gt; &lt;/span&gt;방법론을 기반으로 하는 SPA 가 대중화 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;흔히, Angular, Vue.js, React 등이 그 대표적인 예시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CBD(Component Based Development)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 에러 확인의 시작점은 Divide &amp;amp; Conquer 이듯, 부품을 조립하듯 만드는 개발 방법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Component는 독립적인 기능(서비스)을 제공하는 단위 소프트웨어 모듈을 의미하며, 이런 컴포넌트들은 결국 재사용성이나 대체성을 강화해준다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;ECMAScript&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트 표준 사양인 ECMA-262를 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그래밍 언어의 값, 타입, 객체와 프로퍼티, 함수, 표준 빌트인 객체 등 핵심 문법을 규정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 각 브라우저 제조사는 ECMAScript 사양을 준수해서 브라우저에 내장되는 자바스크립트 엔진을 구현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트는 일반적으로 기본 뼈대(Core)를 이루는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;ECMAScript&lt;/b&gt;&lt;/span&gt;와, 브라우저가 별도로 지원하는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;클라이언트 사이드 Web API&lt;/b&gt;&lt;/span&gt;, 즉 DOM, BOM, Canvas, XMLHttpRequest, fetch, requestAnimationFrame, SVG, Web Storage, Web Component, Web Worker등을 아우르는 개념이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;자바스크립트의 특징은?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트는 결국 &lt;b&gt;웹 브라우저에서 동작하는 유일한 프로그래밍 언어&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 개발자가 별도로 컴파일을 하지 않는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;인터프리터 언어&lt;/b&gt;&lt;/span&gt;이며, 대부분의 모던 자바스크립트 엔진은 인터프리터와 컴파일러의 장점을 결합해 비교적 처리 속도가 느린 단점을 해결하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;또한, 명령형, 함수형, 프로토타입 기반 객체지향 프로그래밍을 지원하는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;멀티 패러다임 프로그래밍&lt;/b&gt; &lt;/span&gt;언어다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 160px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;컴파일러 언어&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;인터프리터 언어&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 40px;&quot;&gt;코드가 실행되기 전 컴파일 타임에 소스코드 전체를 한번에 머신 코드로 변환한 후 실행&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 40px;&quot;&gt;코드가 실행되는 단계인 런타임에 한줄씩 중간 코드인 바이트 코드로 변환한 후 실행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 20px;&quot;&gt;실행 파일을 생성&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 20px;&quot;&gt;실행 파일을 생성하지 않음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 40px;&quot;&gt;컴파일 단계와 실행 단계가 분리, 명시적인 컴파일 단계를 가지고, 명시적으로 실행 파일을 실행&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 40px;&quot;&gt;인터프리트 단계와 실행 단계가 구분되어 있지 않음. 한 줄씩 바이트코드로 변환하고 즉시 실행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 40px;&quot;&gt;컴파일과 실행단계가 분리되어 있으므로 코드 실행 속도가 빠르다.&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 40px;&quot;&gt;인터프리터 단계와 실행 단계가 분리되어 있지 않고 반복 수행되어 코드 실행 속도가 느리다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실행 환경이 중요하다?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 브라우저는 자바스크립트 엔진을 내장하며, Node.js도 자바스크립트 엔진을 가지고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 위와 같은 환경에서 자바스크립트는 실행할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, 브라우저와 Node.js는 용도가 다른점이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;브라우저&lt;/span&gt;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTML, CSS, 자바스크립트를 실행해 웹페이지를 화면에 렌더링 하는 것이 목적&lt;/li&gt;
&lt;li&gt;파싱된 HTML 요소를 선택하거나 조작하는 기능의 집합인 DOM API를 기본 제공&lt;/li&gt;
&lt;li&gt;보안상의 이유로 파일 CRUD(운영체제 역할), 디바이스 상호작용 (마이크 등), Same Origin Policy 등 제약이 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;Node.js&lt;/span&gt;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;브라우저 외부에서 자바스크립트 실행 환경을 제공하는 것이 목적&lt;/li&gt;
&lt;li&gt;DOM API를 제공하지 않는다.&lt;/li&gt;
&lt;li&gt;파일의 생성과 수정을 지원하는 파일 시스템을 기본 제공한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조금 더 설명하자면, 모던 자바스크립트는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;매우 안전한 프로그래밍 언어&lt;/b&gt;&lt;/span&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메모리나 CPU같은 저수준 영역의 조작을 허용하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 접근이 불필요한 브라우저를 대상으로 만들어졌기 때문이다.&lt;/p&gt;</description>
      <category>Programming/javascript</category>
      <category>ECMAScript</category>
      <category>JavaScript</category>
      <category>자바스크립트</category>
      <author>KOOCCI</author>
      <guid isPermaLink="true">https://koocci-dev.tistory.com/28</guid>
      <comments>https://koocci-dev.tistory.com/28#entry28comment</comments>
      <pubDate>Wed, 22 Jun 2022 22:05:10 +0900</pubDate>
    </item>
  </channel>
</rss>