<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Deingve.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Wed, 21 Jun 2023 04:52:30 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Deingve.log</title>
            <url>https://velog.velcdn.com/images/sw_smj/profile/86e592c0-77f2-45cb-8df7-e649eee0f66a/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. Deingve.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/sw_smj" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Effective Java] item 1 : 생성자 대신 정적 팩터리 메서드를 고려하라]]></title>
            <link>https://velog.io/@sw_smj/Effective-Java-item-1-%EC%83%9D%EC%84%B1%EC%9E%90-%EB%8C%80%EC%8B%A0-%EC%A0%95%EC%A0%81-%ED%8C%A9%ED%84%B0%EB%A6%AC-%EB%A9%94%EC%84%9C%EB%93%9C%EB%A5%BC-%EA%B3%A0%EB%A0%A4%ED%95%98%EB%9D%BC</link>
            <guid>https://velog.io/@sw_smj/Effective-Java-item-1-%EC%83%9D%EC%84%B1%EC%9E%90-%EB%8C%80%EC%8B%A0-%EC%A0%95%EC%A0%81-%ED%8C%A9%ED%84%B0%EB%A6%AC-%EB%A9%94%EC%84%9C%EB%93%9C%EB%A5%BC-%EA%B3%A0%EB%A0%A4%ED%95%98%EB%9D%BC</guid>
            <pubDate>Wed, 21 Jun 2023 04:52:30 GMT</pubDate>
            <description><![CDATA[<h2 id="클래스를-얻는-수단">클래스를 얻는 수단</h2>
<ol>
<li>public 생성자 : 클래스의 인스턴스를 얻는 전통적인 수단</li>
<li>정적 팩토리 메서드 : 클래스의 인스턴스를 반환하는 정적 메서드<pre><code class="language-java">public static Boolean valueOf(boolean b) {
   return b ? Boolean.TRUE : Boolean.FALSE;
}</code></pre>
<h2 id="정적-팩터리-메서드">정적 팩터리 메서드</h2>
</li>
</ol>
<h3 id="장점">장점</h3>
<h4 id="1-이름을-가질-수-있다">1. 이름을 가질 수 있다.</h4>
<ul>
<li>이름을 통해 반환될 객체의 특성을 쉽게 묘사할 수 있다.<ul>
<li><code>BigInteger(int, int, Random)</code> vs <code>BigInteger.probablePrime()</code> (값이 소수인 BigInteger를 반환하는 메서드)</li>
</ul>
</li>
<li>생성자를 여러 개 만들 때, 시그니처가 같은 생성자가 여러 개 필요할 경우 → 생성자를 정적 팩터리 메서드로 바꾸고 각각의 차이를 잘 드러내는 이름을 짓는다.<br>

</li>
</ul>
<h4 id="2-호출될-때마다-인스턴스를-새로-생성하지는-않아도-된다">2. 호출될 때마다 인스턴스를 새로 생성하지는 않아도 된다.</h4>
<ul>
<li>불변 클래스 : 인스턴스를 미리 만들어놓거나 새로 생성한 인스턴스를 캐싱하여 재사용할 수 있음<ul>
<li><code>Boolean.valueOf(boolean)</code> : 객체를 아예 생성하지 않음</li>
</ul>
</li>
<li>생성 비용이 큰 같은 객체가 자주 요청되는 상황에서 성능을 끌어올려줌 (≒ 플라이웨이트 패턴(Flyweight pattern))<blockquote>
<p><strong>Flyweight pattern</strong><br></p>
<ul>
<li>어떤 클래스의 인스턴스 한 개만 가지고 여러 개의 &quot;가상 인스턴스&quot;를 제공하고 싶을 때 사용하는 패턴</li>
<li>즉 인스턴스를 가능한 대로 공유시켜 쓸데없이 new연산자를 통한 메모리 낭비를 줄이는 방식
<img src="https://velog.velcdn.com/images/sw_smj/post/c52f130a-6968-4b5c-94da-378d813553ae/image.png" alt=""></li>
</ul>
</blockquote>
</li>
<li>언제 어느 인스턴스를 살아 있게 할지를 철저히 통제할 수 있음 =&gt; <strong>instance-controlled class(인스턴스 통제 클래스)</strong><ul>
<li>클래스를 싱글턴으로도, 혹은 인스턴스화 불가 클래스로도 만들 수 있다.</li>
<li>불변값 클래스에서, 동치인 인스턴스가 단 하나뿐임을 보장할 수 있다.</li>
<li>플라이웨이트 패턴의 근간이 됨</li>
</ul>
</li>
<li>열거 타입 : 인스턴스가 하나만 만들어지는 것을 보장함</li>
</ul>
<br>

<h4 id="3-반환-타입의-하위-타입-객체를-반환할-수-있는-능력이-있다">3. 반환 타입의 하위 타입 객체를 반환할 수 있는 능력이 있다.</h4>
<ul>
<li>반환 객체의 클래스를 자유롭게 선택할 수 있음 -&gt; 유연성 ↑!!!</li>
<li>구현 클래스를 공개하지 않고도 그 객체를 반환할 수 있음 -&gt; API를 작게 유지할 수 있음<ul>
<li>인터페이스를 정적 팩터리 메서드의 반환 타입으로 사용하는 인터페이스 기반 프레임워크를 만드는 핵심 기술</li>
<li>~ Java 7 : 인터페이스에 정적 메서드를 선언할 수 없었음 → 이름이 &quot;Type&quot;인 인터페이스를 반환하는 정적 메서드가 필요할 경우, &quot;Types&quot;라는 companion class(동반 클래스)를 만들어 그 안에 정의하는 것이 관례였음<ul>
<li>Java Collection Framework 중 수정 불가, 동기화 등의 45개 유틸리티 구현체 중 대부분 -&gt; java.util.Collections에서 정적 팩털히 메서드를 통해 얻도록 했음</li>
<li>정적 팩터리 메서드를 사용하는 클라이언트 : 얻은 객체를 구현 클래스가 아닌 인터페이스만으로 다루게 됨 → 좋은 습관</li>
</ul>
</li>
<li>Java 8 : 인터페이스도 정적 메서드를 가지게 됨 → 인스턴스화 불가 동반 클래스를 둘 이유가 별로 없음 (인터페이스 자체에 두면 되기 때문)<ul>
<li>단, 정적 메서드를 구현한 코드 중 많은 부분은 package-private 클래스에 두어야 함</li>
<li>Java 9 : private 정적 메서드까지 허락하지만, 정적 필드와 정적 멤버 클래스는 public이어야 함<br>

</li>
</ul>
</li>
</ul>
</li>
</ul>
<h4 id="4-입력-매개변수에-따라-매번-다른-클래스의-객체를-반환할-수-있다">4. 입력 매개변수에 따라 매번 다른 클래스의 객체를 반환할 수 있다.</h4>
<ul>
<li><p>반환 타입의 하위 타입이기만 하면, 어떤 클래스의 객체를 반환해도 상관 없음</p>
<ul>
<li><code>EnumSet</code> : 원소가 64개 이하면 <code>long</code> 변수 1개를 관리하는 <code>RegularEnumSet</code>, 원소가 65개 이상이면 <code>long</code> 배열로 관리하는 <code>JumboEnumSet</code>의 인스턴스 반환</li>
</ul>
</li>
<li><p>클라이언트는 팩터리가 건네주는 객체가 어느 클래스의 인스턴스인지 알 수도 없고 알 필요도 없음</p>
<br>

</li>
</ul>
<h4 id="5-정적-팩터리-메서드를-작성하는-시점에는-반환할-객체의-클래스가-존재하지-않아도-된다">5. 정적 팩터리 메서드를 작성하는 시점에는 반환할 객체의 클래스가 존재하지 않아도 된다.</h4>
<ul>
<li><p>Service Provider Framework(서비스 제공자 프레임워크)를 만드는 근간이 됨</p>
<ul>
<li>provider = 서비스의 구현체</li>
<li>구현체들을 클라이언트에 제공하는 역할을 프레임워크가 통제하며, 클라이언트를 구현체로부터 분리해줌</li>
</ul>
</li>
<li><p>3개의 핵심 컴포넌트로 이루어짐</p>
<ul>
<li>service interface (서비스 인터페이스)</li>
<li>provider registration API (제공자 등록 API)</li>
<li>service access API (서비스 접근 API)<ul>
<li>클라이언트가 사용할 때, 원하는 구현체의 조건을 명시할 수 있음 (else, 기본 구현체 반환 or 지원하는 구현체들을 하나씩 돌아가며 반환함)</li>
<li>이것이 바로 서비스 제공자 프레임워크의 근간인 유연한 정적 팩터리</li>
</ul>
</li>
<li>service provider interface (서비스 제공자 인터페이스)<ul>
<li>네번째 컴포넌트</li>
<li>서비스 인터페이스의 인스턴스를 생성하는 팩터리 객체 설명해줌</li>
<li>이게 없으면, 각 구현체를 인스턴스로 만들 때 리플렉션을 사용해야 함</li>
</ul>
</li>
</ul>
</li>
<li><p>ex) JDBC(Java Database Connectivity)</p>
<ul>
<li><code>Connection</code> : 서비스 인터페이스</li>
<li><code>DriverManager.registerDriver</code> : 제공자 등록 API</li>
<li><code>DriverManager.getConnection</code> : 서비스 접근 API</li>
<li><code>Driver</code> : 서비스 제공자 인터페이스</li>
</ul>
</li>
<li><p>패턴의 변형이 여러 가지 있음</p>
<ul>
<li>Bridge Pattern(브릿지 패턴) : 공급자가 제공하는 것보다 더 풍부한 서비스 인터페이스를 클라이언트에 반환할 수 있음</li>
<li>Dependency Injection(의존 객체 주입) Framework : 강력한 서비스 제공자</li>
</ul>
</li>
</ul>
<br>

<h3 id="단점">단점</h3>
<h4 id="1-상속을-하려면-public이나-protected-생성자가-필요함---정적-팩터리-메서드만-제공하면-하위-클래스를-만들-수-없음">1. 상속을 하려면 public이나 protected 생성자가 필요함 -&gt; 정적 팩터리 메서드만 제공하면, 하위 클래스를 만들 수 없음</h4>
<ul>
<li>컬렉션 프레임워크의 유틸리티 구현 클래스들은 상속할 수 없다.</li>
<li>단, 상속보다는 컴포지션을 사용하도록 유도하고, 불변 타입으로 만들려면 이 제약을 지켜야 한다는 점에서 오히려 장점이 될 수 있다.</li>
</ul>
<h4 id="2-정적-팩터리-메서드는-프로그래머가-찾기-어렵다">2. 정적 팩터리 메서드는 프로그래머가 찾기 어렵다.</h4>
<ul>
<li>생성자처럼 API 설명에 명확히 드러나지 않음 -&gt; 사용자가 정적 팩터리 메서드 방식 클래스를 인스턴스화할 방법을 찾아야 함</li>
<li>따라서 API 문서를 잘 써놓고, 메서드 이름도 널리 알려진 규약을 따라 짓는 식으로 완화해줘야 함</li>
</ul>
<p><strong>정적 팩터리 메서드 명명 방식</strong></p>
<ul>
<li><code>from</code> :매개변수를 하나 받아서 해당 타입의 인스턴스 반환하는 형변환 메서드 </li>
<li><code>of</code> : 여러 매개변수를 받아 적합한 타입의 인스턴스를 반환하는 집계 메서드</li>
<li><code>valueOf</code> : from과 of의 더 자세한 버전</li>
<li><code>instance</code>, <code>getInstance</code> : (받는다면) 매개변수로 명시한 인스턴스를 반환하지만, 같은 인스턴스임을 보장하지는 않음</li>
<li><code>create</code>, <code>newInstance</code> : instance 혹은 getInstance와 같지만, 매번 새로운 인스턴스를 생성해 반환함을 보장</li>
<li><code>getType</code> : getInstance와 같으나, 생성할 클래스가 아닌 다른 클래스에 팩터리 메서드를 정의할 때 사용함 (Type : 팩터리 메서드가 반환할 객체의 타입)</li>
<li><code>newType</code> : newInstance와 같으나, 생성할 클래스가 아닌 다른 클래스의 팩터리 메서드를 정의할 때 사용함 (Type : 팩터리 메서드가 반환할 객체의 타입)</li>
<li><code>type</code> : getType, newType의 간결한 버전</li>
</ul>
<br>

<h2 id="정리">정리</h2>
<ul>
<li>정적 팩터리 메서드와 public 생성자는 각자의 쓰임새가 있으니, 상대적인 장단점을 이해하고 사용하는 것이 좋다. </li>
<li>단, 정적 팩터리를 사용하는 것이 유리한 경우가 더욱 많으므로, 무작정 public 생성자를 제공하던 습관이 있다면 고쳐야 한다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[HTTP] HTTP 메서드의 활용]]></title>
            <link>https://velog.io/@sw_smj/HTTP-HTTP-%EB%A9%94%EC%84%9C%EB%93%9C%EC%9D%98-%ED%99%9C%EC%9A%A9</link>
            <guid>https://velog.io/@sw_smj/HTTP-HTTP-%EB%A9%94%EC%84%9C%EB%93%9C%EC%9D%98-%ED%99%9C%EC%9A%A9</guid>
            <pubDate>Mon, 01 May 2023 11:55:05 GMT</pubDate>
            <description><![CDATA[<h1 id="client-→-server-데이터-전송">Client → Server 데이터 전송</h1>
<br>

<h3 id="방법-1-query-parameter를-통한-데이터-전송">방법 1. Query Parameter를 통한 데이터 전송</h3>
<ul>
<li>GET</li>
<li>정렬 필터(검색어)</li>
</ul>
<br>

<h3 id="방법-2-message-body를-통한-데이터-전송">방법 2. Message Body를 통한 데이터 전송</h3>
<ul>
<li>POST, PUT, PATCH</li>
<li>회원 가입, 상품 주문, 리소스 등록, 리소스 변경 등</li>
</ul>
<br>

<h3 id="상황-1-정적-데이터-조회">상황 1. 정적 데이터 조회</h3>
<ul>
<li>ex: 이미지, 정적 텍스트 문서</li>
<li>조회 : GET 사용</li>
<li>일반적으로 쿼리 파라미터 없이 리소스 경로로 단순히 조회 가능</li>
</ul>
<br>

<h3 id="상황-21-동적-데이터-조회">상황 21. 동적 데이터 조회</h3>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/caa942a5-b93c-45e4-b434-62812cd47e58/image.png" alt=""></p>
<ul>
<li>ex: 검색, 게시판 목록에서 정렬 필터(검색어)</li>
<li>조회 : GET 사용<ul>
<li>Query Parameter를 사용해서 데이터 전달</li>
</ul>
</li>
<li>조회 조건을 줄여주는 필터, 조회 결과를 정렬하는 정렬 조건에 주로 사용</li>
</ul>
<br>

<h3 id="상황-3-html-form">상황 3. HTML Form</h3>
<ul>
<li><p><code>POST</code> -&gt; Message Body에 넣어 전송
<img src="https://velog.velcdn.com/images/sw_smj/post/7f89f16d-7a9c-45f5-bc02-bc54e1d03013/image.png" alt=""></p>
</li>
<li><p><code>GET</code> -&gt; URL에 넣어 전송
<img src="https://velog.velcdn.com/images/sw_smj/post/0452ddc9-ba1f-4bb1-9aab-b4a8bbdb2369/image.png" alt=""></p>
<blockquote>
<p>📌 <strong>주의</strong>
단, GET은 조회에만 사용!
리소스 변경이 발생하는 곳에 사용 X (ex: 회원가입 등)</p>
</blockquote>
</li>
<li><p><code>multipart/form-data</code> 
<img src="https://velog.velcdn.com/images/sw_smj/post/80770b84-84a3-405f-a2e5-4482395cba7f/image.png" alt=""></p>
</li>
<li><p>ex: 회원 가입, 상품 주문, 데이터 변경</p>
</li>
<li><p><code>GET</code>, <code>POST</code> 가능</p>
</li>
<li><p><code>Content-Type : application/x-www-form-urlencoded</code></p>
<ul>
<li>form의 내용을 메시지 바디를 통해 전송(key-value, 쿼리 파라미터 형식)</li>
<li>전송 데이터를 url encoding 처리 (ex: <code>abc김</code> → <code>abc%EA%B9%80</code>)</li>
</ul>
</li>
<li><p><code>Content-Type : multipart/form-data</code></p>
<ul>
<li>파일 업로드 등의 바이너리 데이터 전송 시 사용</li>
<li>다른 종류의 여러 파일과 폼의 내용을 함께 전송 가능 (그래서 multipart)</li>
</ul>
</li>
</ul>
<br>

<h3 id="상황-4-http-api">상황 4. HTTP API</h3>
<ul>
<li>ex: 회원 가입, 상품 주문, 데이터 변경</li>
<li>용도 : 서버 to 서버(백엔드), 앱 클라이언트(iOS, Android), 웹 클라이언트(Ajax(React, View))</li>
<li><code>POST</code>, <code>PUT</code>, <code>PATCH</code> : 메시지 바디를 통해 데이터 전송</li>
<li><code>GET</code> : 쿼리 파라미터로 데이터 전달</li>
<li><code>Content-Type: application/json</code> 주로 사용 (그 외: TEXT, XML 등)</li>
</ul>
<p><br><br></p>
<h1 id="api-설계">API 설계</h1>
<h2 id="방향">방향</h2>
<p><strong>1. Collection</strong></p>
<ul>
<li><code>POST</code> 기반 등록</li>
<li>ex) 회원 관리 API</li>
</ul>
<p><strong>2. Store</strong></p>
<ul>
<li><code>PUT</code> 기반 등록</li>
<li>ex) 정적 컨텐츠 관리, 원격 파일 관리</li>
</ul>
<p><strong>3. HTML Form 사용</strong></p>
<ul>
<li><code>GET</code>, <code>POST</code>만 지원</li>
<li>웹 페이지 회원 관리</li>
</ul>
<br>

<h2 id="1-collection---post-기반-등록">1. Collection - POST 기반 등록</h2>
<blockquote>
<ul>
<li>회원 목록 <code>/members</code> : <code>GET</code></li>
<li>회원 등록 <code>/members</code> : <code>POST</code></li>
<li>회원 조회 <code>/members/{id}</code> : <code>GET</code></li>
<li>회원 수정 <code>/members/{id}</code> : <code>PATCH</code>, <code>PUT</code>, <code>POST</code></li>
<li>회원 삭제 <code>/members/{id}</code> : <code>DELETE</code></li>
</ul>
</blockquote>
<ul>
<li>클라이언트는 등록될 리소스의 URI를 모름</li>
<li>서버가 새로 등록된 리소스 URI를 생성해줌<ul>
<li>ex) <code>POST /members/100</code></li>
</ul>
</li>
<li><strong><code>Collection</code></strong><ul>
<li>서버가 관리하는 리소스 디렉토리</li>
<li>서버가 리소스의 URI를 생성하고 관리</li>
<li>여기서 컬렉션 : <code>/members</code></li>
</ul>
</li>
</ul>
<br>

<h2 id="2-store---post-기반-등록">2. Store - POST 기반 등록</h2>
<blockquote>
<ul>
<li>회원 목록 <code>/members</code> : <code>GET</code></li>
<li>회원 등록 <code>/members</code> : <code>POST</code></li>
<li>회원 조회 <code>/members/{id}</code> : <code>GET</code></li>
<li>회원 수정 <code>/members/{id}</code> : <code>PATCH</code>, <code>PUT</code>, <code>POST</code></li>
<li>회원 삭제 <code>/members/{id}</code> : <code>DELETE</code></li>
</ul>
</blockquote>
<ul>
<li>클라이언트가 리소스 URI를 알고 있음<ul>
<li><code>PUT /files/{filename}</code></li>
<li><code>PUT /files/star.jpg</code></li>
</ul>
</li>
<li>클라이언트가 직접 리소스의 URI를 지정함</li>
<li><strong><code>Store</code></strong><ul>
<li>클라이언트가 관리하는 리소스 저장소</li>
<li>클라이언트가 리소스의 URI를 알고 관리</li>
<li><code>/files</code> : 스토어</li>
</ul>
</li>
</ul>
<br>

<h2 id="3-html-form-사용">3. HTML Form 사용</h2>
<blockquote>
<ul>
<li>회원 목록 <code>/members</code> : <code>GET</code></li>
<li>회원 등록 폼 <code>/members/new</code> : <code>GET</code></li>
<li>회원 등록 폼 <code>/members/new</code> or <code>/members</code> : <code>POST</code></li>
<li>회원 조회 <code>/members/{id}</code> : <code>GET</code></li>
<li>회원 수정 폼 <code>/members/{id}/edit</code> : <code>GET</code></li>
<li>회원 수정 <code>/members/{id}/edit</code> or <code>/members/{id}</code> : <code>POST</code></li>
<li>회원 삭제 <code>/members/{id}/delete</code> : <code>POST</code></li>
</ul>
</blockquote>
<ul>
<li><code>GET</code>, <code>POST</code>만 지원<ul>
<li>AJAX 같은 기술을 사용해서 해결 가능</li>
<li>순수 HTML Form만 이용하면 제약이 있음</li>
</ul>
</li>
</ul>
<blockquote>
<p>💡 <strong>추가 Tips!</strong> 참고하면 좋을 URI 설계 개념</p>
<ul>
<li><p><strong>document</strong> 
단일 개념
ex) <code>/members/100</code>, <code>/files/star.jpg</code></p>
</li>
<li><p><strong>collection</strong>
서버가 관리하는 리소스 디렉토리, 서버가 리소스의 URI를 생성하고 관리 
ex) <code>/members</code></p>
</li>
<li><p><strong>store</strong>
클라이언트가 관리하는 자원 저장소
클라이언트가 리소스의 URI를 알고 관리
<code>/files</code></p>
</li>
<li><p><strong>controller, control URI</strong>
문서, 컬렉션, 스토어로 해결하기 어려운 추가 프로세스 실행. 동사를 직접 사용
ex) <code>/members/{id}/delete</code></p>
</li>
</ul>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[HTTP] HTTP 설계 및 메서드]]></title>
            <link>https://velog.io/@sw_smj/HTTP-HTTP-%EC%84%A4%EA%B3%84-%EB%B0%8F-%EB%A9%94%EC%84%9C%EB%93%9C</link>
            <guid>https://velog.io/@sw_smj/HTTP-HTTP-%EC%84%A4%EA%B3%84-%EB%B0%8F-%EB%A9%94%EC%84%9C%EB%93%9C</guid>
            <pubDate>Sun, 23 Apr 2023 13:00:39 GMT</pubDate>
            <description><![CDATA[<h2 id="api-uri-설계">API URI 설계</h2>
<ul>
<li>리소스 식별</li>
<li>URI 계층 구조 활용</li>
</ul>
<h3 id="예시">예시</h3>
<ul>
<li>회원 목록 조회 <code>/members</code></li>
<li>회원 목록 조회 <code>/members</code></li>
<li>회원 목록 조회 <code>/members</code></li>
<li>회원 목록 조회 <code>/members</code></li>
</ul>
<h3 id="리소스와-행위를-분리한다">리소스와 행위를 분리한다</h3>
<ul>
<li>URI : 리소스만 식별하며, 행위는 식별하지 않는다.</li>
<li>리소스 = 명사 / 행위 = 동사</li>
</ul>
<blockquote>
<p><strong>URI 네이밍시 참고!</strong>
계층 구조상 상위를 컬렉션으로 봄
→ 복수단어 사용 권장!
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- member (X)
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- members (O)</p>
</blockquote>
<br>

<h3 id="http-메서드-종류">HTTP 메서드 종류</h3>
<ul>
<li><code>GET</code> : 리소스 조회</li>
<li><code>POST</code> : 요청 데이터 처리, 주로 등록에 사용</li>
<li><code>PUT</code> : 리소스를 대체, 해당 리소스가 없으면 생성</li>
<li><code>PATCH</code> : 리소스 부분 변경</li>
<li><code>DELETE</code> : 리소스 삭제</li>
</ul>
<p><strong>기타 메서드</strong></p>
<ul>
<li><code>HEAD</code> : GET과 동일하지만 메시지 부분을 제외하고 상태 줄과 헤더만 반환</li>
<li><code>OPTIONS</code> : 대상 리소스에 대한 통신 가능 옵션(메서드)을 주로 설명 (주로 CORS에서 사용)</li>
<li><code>CONNECT</code> : 대상 자원으로 식별되는 서버에 대한 터널을 설정</li>
<li><code>TRACE</code> : 대상 리소스에 대한 경로를 따라 메시지 루프백 테스트를 수행</li>
</ul>
<br>

<h3 id="get">GET</h3>
<ul>
<li>서버에 전달하고 싶은 데이터는 query parameter(query string)를 통해 전달</li>
<li>메시지 바디를 사용해서 데이터 전달도 가능은 하지만, 지원하지 않는 곳이 많아 권장하지 않음</li>
</ul>
<h3 id="post">POST</h3>
<ul>
<li>메시지 바디를 통해 서버로 요청 데이터 전달</li>
<li>서버는 요청 데이터를 처리함 (메시지 바디를 통해 들어온 데이터를 처리하는 모든 기능들 수행)</li>
<li>전달된 데이터로 신규 리소스를 등록하고, 프로세스 처리에 사용함</li>
</ul>
<h4 id="기능">기능</h4>
<ol>
<li>새 리소스 생성</li>
<li>요청 데이터 처리 (프로세스 처리)</li>
<li>다른 메서드로 처리하기 어려운 경우<ul>
<li>JSON으로 조회 데이터를 넘겨야 하는데, GET 메서드를 사용하기 어려운 경우</li>
<li>애매하면 POST 사용</li>
</ul>
</li>
</ol>
<h3 id="put">PUT</h3>
<ul>
<li>리소스를 대체함<ul>
<li>리소스가 있으면 대체, 없으면 생성</li>
<li>즉, 덮어씌워버림!</li>
</ul>
</li>
<li>POST와의 차이점 : 클라이언트가 리소스 위치를 알고 URI를 지정한다.</li>
</ul>
<h3 id="patch">PATCH</h3>
<ul>
<li>리소스 부분을 변경함</li>
</ul>
<blockquote>
<p>💡 <strong>PUT과 PATCH의 차이</strong>
⇒ <strong>멱등성</strong>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;: 어떤 대상에 같은 연산을 여러 번 적용해도 결과가 달라지지 않는 성질</p>
<ul>
<li>PUT : 멱등성 보장</li>
<li>PATCH : 멱등성 보장하지 않을 수 있음</li>
</ul>
</blockquote>
<h3 id="delete">DELETE</h3>
<ul>
<li>리소스를 제거함</li>
</ul>
<br>

<h2 id="http-메서드의-속성들">HTTP 메서드의 속성들</h2>
<ul>
<li>안전함 여부</li>
<li>멱등성 여부</li>
<li>캐시 가능 여부</li>
</ul>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/3824023b-e732-49ba-9444-44bd2c8a76b0/image.png" alt=""></p>
<h3 id="안전함">안전함</h3>
<ul>
<li>호출해도 리소스를 변경하지 않음
(로그 데이터 고려 X)</li>
</ul>
<h3 id="멱등성idempotent">멱등성(Idempotent)</h3>
<ul>
<li>f(f(x)) = f(x)</li>
</ul>
<blockquote>
<p>POST는 멱등 메서드가 아님! 두 번 호출하면 같은 결제가 중복해서 발생할 수 있음</p>
</blockquote>
<blockquote>
<p>📌 <strong>중요한 이유</strong></p>
<ul>
<li>자동 복구 메커니즘을 짤 떄 고려</li>
<li>서버가 TIMEOUT 등으로 정상 응답을 못 주었을 때, 클라이언트가 같은 요청을 다시 해도 되는가?</li>
</ul>
</blockquote>
<h3 id="캐시-가능-cacheable">캐시 가능 (Cacheable)</h3>
<ul>
<li>응답 결과 리소스를 캐시해서 사용해도 되는가?<ul>
<li><code>GET</code>, <code>HEAD</code>, <code>POST</code>, <code>PATCH</code> 캐시 가능</li>
<li>실제로는 <code>GET</code>, <code>HEAD</code> 정도만 캐시로 사용</li>
<li><code>POST</code>, <code>PATCH</code> : 본문 내용까지 캐시 키로 고려해야 하는데, 구현이 쉽지 않음</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[HTTP] HTTP의 기본]]></title>
            <link>https://velog.io/@sw_smj/HTTP-HTTP%EC%9D%98-%EA%B8%B0%EB%B3%B8</link>
            <guid>https://velog.io/@sw_smj/HTTP-HTTP%EC%9D%98-%EA%B8%B0%EB%B3%B8</guid>
            <pubDate>Sun, 23 Apr 2023 12:09:46 GMT</pubDate>
            <description><![CDATA[<h1 id="http">HTTP</h1>
<p><strong>HyperText Transfer Protocol</strong></p>
<br>

<h3 id="http-메시지에-담길-수-있는-것들">HTTP 메시지에 담길 수 있는 것들</h3>
<blockquote>
<p>거의 모든 것!</p>
</blockquote>
<ul>
<li>HTML, TEXT</li>
<li>IMAGE, 음성, 영상, 파일</li>
<li>JSON, XML (API)</li>
</ul>
<p>즉,</p>
<ul>
<li>거의 모든 형태의 데이터 전송 가능</li>
<li>서버간에 데이터를 주고 받을 때도 대부분 HTTP 사용</li>
<li>지금은 HTTP 시대</li>
</ul>
<br>

<h3 id="역사">역사</h3>
<ul>
<li><code>HTTP/0.9</code> : GET 메서드만 지원. HTTP 헤더 X (1991)</li>
<li><code>HTTP/1.0</code> : 메서드, 헤더 추가 (1996)</li>
<li><strong><code>HTTP/1.1</code></strong> : 가장 많이 사용. 우리에게 가장 중요한 버전 (1997)<ul>
<li>RFC2068 (1997) → RFC2616 (1999) → RFC7230 ~ 7235 (2014)</li>
</ul>
</li>
<li><code>HTTP/2</code> : 성능 개선 (2015)</li>
<li><code>HTTP/3</code> : TCP 대신 UDP 사용, 성능 개선 (진행 중)</li>
</ul>
<br>

<h3 id="기반-프로토콜">기반 프로토콜</h3>
<ul>
<li><strong>TCP</strong> : <code>HTTP/1.1</code>, <code>HTTP/2</code></li>
<li><strong>UDP</strong> : <code>HTTP/3</code></li>
</ul>
<blockquote>
<p>현재는 HTTP/1.1 주로 사용!
단, HTTP/2, HTTP/3도 점점 증가 중</p>
</blockquote>
<br>

<h2 id="http의-특징">HTTP의 특징</h2>
<ul>
<li>Client-Server 구조</li>
<li>Stateless Protocol</li>
<li>비연결성</li>
<li>HTTP 메시지</li>
<li>단순함, 확장 가능</li>
</ul>
<br>

<h3 id="1-client-server-구조">1. Client-Server 구조</h3>
<ul>
<li>Request, Response의 구조</li>
<li>클라이언트 : 서버에 요청을 보내고, 응답을 대기</li>
<li>서버 : 요청에 대한 결과를 만들어 응답</li>
</ul>
<blockquote>
<p>💡 <strong>중요한 이유!</strong></p>
<ul>
<li><strong>클라이언트와 서버를 분리할 수 있음</strong></li>
<li>비즈니스 로직 등 필요한 로직 등을 모두 서버에 넣을 수 있음</li>
</ul>
</blockquote>
<br>

<h3 id="2-stateless-protocol">2. Stateless Protocol</h3>
<ul>
<li>서버가 클라이언트의 상태를 보존하지 않음</li>
</ul>
<h4 id="장점">장점</h4>
<ul>
<li>서버 확장성 높음 (Scale-Out) 즉, 갑자기 클라이언트 요청이 증가해도 서버를 대거 투입할 수 있음. 수평 확장 유리</li>
<li>응답 서버를 쉽게 바꿀 수 있음 → <strong>무한한 서버 증설 가능</strong></li>
</ul>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/4e73e324-3cc1-4f5b-88ba-3c6a30707d09/image.png" alt=""></p>
<br>

<h4 id="단점">단점</h4>
<ul>
<li>클라이언트가 데이터가 필요할 때마다 매번 추가적으로 전송해야 함</li>
</ul>
<br>

<h4 id="실무-한계">실무 한계</h4>
<ul>
<li>모든 것을 무상태로 설계할 수 없는 경우도 존재함 
(ex: 로그인 - 로그인한 사용자의 경우, 로그인했다는 상태를 서버에 유지해야 함)</li>
<li>일반적으로 브라우저 쿠키와 서버 세션등을 사용해서 상태 유지</li>
<li>상태 유지(Stateful)는 최소한만 사용</li>
</ul>
<h3 id="3-connectionless-비연결성">3. Connectionless (비연결성)</h3>
<ul>
<li>HTTP : 기본적으로 연결을 유지하지 않는 모델</li>
</ul>
<p><strong>만약 비연결성이 아니라면?</strong></p>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/33215983-82a5-403a-85ee-0f3abfe2edd8/image.png" alt=""></p>
<p><strong>비연결성의 장점</strong></p>
<ul>
<li>일반적으로 초단위 이하의 빠른 속도로 응답 가능</li>
<li>1시간 동안 수천명이 서비스를 사용해도, 실제 서버에서 동시에 처리하는 요청은 수십개 이하로 매우 작음 (ex: 웹브라우저에서 연속해서 검색 버튼을 누르지 않음)</li>
<li>서버 자원을 매우 효율적으로 사용 가능</li>
</ul>
<p><strong>비연결성의 한계와 극복</strong></p>
<ul>
<li>TCP/IP 연결을 새로 맺어야 함 → 3-way handshake 시간 추가됨</li>
<li>HTML 뿐만 아니라 JS, CSS, 추가 이미지 등 많은 자원이 함께 다운로드됨</li>
<li>현재는 <strong>HTTP Persistent Connections (지속 연결)</strong>로 문제 해결 (이제는 기본 설정임)
<img src="https://velog.velcdn.com/images/sw_smj/post/26530264-cc1a-4daa-9ff7-31450300befc/image.png" alt=""><blockquote>
<p>📌 <strong>참고 - HTTP 초기 (지속 연결 X)</strong>
<img src="https://velog.velcdn.com/images/sw_smj/post/16e9a8ec-21dd-4bc7-8d6e-18dd8ee86e4b/image.png" alt=""></p>
</blockquote>
</li>
<li>HTTP/2, HTTP/3에서 더 많은 최적화</li>
</ul>
<br>

<h3 id="4-stateless">4. Stateless</h3>
<blockquote>
<p>서버 개발자들이 어려워하는 업무</p>
</blockquote>
<ul>
<li>정말 같은 시간에 딱 맞추어 발생하는 대용량 트래픽 등에도 잘 대처할 수 있음</li>
</ul>
<br>

<h1 id="http-구조">HTTP 구조</h1>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/5188d48e-da68-4e50-82ca-a835df73ead9/image.png" alt=""></p>
<h3 id="request">Request</h3>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/f696d405-06c5-4598-b3b7-e040503b5e9d/image.png" alt=""></p>
<blockquote>
<p>단! 요청 메시지도 body 본문을 가질 수 있음</p>
</blockquote>
<ul>
<li>start-line = <strong>request-line</strong> / status-line<ul>
<li><strong>request-line</strong> = <code>method</code> SP(공백) <code>request-target</code> SP <code>HTTP-version</code> CRLF(엔터)</li>
<li>request-target = <code>/search?q=hello&amp;hl=ko</code>. 절대경로[?]쿼리 (<code>/</code>로 시작함)   </li>
</ul>
</li>
</ul>
<h3 id="response">Response</h3>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/0ac8aff3-1931-40e6-acf4-e4833b128af3/image.png" alt=""></p>
<ul>
<li>start-line = request-line / <strong>status-line</strong></li>
<li><strong>status-line</strong> = <code>HTTP-version</code> SP <code>status-code</code> SP <code>reason-phrase</code> CRLF<ul>
<li><code>reason-phrase</code> : 짧은 상태코드 설명 글</li>
</ul>
</li>
</ul>
<h2 id="http-header">HTTP Header</h2>
<ul>
<li>header-field = <code>field-name``:</code> OWS <code>field-value</code> OWS(띄어쓰기 허용)<ul>
<li><code>field-name</code> : 대소문자 구분 없음</li>
</ul>
</li>
</ul>
<h3 id="특징">특징</h3>
<ul>
<li>HTTP 전송에 필요한 모든 부가 정보<ul>
<li>메시지 바디의 내용</li>
<li>메시지 바디의 크기</li>
<li>압축</li>
<li>인증</li>
<li>요청 클라이언트(브라우저) 정보</li>
<li>서버 애플리케이션 정보</li>
<li>캐시 관리 정보</li>
</ul>
</li>
<li>표준 헤더가 너무 많음</li>
<li>필요시 임의의 헤더 추가 가능</li>
</ul>
<h2 id="http-message-body">HTTP Message Body</h2>
<ul>
<li>실제 전송할 데이터</li>
<li>HTML 문서, 이미지, 영상, JSON 등등 byte로 표현할 수 있는 모든 데이터 전송 가능</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Web] URI와 웹 브라우저 요청 흐름]]></title>
            <link>https://velog.io/@sw_smj/Web-URI%EC%99%80-%EC%9B%B9-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EC%9A%94%EC%B2%AD-%ED%9D%90%EB%A6%84</link>
            <guid>https://velog.io/@sw_smj/Web-URI%EC%99%80-%EC%9B%B9-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EC%9A%94%EC%B2%AD-%ED%9D%90%EB%A6%84</guid>
            <pubDate>Sun, 23 Apr 2023 09:27:02 GMT</pubDate>
            <description><![CDATA[<h2 id="uri-uniform-resource-identifier">URI (Uniform Resource Identifier)</h2>
<p><strong>자원 식별자</strong></p>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/21ea5497-640f-48d1-893e-57fe50ba174f/image.png" alt=""></p>
<ul>
<li>Locator, Name 또는 둘 다 추가로 분류될 수 있다.</li>
</ul>
<h2 id="url-vs-urn">URL vs URN</h2>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/9193db49-da86-4b8f-b4c1-b574de3bd32b/image.png" alt=""></p>
<h3 id="url이란">URL이란?</h3>
<p><strong>Uniform Resource Locator</strong></p>
<ul>
<li>리소스가 있는 위치를 지정</li>
<li>보통 리소스를 찾는 방법으로는 보편적으로 URL을 사용</li>
</ul>
<blockquote>
<p>따라서, 편의상 앞으로 URI를 URL과 같은 의미로 이야기할 것임</p>
</blockquote>
<h3 id="urn이란">URN이란?</h3>
<p><strong>Uniform Resource Name</strong></p>
<ul>
<li>리소스에 이름을 부여</li>
<li>위치는 변할 수 있지만, 이름은 변하지 않는다.</li>
<li>단, 반대로 URN 이름만으로 실제 리소스를 찾을 수 있는 방법이 보편화 되지 않음</li>
<li>책의 isbn 등에 유용 - ex)<code>urn:isbn:89607773331</code></li>
</ul>
<br>

<h2 id="url-문법">URL 문법</h2>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/9e8e6451-fc08-4167-a64e-919a0f067cd3/image.png" alt=""></p>
<ul>
<li><code>https</code> : 프로토콜</li>
<li><code>www.google.com</code> : 호스트명 (도메인명 또는 IP 주소)</li>
<li><code>443</code> : 포트 번호</li>
<li><code>/search</code> : 패스 (= path = 리소스 경로, 계층적 구조)</li>
<li><code>q=hello&amp;hl=ko</code> : 쿼리 파라미터 (key=value 형태, ?로 시작) (=query parameter, query string)</li>
</ul>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/9c333019-18f7-45b6-9f11-42a6132ba9ba/image.png" alt=""></p>
<ul>
<li><code>#fragment</code> : HTML 내 북마크 등에서 사용함 (블록으로 이동 등) (서버에 전송하는 정보 X)</li>
</ul>
<h3 id="특징">특징</h3>
<ul>
<li>주로 프로토콜 사용<blockquote>
<p>📌 <strong>프로토콜</strong>
어떤 방식으로 자원에 접근할 것인가 하는 약속 규칙</p>
<ul>
<li>ex) <code>http</code>, <code>https</code>, <code>ftp</code> 등</li>
<li><code>http</code>
80 포트 주로 사용 (생략 가능)</li>
<li><code>https</code>
 http에 보안 추가된 것 (HTTP Secure)
 443 포트 주로 사용 (생략 가능)</li>
</ul>
</blockquote>
</li>
</ul>
<br>

<h1 id="웹-브라우저의-요청-흐름">웹 브라우저의 요청 흐름</h1>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/e15fe44b-a862-431e-a2db-337dc17264b4/image.png" alt=""></p>
<h3 id="http-request">HTTP Request</h3>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/a44ea61a-7da2-430a-a154-6393ad759fb3/image.png" alt=""></p>
<h3 id="packet">Packet</h3>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/e2cf3667-e724-4747-82c5-afeb3720fbc7/image.png" alt=""></p>
<h3 id="요청-packet-전송">요청 Packet 전송</h3>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/1817578d-cde4-4da8-bc9f-c96554fb4a96/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/046c69e3-4bc2-4de4-bd44-e73f27a301c8/image.png" alt=""></p>
<h3 id="http-response">HTTP Response</h3>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/8fb57ea0-24ac-494a-b56c-70aeac83bf60/image.png" alt=""></p>
<h3 id="응답-packet-전송">응답 Packet 전송</h3>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/f5df7bf1-1210-4080-8e40-42bcb6fa7ea4/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Web] 인터넷 통신]]></title>
            <link>https://velog.io/@sw_smj/HTTPWEB-%EC%9D%B8%ED%84%B0%EB%84%B7-%ED%86%B5%EC%8B%A0</link>
            <guid>https://velog.io/@sw_smj/HTTPWEB-%EC%9D%B8%ED%84%B0%EB%84%B7-%ED%86%B5%EC%8B%A0</guid>
            <pubDate>Sun, 23 Apr 2023 08:19:47 GMT</pubDate>
            <description><![CDATA[<h3 id="web">Web</h3>
<p>모든 것이 HTTP 위에서 동작함! (데이터를 주고 받음)</p>
<h1 id="ip">IP</h1>
<p><strong>Internet Protocol</strong></p>
<ul>
<li>지정한 IP Address(IP 주소)에 데이터 전달</li>
<li>Packet이라는 통신 단위로 데이터 전달<ul>
<li>패킷 구조
<img src="https://velog.velcdn.com/images/sw_smj/post/4b23d04c-4542-48ef-bdfd-613a3a1edcb6/image.png" alt=""></li>
<li>Client가 패킷을 전달하기
<img src="https://velog.velcdn.com/images/sw_smj/post/0d78d4f4-9b02-4eb1-bb24-7a13b5f6cf9c/image.png" alt=""></li>
<li>Server가 패킷을 전달하기
<img src="https://velog.velcdn.com/images/sw_smj/post/1b5c62a5-20a1-4c50-9a97-7559a68dd992/image.png" alt=""></li>
</ul>
</li>
</ul>
<h3 id="한계">한계</h3>
<ul>
<li><p><strong>비연결성</strong>
패킷을 받을 대상이 없거나 서비스 불능 상태여도 패킷이 전송됨</p>
</li>
<li><p><strong>비신뢰성</strong></p>
<ul>
<li>중간에 패킷이 사라지면?</li>
<li>패킷이 순서대로 안 오면?</li>
</ul>
</li>
<li><p><strong>프로그램 구분</strong></p>
<ul>
<li>같은 IP를 사용하는 서버에서 통신하는 애플리케이션이 둘 이상이면?</li>
</ul>
</li>
</ul>
<br>


<h3 id="인터넷-4계층">인터넷 4계층</h3>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/fa1c95b0-08b9-4366-b72b-f55107329839/image.png" alt=""></p>
<p>계층별로 올라가면서, 다음과 그림과 같이 데이터를 덧붙여 씌움</p>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/ca3bb327-6142-46bb-bbc4-e28ea096078a/image.png" alt=""></p>
<p>다음은 전송계층 / 인터넷계층을 지나면서 덧붙여지는 내용들
<img src="https://velog.velcdn.com/images/sw_smj/post/ddc8aa54-3d04-44c7-88cc-74fdb97b8e05/image.png" alt=""></p>
<br>

<h1 id="tcpudp">TCP/UDP</h1>
<h2 id="tcp">TCP</h2>
<p><strong>전송 제어 프로토콜 (Transmission Control Protocol)</strong></p>
<ul>
<li>연결 지향 - TCP 3 handshake (가상 연결)</li>
<li>데이터 전달 보증</li>
<li>순서 보장
<img src="https://velog.velcdn.com/images/sw_smj/post/5a6c8f51-71b4-4403-816a-f731d8902a48/image.png" alt=""></li>
<li>신뢰할 수 있는 프로토콜</li>
<li>현재는 대부분 TCP 사용</li>
</ul>
<h3 id="3-way-handshake">3-way handshake</h3>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/8d4406a1-d3b1-466a-8695-590265249952/image.png" alt=""></p>
<h3 id="4-way-handshake">4-way handshake</h3>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/3cc95d68-119f-4fb2-a3bd-4fe8c5c9beea/image.png" alt=""></p>
<br>

<h2 id="udp">UDP</h2>
<p><strong>사용자 데이터그램 프로토콜 (User Datagram Protocol)</strong></p>
<ul>
<li>기능이 거의 없음</li>
<li>연결 지향 X</li>
<li>데이터 전달 보증 X</li>
<li>순서 보장 X</li>
<li>데이터 전달 및 순서가 보장되지 않지만, 단순하고 빠름</li>
<li>정리<ul>
<li>IP와 거의 같지만, PORT, CHECKSUM 정도만 추가됨</li>
<li>Application에서 추가 작업 필요</li>
</ul>
</li>
</ul>
<br>

<h3 id="port-정보란">PORT 정보란?</h3>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/7f7a5c52-3905-4e31-8710-6afbf6e587a4/image.png" alt=""></p>
<ul>
<li><p><code>0</code> ~ <code>65535</code> : 할당 가능</p>
</li>
<li><p><code>0</code> ~ <code>1023</code> : 잘 알려진 포트, 사용하지 않는 것이 좋음</p>
<ul>
<li><code>20</code>, <code>21</code> : FTP</li>
<li><code>23</code> : TELNET</li>
<li><code>80</code> : HTTP</li>
<li><code>443</code> : HTTPS</li>
</ul>
<br>

<h2 id="dns란">DNS란?</h2>
<p><strong>Domain Name System</strong></p>
<ul>
<li>전화번호부</li>
<li>도메인 명을 IP 주소로 변환
<img src="https://velog.velcdn.com/images/sw_smj/post/3797c9cb-b07d-48a5-888f-634c7c2ab21b/image.png" alt=""></li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] Bean Scope]]></title>
            <link>https://velog.io/@sw_smj/Spring-Bean-Scope</link>
            <guid>https://velog.io/@sw_smj/Spring-Bean-Scope</guid>
            <pubDate>Fri, 21 Apr 2023 13:09:27 GMT</pubDate>
            <description><![CDATA[<h1 id="bean-scope">Bean Scope</h1>
<p>: 빈이 존재할 수 있는 범위</p>
<h3 id="다양한-scope">다양한 Scope</h3>
<ul>
<li><strong>Singleton</strong><ul>
<li>기본 스코프</li>
<li>스프링 컨테이너의 시작과 종료까지 유지되는, 가장 넒은 범위의 스코프</li>
</ul>
</li>
<li><strong>Prototype</strong><ul>
<li>스프링 컨테이너는 생성과 의존관계 주입가지만 관여</li>
<li>그 이후는 관리하지 않음</li>
<li>매우 짧은 범위의 스코프</li>
</ul>
</li>
</ul>
<h3 id="web-관련-scope">Web 관련 Scope</h3>
<ul>
<li><strong>request</strong> : 웹 요청이 들어오고 나갈 때까지 유지되는 스코프</li>
<li><strong>session</strong> : 웹 세션이 생성되고 종료될 때까지 유지되는 스코프</li>
<li><strong>application</strong> : 웹의 서블릿 컨텍스트와 같은 범위로 유지되는 스코프</li>
</ul>
<br>

<h2 id="singleton-bean-scope">Singleton Bean Scope</h2>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/f417b8e6-58c7-4be0-aac6-003b3695d060/image.png" alt=""></p>
<ul>
<li>스프링 컨테이너가 소멸때까지 관리함</li>
<li></li>
</ul>
<br>

<h2 id="prototype-bean-scope">Prototype Bean Scope</h2>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/c250f3a8-897f-410e-94e4-7dad64481814/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/03005af7-1aec-49d9-95d8-4bd8c644f837/image.png" alt=""></p>
<ul>
<li>스프링 컨테이너는 생성과 의존관계 주입, 초기화까지만 관리하고, 다시 유저에게 반환해버림</li>
<li>즉, 보관하지 않기 때문에 매번 생성해서 반환함</li>
<li>따라서 <code>@PreDestroy</code>와 같은 종료메서드가 호출되지 않는다.</li>
</ul>
<h3 id="문제-사항">문제 사항</h3>
<ul>
<li>스프링은 일반적으로 싱글톤 빈을 사용하므로, 싱글톤 빈이 프로토타입 빈을 사용하게 된다.</li>
<li>단, 싱글톤 빈은 생성 시점에만 의존관계 주입을 받기 때문에, 프로토타입 빈이 생성 단계에서 생성된 후 유지되는 것이 문제!!</li>
</ul>
<blockquote>
<p>보통은, 이런 경우를 피하고 싶어서 프로토타입 빈을 사용한다. 따라서 의도와 다르게 동작할 가능성 ↑</p>
</blockquote>
<br>

<h3 id="singleton-bean--prototype-bean">Singleton Bean + Prototype Bean</h3>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/2260ce71-2529-48b4-9f27-5b12e942a5e8/image.png" alt=""></p>
<ul>
<li>Client Bean : 싱글톤이기 때문에, 스프링 컨테이너 생성 시점에 생성된 후 의존관계 주입도 발생<ul>
<li>Prototype Bean을 스프링 컨테이너에 요청</li>
<li>그 후 clientBean이 prototypeBean을 내부 필드에 보관</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/8fc673de-ee5d-4601-9b39-413ff0878349/image.png" alt=""></p>
<ul>
<li>clientBean은 요청이 들어올 때마다 같은 빈을 반환함</li>
<li>clientBean.logic()이 호출되면, clientBean은 prototypeBean의 addCount() 호출 → prototype의 count 1 증가</li>
</ul>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/4c0f7997-787e-4c04-97dc-9ae1c9889cab/image.png" alt=""></p>
<p>이 경우, prototypeBean의 count는 2로 증가하게 된다 → 프로토타입 빈의 특성과 맞지 않는 결과!</p>
<br>

<h2 id="provider-사용하기">Provider 사용하기</h2>
<h3 id="방법-0-싱글톤-빈이-프로토타입을-사용할-때마다-스프링-컨테이너에-새로-요청">방법 0. 싱글톤 빈이 프로토타입을 사용할 때마다 스프링 컨테이너에 새로 요청</h3>
<ul>
<li><p><strong>Dependency Lookup(DL)</strong> : 의존관계 조회(탐색)</p>
<ul>
<li>외부에서 의존관계를 주입받는 것이 아니라, 직접 필요한 의존관계를 찾는 것</li>
</ul>
</li>
<li><p>단, 이렇게 스프링 ApplicationContext 전체를 주입받는 것은 권장되지 않는다!</p>
<ul>
<li>스프링 컨테이너에 종속적인 코드가 됨</li>
<li>단위 테스트가 어려워짐</li>
</ul>
</li>
<li><p>지정한 프로토타입 빈을 컨테이너에서 대신 찾아주는, DL 정도의 기능만 제공하는 무언가만 있으면 됨</p>
</li>
</ul>
<br>

<h3 id="방법-1-objectprovider">방법 1. ObjectProvider</h3>
<blockquote>
<p>원래는 ObjectFactory가 있었는데, 여기에 편의 기능을 추가해서 ObjectProvider가 만들어짐!</p>
</blockquote>
<ul>
<li>지정한 Bean을 컨테이너에서 대신 찾아주는 DL 서비스를 함</li>
</ul>
<pre><code class="language-java">@Autowired
private ObjectProvider&lt;PrototypeBean&gt; prototypeBeanProvider;

public int logic() {
     PrototypeBean prototypeBean = prototypeBeanProvider.getObject();
     prototypeBean.addCount();
     int count = prototypeBean.getCount();
     return count;
}</code></pre>
<ul>
<li><code>getObject()</code> 메서드를 통해, 항상 새로운 프로토타입 빈을 생성함<ul>
<li>내부에서는 스프링 컨테이너를 통해 해당 빈을 찾아 반환함</li>
</ul>
</li>
</ul>
<h4 id="특징">특징</h4>
<ul>
<li>ObjectFactory<ul>
<li>기능이 단순함</li>
<li>별도의 라이브러리 필요 없음</li>
<li>스프링에 의존함</li>
</ul>
</li>
<li>ObjectProvider<ul>
<li>ObjectFactory 상속</li>
<li>옵션, 스트림 처리 등 편의 기능이 많음</li>
<li>별도의 라이브러리 필요 없음</li>
<li>스프링에 의존</li>
</ul>
</li>
</ul>
<br>

<h3 id="방법-2-jsr-330-provider">방법 2. JSR-330 Provider</h3>
<blockquote>
<p>javax.inject.Provider
  (jakarta.inject.Provider - Spring Boot 3.0 이상)</p>
</blockquote>
<ul>
<li>JSR-330 자바 표준을 사용</li>
</ul>
<pre><code class="language-java">@Autowired
private Provider&lt;PrototypeBean&gt; provider;

public int logic() {
     PrototypeBean prototypeBean = provider.get();
     prototypeBean.addCount();
     int count = prototypeBean.getCount();
     return count;
}</code></pre>
<h4 id="특징-1">특징</h4>
<ul>
<li><code>get()</code> 메서드 하나 - 기능이 매우 단순</li>
<li>별도의 라이브러리가 필요함</li>
<li>Java 표준임 → 스프링이 아닌 다른 컨테이너에서도 사용할 수 있음</li>
</ul>
<br>

<blockquote>
<p>📌 <strong>하나 더!</strong></p>
<ul>
<li>스프링이 제공하는 메서드 중 @Lookup 애노테이션도 있음<ul>
<li>단, 위의 방법들로도 충분함</li>
<li>고려해야 할 내용도 많음</li>
</ul>
</li>
</ul>
</blockquote>
<blockquote>
<p>👉🏻 <strong>참고 사항</strong></p>
<ul>
<li>다만, 실무에서 웹 애플리케이션을 개발해보면 싱글톤 빈만 사용해도 대부분의 문제를 해결할 수 있음 → 프로토타입 빈을 직접적으로 사용하는 일은 매우 드묾</li>
</ul>
</blockquote>
<blockquote>
<p>💡 <strong>Tip!</strong></p>
<ul>
<li>ObjectProvider, JSR330 Provider 등 : 프로토타입 뿐만 아니라 DL이 필요한 경우는 언제든지 사용 가능<ul>
<li>ex) 순환 참조 방지용</li>
</ul>
</li>
</ul>
</blockquote>
<br>

<h3 id="java-표준-vs-spring-제공-기능">Java 표준 vs Spring 제공 기능?</h3>
<p>위의 방법 2와 3을 보면, 둘 중 어느 것을 사용할지 고민이 될 수 있다. </p>
<ul>
<li><p>만약 (거의 없지만) 코드를 스프링이 아닌 다른 컨테이너에서도 사용할 수 있어야 한다면, 자바 표준을 써야 한다.</p>
</li>
<li><p>스프링은 이제 사실상 기술의 표준에 가까움</p>
</li>
<li><p>다만, 대부분의 경우 위와 같은 일이 엇고, 스프링이 대부분 더 다양하고 편리한 기능을 제공해주기 때문에 특별한 일이 없다면 스프링이 제공하는 기능을 사용해도 좋다.</p>
</li>
</ul>
<br>

<h1 id="web-scope">Web Scope</h1>
<ul>
<li>웹 환경에서만 동작한다.</li>
<li><strong>프로토타입과 다르게 스프링이 해당 스코프의 종료 시점까지 관리</strong>한다.</li>
<li>따라서 종료 메서드가 호출된다.</li>
</ul>
<h3 id="종류-1-request">종류 1. request</h3>
<ul>
<li><strong>HTTP 요청 하나가 들어오고 나갈 때까지 유지되는 Scope</strong></li>
<li>각각의 HTTP 요청마다 별도의 빈 인스턴스가 생성되고, 관리된다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/f77634ed-f7e8-4c76-93eb-2ea9cd79cd3c/image.png" alt=""></p>
<h3 id="종류-2-session">종류 2. session</h3>
<ul>
<li>HTTP Session과 동일한 생명주기를 가짐</li>
</ul>
<h3 id="종류-3-application">종류 3. application</h3>
<ul>
<li>ServletContext와 동일한 생명주기를 가짐</li>
</ul>
<h3 id="종류-4-websocket">종류 4. websocket</h3>
<ul>
<li>웹 소켓과 동일한 생명주기를 가짐</li>
</ul>
<blockquote>
<p>📌 <strong>실습 시 참고!</strong>
spring-boot-starter-web 라이브러리를 추가하면 스프링 부트는 내장 톰켓 서버를 활용해서 웹
서버와 스프링을 함께 실행시킨다.</p>
</blockquote>
<blockquote>
<p>📌 <strong>실습 시 참고! 2</strong></p>
<ul>
<li>스프링 부트는 웹 라이브러리가 없으면 우리가 지금까지 학습한
<code>AnnotationConfigApplicationContext</code>을 기반으로 애플리케이션을 구동한다.</li>
<li>웹 라이브러리가 추가되면 웹과 관련된 추가 설정과 환경들이 필요하므로 <code>AnnotationConfigServletWebServerApplicationContext</code>를 기반으로 애플리케이션을 구동하면 된다.</li>
</ul>
</blockquote>
<br>

<h2 id="request-scope">request Scope</h2>
<ul>
<li>동시에 여러 HTTP 요청이 오면 → 정확히 어떤 요청이 남긴 로그인지 구분하기 어려워짐</li>
<li>이럴 때 request 스코프를 사용하면 좋음!</li>
<li><code>@Scope(value = &quot;request&quot;)</code><ul>
<li>HTTP 요청 당 하나씩 생성됨</li>
<li>HTTP 요청이 끝나는 시점에 소멸됨</li>
<li>다른 HTTP 요청 때문에 섞이는 걱정 안해도 됨</li>
</ul>
</li>
</ul>
<blockquote>
<p>📌 <strong>참고!</strong></p>
<ul>
<li>requestURL 로그를 남기는 부분 등은 컨트롤러보다는 스프링 인터셉터나 서블릿 필터 등을 활용하는 것이 좋음</li>
</ul>
</blockquote>
<br>

<h2 id="provider">Provider</h2>
<ul>
<li><p>Controller</p>
<pre><code class="language-java">@Controller
 @RequiredArgsConstructor
 public class LogDemoController {
     private final LogDemoService logDemoService;
     private final ObjectProvider&lt;MyLogger&gt; myLoggerProvider;

    @RequestMapping(&quot;log-demo&quot;)
    @ResponseBody
     public String logDemo(HttpServletRequest request) {
        String requestURL = request.getRequestURL().toString();

          MyLogger myLogger = myLoggerProvider.getObject();
        myLogger.setRequestURL(requestURL);
        myLogger.log(&quot;controller test&quot;);

          logDemoService.logic(&quot;testId&quot;);

          return &quot;OK&quot;;
   }
}</code></pre>
</li>
<li><p>Service</p>
<pre><code class="language-java">@Service
 @RequiredArgsConstructor
 public class LogDemoService {
     private final ObjectProvider&lt;MyLogger&gt; myLoggerProvider;
     public void logic(String id) {
         MyLogger myLogger = myLoggerProvider.getObject();
        myLogger.log(&quot;service id = &quot; + id);
    }
}</code></pre>
</li>
<li><p><code>ObjectProvider</code>을 사용하면?</p>
<ul>
<li><p><code>ObjectProvider.getObject()</code>를 호출하기 전까지 request scope 빈의 생성 지연 가능</p>
</li>
<li><p>ObjectProvider.getObject()` 호출 시점에는 HTTP 요청이 진행 중이므로 request scope 빈의 생성이 정상 처리됨</p>
</li>
<li><p><code>ObjectProvider.getObject()</code>를 <code>LogDemoController</code>, <code>LogDemoService</code>에서 각각 한번씩 따로 호출해도, <strong>같은 HTTP 요청이면 같은 스프링 빈이 반환됨</strong></p>
</li>
</ul>
</li>
</ul>
<br>

<h2 id="proxy">Proxy</h2>
<h4 id="활용-방법">활용 방법</h4>
<pre><code class="language-java">@Component
@Scope(value = &quot;request&quot;, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MyLogger {
}</code></pre>
<ul>
<li>MyLogger의 가짜 프록시 클래스를 만들어두고, HTTP request와 상관 없이 가짜 프록시 클래스를 다른 빈에 주입해둘 수 있다. <ul>
<li>적용 대상이 클래스 : TARGET_CLASS</li>
<li>적용 대상이 인터페이스 : INTERFACES</li>
</ul>
</li>
</ul>
<h4 id="주입된-mylogger">주입된 myLogger</h4>
<pre><code class="language-java">  System.out.println(&quot;myLogger = &quot; + myLogger.getClass());</code></pre>
<pre><code>  myLogger = class hello.core.common.MyLogger$$EnhancerBySpringCGLIB$$b68b726d</code></pre><ul>
<li>CGLIB라는 바이트코드를 조작하는 라이브러리로 내 클래스를 상속 받은 가짜 프록시 객체를 만들어서 주입한다.</li>
<li>스프링 컨테이너는 CGLIB를 사용해서, <code>MyLogger</code>를 상속받은 가짜 프록시 객체를 생성한다.</li>
<li>스프링 컨테이너에 &quot;<code>myLogger</code>&quot;라는 이름으로 진짜 대신에 이 가짜 프록시 객체를 등록한다</li>
<li><strong>그래서 의존관계 주입도 이 가짜 프록시 객체가 주입된다!</strong></li>
</ul>
<h3 id="그럼-어떻게-동작하는가">그럼 어떻게 동작하는가?</h3>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/9a4ea0f5-6d4b-48a6-9745-50ec4bb9a727/image.png" alt=""></p>
<ul>
<li><p>가짜 프록시 객체</p>
<ul>
<li>요청이 오면 그때 내부에서 진짜 빈을 요청하는 위임 로직이 들어있음</li>
<li>내부에 진짜 <code>myLogger</code>를 찾는 방법을 알고 있음</li>
<li>클라이언트가 <code>myLogger.logic()</code>을 호출하면 사실은 가짜 프록시 객체의 메서드를 호출한 것 → 가짜 프록시 객체가 request scope를 가진 진짜 <code>myLogger.logic()</code>를 호출한다.</li>
<li>원본 클래스를 상속 받아서 만들어짐 → 이 객체를 사용하는 클라이언트 입장에서는 사실 원본인지 아닌지도 모르게, 동일하게 사용할 수 있음(다형성)</li>
</ul>
<blockquote>
<p><strong>정리!</strong>
가짜 프록시 객체는 실제 request scope와는 관계가 없다. 그냥 가짜이고, 내부에 단순한 위임 로직만
있고, 싱글톤 처럼 동작한다.</p>
</blockquote>
</li>
</ul>
<h3 id="장점">장점</h3>
<ul>
<li>프록시 객체 덕분에 클라이언트는 마치 싱글톤 빈을 사용하듯이 편리하게 request scope를 사용할 수 있다.</li>
<li>사실 Provider를 사용하든, 프록시를 사용하든 <strong>핵심 아이디어</strong>는 <strong>진짜 객체 조회를 꼭 필요한 시점까지 지연처리 한다는 점</strong>이다.</li>
<li>Proxy : 단지 애노테이션 설정 변경만으로 원본 객체를 프록시 객체로 대체할 수 있다. (이것이 바로 다형성과 DI 컨테이너가 가진 큰 강점이다.)</li>
<li><strong>꼭 웹 스코프가 아니어도 프록시는 사용할 수 있다</strong> (나중에 나오는 AOP 원리가 딱 이것임)</li>
</ul>
<h3 id="주의점">주의점</h3>
<ul>
<li>마치 싱글톤을 사용하는 것 같지만 다르게 동작하기 때문에 결국 <strong>주의해서 사용</strong>해야 한다.</li>
<li>이런 <strong>특별한 scope는 꼭 필요한 곳에만 최소화해서 사용</strong>하자 (<strong>무분별하게 사용하면 유지보수하기 어려워진다!</strong>)</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] Bean Lifecycle Callback]]></title>
            <link>https://velog.io/@sw_smj/Spring-Bean-Lifecycle-Callback</link>
            <guid>https://velog.io/@sw_smj/Spring-Bean-Lifecycle-Callback</guid>
            <pubDate>Tue, 18 Apr 2023 11:55:41 GMT</pubDate>
            <description><![CDATA[<h1 id="bean-lifecycle">Bean Lifecycle</h1>
<p><strong>스프링 컨테이너 생성 → 스프링 빈 생성 → 의존관계 주입 → 초기화 콜백 → 사용 → 소멸 전 콜백 → 스프링 종료</strong></p>
<ul>
<li>스프링 빈 : 객체를 생성하고, 의존 관계 주입 후에야 필요한 데이터를 사용할 준비가 제대로 완료됨<ul>
<li>준비 완료 시점을 알려주기 위한 콜백 메서드 필요함!</li>
</ul>
</li>
</ul>
<br>

<h2 id="bean-lifecycle-callback">Bean Lifecycle Callback</h2>
<p>스프링은 다양한 콜백 기능을 제공함</p>
<ul>
<li><p>초기화 콜백: 빈이 생성되고, 빈의 의존관계 주입이 완료된 후 호출(초기화 시점을 알려줌)</p>
</li>
<li><p>소멸전 콜백: 빈이 소멸되기 직전에 호출 (스프링 컨테이너가 종료되기 직전)</p>
</li>
</ul>
<blockquote>
<p><strong>💡 객체의 생성과 초기화를 분리해야만 하는가?</strong></p>
<ul>
<li>객체의 생성 : 생성자가 필수 정보(파라미터)를 받아서 메모리를 할당해서 객체를 생성</li>
<li>초기화 : 이 값들을 활요해서 외부 커넥션과 연결하는 등 무거운 동작 수행
(단, 초기화 작업이 내부 값들만 약간 변경하는 정도로 단순한 경우, 생성자에서 한 번에 다 처리하는 게 더 나을 수 있음)</li>
</ul>
</blockquote>
<h3 id="방법">방법</h3>
<ol>
<li>인터페이스(InitializingBean, DisposableBean)</li>
<li>설정 정보에 초기화 메서드, 종료 메서드 지정</li>
<li>@PostConstruct, @PreDestroy 애너테이션</li>
</ol>
<br>

<h3 id="방법-1-initalizingbean-disposablebean">방법 1. InitalizingBean, DisposableBean</h3>
<ul>
<li><p><code>InitializingBean</code> - <code>afterPropertiesSet()</code> 메서드</p>
</li>
<li><p><code>DisposableBean</code> - <code>destroy()</code> 메서드</p>
</li>
</ul>
<h4 id="단점">단점</h4>
<ul>
<li>스프링 전용 인터페이스. 즉, 해당 코드가 스프링 전용 인터페이스에 의존함</li>
<li>초기화, 소멸 메서드의 이름을 변경할 수 없음</li>
<li>코드를 고칠 수 없는 외부 라이브러리에 적용할 수 없음</li>
</ul>
<blockquote>
<ul>
<li>초창기 방법!</li>
<li>다른 방법들이 더 낫기 때문에, 거의 사용하지 않음!</li>
</ul>
</blockquote>
<br>

<h3 id="방법-2-빈-등록-초기화-소멸-메서드-지정">방법 2. 빈 등록 초기화, 소멸 메서드 지정</h3>
<ul>
<li>빈 등록할 때, 초기화/소멸 메서드 지정</li>
</ul>
<pre><code class="language-java">@Bean(initMethod = &quot;init&quot;, destroyMethod = &quot;close&quot;)</code></pre>
<h4 id="특징">특징</h4>
<ul>
<li>메서드 이름을 자유롭게 지정할 수 있음</li>
<li>스프링 빈이 스프링 코드에 의존하지 않음</li>
<li>코드가 아니라 설정 정보를 사용함 → 코드를 고칠 수 없는 외부 라이브러리에도 초기화/종료 메서드 지정 가능</li>
</ul>
<h4 id="-독특한-기능---종료-메서드-추론">+) 독특한 기능 - 종료 메서드 추론</h4>
<ul>
<li><code>@Bean</code>의 <code>destroyMethod</code> 속성 - 기본값이 (inferred)(추론)으로 되어 있음</li>
<li><code>close</code>, <code>shutdown</code>이라는 이름의 메서드를 종료 메서드로 추론해서 자동으로 호출해줌</li>
<li>추론 기능을 사용하기 싫으면 → <code>destroyMethod=&quot;&quot;</code> 처럼 공백 지정하면 됨 (단, 설정을 아주 꼬이게 할 수 있으므로, 추천하지 않음)</li>
</ul>
<br>

<h3 id="방법-3-애노테이션-postconstruct-predestroy">방법 3. 애노테이션 @PostConstruct, @PreDestroy</h3>
<h4 id="특징-1">특징</h4>
<ul>
<li>가장 편리하고 간단하게 초기화/종료 메서드 실행 가능</li>
<li><strong>최신 스프링에서 가장 권장하는 방법</strong></li>
<li>애너테이션 하나만 붙이면 됨</li>
<li><code>javax.annotation.PostConstruct</code> 패키지 : 스프링에 종속적인 기술이 아닌 자바 표준 → Spring이 아닌 다른 컨테이너에서도 동작함</li>
<li>Component Scan과 잘 어울림</li>
<li>유일한 단점 : 외부 라이브러리에는 적용하지 못함(까볼 수 없으니까) → 외부 라이브러리 이용 시에는 방법2(@Bean) 기능 활용하기</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] 의존관계 자동 주입]]></title>
            <link>https://velog.io/@sw_smj/Spring-%EC%9D%98%EC%A1%B4%EA%B4%80%EA%B3%84-%EC%9E%90%EB%8F%99-%EC%A3%BC%EC%9E%85</link>
            <guid>https://velog.io/@sw_smj/Spring-%EC%9D%98%EC%A1%B4%EA%B4%80%EA%B3%84-%EC%9E%90%EB%8F%99-%EC%A3%BC%EC%9E%85</guid>
            <pubDate>Sun, 16 Apr 2023 16:19:34 GMT</pubDate>
            <description><![CDATA[<h2 id="의존관계-주입-방법">의존관계 주입 방법</h2>
<ol>
<li>생성자 주입</li>
<li>수정자 주입(setter 주입)</li>
<li>필드 주입</li>
<li>일반 메서드 주입</li>
</ol>
<br>

<h2 id="1-constructor-injection-생성자-주입">1. Constructor Injection (생성자 주입)</h2>
<h3 id="방법">방법</h3>
<pre><code class="language-java">@Component
public class OrderServiceImpl implements OrderService {
    private final MemberRepository memberRepository;
    private final DiscountPolicy discountPolicy;

    @Autowired
    public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy 
discountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy;
    }
}</code></pre>
<h3 id="특징">특징</h3>
<ul>
<li>생성자 호출시점에 딱 1번만 호출되는 것이 보장된다.</li>
<li>불변, 필수 의존관계에 사용</li>
<li><strong>요즘 가장 많이 쓰임</strong></li>
</ul>
<blockquote>
<p>💡 <strong>중요!</strong>
해당 클래스에 <strong>생성자가 딱 1개만 있으면</strong> <code>@Autowired</code>를 생략해도 자동 주입 된다. 
(물론 스프링 빈에만 해당한다.)</p>
</blockquote>
<h3 id="⭐-생성자-주입을-선택해라">⭐ 생성자 주입을 선택해라!</h3>
<p>최근에는 스프링 뿐만 아니라 다른 DI 프레임워크들도 대부분 생성자 주입을 권장한다. </p>
<p><strong>이유 1 : 불변성</strong></p>
<ul>
<li><p>대부분의 의존관계 주입은 한번 일어나면 애플리케이션 종료시점까지 의존관계를 변경할 일이 없다. 오히려 대부분의 의존관계는 애플리케이션 종료 전까지 변하면 안된다.(불변해야 한다.)</p>
</li>
<li><p>수정자 주입 : setXxx 메서드를 public으로 열어두어야 한다.</p>
</li>
<li><p>누군가 실수로 변경할 수 도 있고, 변경하면 안되는 메서드를 열어두는 것은 좋은 설계 방법이 아니다.</p>
<p>👉🏻 <strong>생성자 주입은 객체를 생성할 때 딱 1번만 호출되므로 이후에 호출되는 일이 없다. 따라서 불변하게 설계할 수 있다.</strong></p>
</li>
</ul>
<p><strong>이유 2 : 누락 방지</strong></p>
<ul>
<li><code>@Autowired</code> : 프레임워크 없이 순수한 자바 코드로만 단위 테스트를 수행하게 되면 의존관계가 없어도 오류가 발생하지 않는다.</li>
<li>수정자 주입 : 의존관계를 실수로 누락하면, 실행은 되는데 NPE가 발생한다. </li>
<li>생성자 주입 : 주입 데이터를 누락 했을 때 컴파일 오류가 발생한다.</li>
<li>그리고 IDE에서 바로 어떤 값을 필수로 주입해야 하는지 알 수 있다.</li>
</ul>
<p><strong>이유 3 : final 키워드</strong></p>
<ul>
<li>생성자 주입을 사용하면 필드에 final 키워드를 사용할 수 있다. 그래서 생성자에서 혹시라도 값이 설정되지 않는 오류를 컴파일 시점에 막아준다.</li>
<li>발생하는 오류 : <code>java: variable discountPolicy might not have been initialized</code></li>
</ul>
<blockquote>
<p>💡 <strong>참고</strong></p>
<ul>
<li>수정자 주입을 포함한 나머지 주입 방식은 모두 생성자 이후에 호출되므로, 필드에 final 키워드를 사용할 수 없다. </li>
<li>오직 생성자 주입 방식만 final 키워드를 사용할 수 있다.</li>
</ul>
</blockquote>
<br>

<h2 id="2-setter-injection-수정자-주입">2. Setter Injection (수정자 주입)</h2>
<h3 id="방법-1">방법</h3>
<pre><code class="language-java">@Component
public class OrderServiceImpl implements OrderService {
    private MemberRepository memberRepository;
    private DiscountPolicy discountPolicy;

    @Autowired    // 빼면 당연히 안 들어옴!
    public void setMemberRepository(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    @Autowired
    public void setDiscountPolicy(DiscountPolicy discountPolicy) {
        this.discountPolicy = discountPolicy;
    }
}</code></pre>
<blockquote>
<p><strong>참고</strong></p>
<ul>
<li>@Autowired 의 기본 동작은 주입할 대상이 없으면 오류가 발생한다.</li>
<li>주입할 대상이 Spring Container에 없어도 동작하게 하려면 @Autowired(required = false) 로 지정하면 된다.</li>
</ul>
</blockquote>
<h3 id="특징-1">특징</h3>
<ul>
<li>선택, 변경 가능성이 있는 의존관계에 사용 
(중간에 필드 의존 관계를 바꾸고 싶을 때, 외부에서 냅다 setter 사용해서 바꿀 수 있음)</li>
<li>자바빈 프로퍼티 규약의 수정자 메서드 방식을 사용하는 방법이다.</li>
<li>생성자 주입과 달리, 생성과 동시에 의존관계 주입이 되는 원리는 아님</li>
<li>종종 쓰임</li>
</ul>
<blockquote>
<p>💡 <strong>참고: 자바빈 프로퍼티란?</strong></p>
<ul>
<li>자바에서는 과거부터 필드의 값을 직접 변경하지 않고, setXxx, getXxx 라는 메서드를 통해서 값을 읽거나 수정하는 규칙을 만들었는데, 그것이 자바빈 프로퍼티 규약이다.</li>
</ul>
</blockquote>
<br>

<h2 id="3-field-injection-필드-주입">3. Field Injection (필드 주입)</h2>
<h3 id="방법-2">방법</h3>
<pre><code class="language-java">@Component
public class OrderServiceImpl implements OrderService {

    @Autowired
     private MemberRepository memberRepository;
     @Autowired
     private DiscountPolicy discountPolicy;
}</code></pre>
<blockquote>
<p>💡 <strong>참고</strong></p>
<ul>
<li>순수한 자바 테스트 코드에는 당연히 <code>@Autowired</code>가 동작하지 않는다. </li>
<li><code>@SpringBootTest</code>처럼 스프링 컨테이너를 테스트에 통합한 경우에만 가능하다</li>
</ul>
</blockquote>
<h3 id="특징-2">특징</h3>
<ul>
<li><strong>안티 패턴!</strong> - 코드가 간결해서 많은 개발자들을 유혹하지만 외부에서 변경이 불가능해서 테스트 하기 힘들다는 치명적인 단점이 있다.</li>
<li>DI 프레임워크가 없으면 아무것도 할 수 없다. <strong>사용하지 말자!</strong></li>
<li>사용해도 좋을 특별한 용도들<ul>
<li>애플리케이션의 실제 코드와 관계 없는 테스트 코드</li>
<li>스프링 설정을 목적으로 하는 <code>@Configuration</code> 같은 곳</li>
</ul>
</li>
</ul>
<blockquote>
<p><strong>참고</strong>
위의 방법이 아닌, 그냥 new로 바로 직접 자동 주입하는 방식도 역시 추천되지 않는다.</p>
<ul>
<li>자동 등록 : 다음 코드와 같이 @Bean에서 파라미터에 의존관계는 자동 주입된다.<pre><code class="language-java">@Bean
OrderService orderService(MemberRepository memberRepoisitory, DiscountPolicy 
discountPolicy) {
   new OrderServiceImpl(memberRepository, discountPolicy)
}</code></pre>
</li>
<li>수동 등록 : 자동 등록된 빈의 의존관계가 필요할 때 문제를 해결할 수 있다.</li>
</ul>
</blockquote>
<br>

<h2 id="4-일반-메서드-주입">4. 일반 메서드 주입</h2>
<h3 id="방법-3">방법</h3>
<pre><code class="language-java">@Component
public class OrderServiceImpl implements OrderService {
     private MemberRepository memberRepository;
     private DiscountPolicy discountPolicy;

    @Autowired
    public void init(MemberRepository memberRepository, DiscountPolicy 
discountPolicy) {
         this.memberRepository = memberRepository;
         this.discountPolicy = discountPolicy;
     }
}</code></pre>
<h3 id="특징-3">특징</h3>
<ul>
<li>한번에 여러 필드를 주입 받을 수 있다.</li>
<li>일반적으로 잘 사용하지 않는다</li>
</ul>
<blockquote>
<p>💡 <strong>참고</strong></p>
<ul>
<li>의존관계 자동 주입은 스프링 컨테이너가 관리하는 스프링 빈이어야 동작한다.</li>
<li>스프링 빈이 아닌 클래스에서 @Autowired 코드를 적용해도 아무 기능도 동작하지 않는다!</li>
</ul>
</blockquote>
<blockquote>
<p>📌 <strong>정리 - 생성자 주입 방식을 선택하자!</strong></p>
<ul>
<li>프레임워크에 의존하지 않고, 순수한 자바 언어의 특징을 잘 살리는 방법이다.</li>
<li>항상 생성자 주입을 선택해라! 그리고 가끔 옵션이 필요하면 수정자 주입을 선택해라. (생성자 주입과 수정자 주입을 동시에 사용할 수 있다.)</li>
<li>필드 주입은 사용하지 않는게 좋다</li>
<li><code>Lombok</code>의 <code>@RequiredArgsConstructor</code>를 보통 사용한다.</li>
</ul>
</blockquote>
<br>

<h2 id="options">Options</h2>
<h3 id="자동-주입을-옵션으로-처리하기">자동 주입을 옵션으로 처리하기</h3>
<blockquote>
<ul>
<li>주입할 스프링 빈이 없어도 동작해야 할 때가 있다.</li>
<li>그런데 <code>@Autowired</code>만 사용하면 <code>required</code> 옵션의 기본값이 <code>true</code>로 되어 있어서 자동 주입 대상이 없으면 오류가 발생한다.</li>
</ul>
</blockquote>
<h3 id="방법-3가지">방법 3가지</h3>
<h4 id="방법-1-autowiredrequiredfalse">방법 1. <code>@Autowired(required=false)</code></h4>
<p>: 자동 주입할 대상이 없으면 수정자 메서드 자체가 호출 안됨</p>
<pre><code class="language-java">  //호출 안됨
  @Autowired(required = false)
  public void setNoBean1(Member member) {
      System.out.println(&quot;setNoBean1 = &quot; + member);
  }</code></pre>
<h4 id="방법-2--orgspringframeworklangnullable">방법 2 : <code>org.springframework.lang.@Nullable</code></h4>
<p>: 자동 주입할 대상이 없으면 null이 입력된다.</p>
<pre><code class="language-java">  //null 호출
  @Autowired
  public void setNoBean2(@Nullable Member member) {
     System.out.println(&quot;setNoBean2 = &quot; + member);
  }</code></pre>
<h4 id="방법-3--optional">방법 3 : <code>Optional&lt;&gt;</code></h4>
<p>: 자동 주입할 대상이 없으면 <code>Optional.empty</code>가 입력된다.</p>
<pre><code class="language-java">  //Optional.empty 호출
  @Autowired(required = false)
  public void setNoBean3(Optional&lt;Member&gt; member) {
      System.out.println(&quot;setNoBean3 = &quot; + member);
  }</code></pre>
<h4 id="출력-결과">출력 결과</h4>
<pre><code class="language-java">setNoBean2 = null
setNoBean3 = Optional.empty</code></pre>
<ul>
<li>Member는 스프링 빈이 아니다.</li>
<li>setNoBean1() 은 @Autowired(required=false) 이므로 호출 자체가 안된다.</li>
</ul>
<blockquote>
<p><strong>참고</strong></p>
<ul>
<li>@Nullable, Optional은 스프링 전반에 걸쳐서 지원된다. </li>
<li>예를 들어서 생성자 자동 주입에서 특정 필드에만 사용해도 된다.</li>
</ul>
</blockquote>
<br>

<h2 id="lombok">Lombok</h2>
<h4 id="requiredargsconstructor">@RequiredArgsConstructor</h4>
<ul>
<li>final이 붙은 필드를 모아서 생성자를 자동으로 만들어준다.</li>
<li>롬복이 자바의 애노테이션 프로세서라는 기능을 이용해서 컴파일 시점에 생성자 코드를 자동으로 생성해준다.</li>
</ul>
<br>

<h2 id="autowired와-중복-타입의-빈-충돌">@Autowired와 중복 타입의 빈 충돌</h2>
<ul>
<li><strong><code>@Autowired</code></strong> : Type으로 조회함
타입으로 조회하면 선택된 빈이 2개 이상일 때 문제가 발생한다.<ul>
<li>발생하는 오류 : <code>NoUniqueBeanDefinitionException</code></li>
</ul>
</li>
</ul>
<h3 id="해결-방법">해결 방법</h3>
<blockquote>
<ul>
<li>하위 타입으로 지정 : DIP를 위배하고 유연성이 떨어진다. </li>
<li>타입이 똑같은 빈 여러 개 or 자식 여러 개 : 해결이 안된다.</li>
<li>빈 수동 등록도 방법이지만, 의존관계 자동 주입에서도 해결 가능</li>
</ul>
</blockquote>
<br>

<h3 id="방법-1--autowired-매칭-방법">방법 1 : @Autowired 매칭 방법</h3>
<ol>
<li>타입 매칭</li>
<li>타입 매칭의 결과가 2개 이상일 때 필드 명, 파라미터 명으로 빈 이름 매칭</li>
</ol>
<br>

<h3 id="방법-2--qualifier">방법 2 : @Qualifier</h3>
<p>: 추가 구분자를 붙여주는 방법</p>
<ul>
<li>주입시 추가적인 방법을 제공하는 것이지 빈 이름을
변경하는 것은 아니다</li>
</ul>
<p>즉,</p>
<ol>
<li><code>@Qualifier</code>끼리 매칭</li>
<li>빈 이름 매칭</li>
<li><code>NoSuchBeanDefinitionException</code> 예외 발생</li>
</ol>
<h4 id="방법-4">방법</h4>
<pre><code class="language-java">@Component
@Qualifier(&quot;mainDiscountPolicy&quot;)
public class RateDiscountPolicy implements DiscountPolicy {}</code></pre>
<pre><code class="language-java">@Component
@Qualifier(&quot;fixDiscountPolicy&quot;)
public class FixDiscountPolicy implements DiscountPolicy {}</code></pre>
<ul>
<li>생성자 자동 주입<pre><code class="language-java">@Autowired
public OrderServiceImpl(MemberRepository memberRepository,
                        @Qualifier(&quot;mainDiscountPolicy&quot;) DiscountPolicy 
discountPolicy) {
    this.memberRepository = memberRepository;
    this.discountPolicy = discountPolicy;
}</code></pre>
</li>
<li>수정자 자동 주입<pre><code class="language-java">@Autowired
public DiscountPolicy setDiscountPolicy(@Qualifier(&quot;mainDiscountPolicy&quot;)
DiscountPolicy discountPolicy) {
    this.discountPolicy = discountPolicy;
}</code></pre>
<blockquote>
<p><strong>참고</strong></p>
<ul>
<li><code>@Qualifier</code> 로 주입할 때 <code>@Qualifier(&quot;mainDiscountPolicy&quot;)</code>를 못찾으면 → <code>mainDiscountPolicy</code>라는 이름의 스프링 빈을 추가로 찾는다.</li>
<li>하지만 경험상 <code>@Qualifier</code>는 같은 <code>@Qualifier</code>를 찾는 용도로만 사용하는게 명확하고 좋다.</li>
</ul>
</blockquote>
</li>
</ul>
<br>

<h3 id="방법-3--primary">방법 3 : @Primary</h3>
<p><code>@Primary</code>는 우선순위를 정하는 방법이다. <code>@Autowired</code> 시에 여러 빈이 매칭되면 <code>@Primary</code>가 우선권을 가진다.</p>
<pre><code class="language-java">@Component
@Primary
public class RateDiscountPolicy implements DiscountPolicy {}

@Component
public class FixDiscountPolicy implements DiscountPolicy {}</code></pre>
<br>

<h3 id="qualifier-vs-primary">@Qualifier vs @Primary</h3>
<ul>
<li>Main-DB Connection 획득 스프링 빈 : <code>@Primary</code>를 적용해서 조회하는 곳에서 <code>@Qualifier</code> 지정 없이 편리하게 조회</li>
<li>Sub-DB Connection 획득 스프링 빈 : <code>@Qualifier</code>를 지정해서 명시적으로 획득 하는 방식으로 사용</li>
</ul>
<p>→ 코드를 깔끔하게 유지할 수 있다. </p>
<h4 id="둘-중-적용되는-우선순위는">둘 중 적용되는 우선순위는?</h4>
<ul>
<li>스프링은 자동보다는 수동이, 넒은 범위의 선택권 보다는 좁은 범위의 선택권이 우선 순위가 높다. 
→ 여기서도 @Qualifier 가 우선권이 높다</li>
</ul>
<br>

<h2 id="annotation-직접-만들기">Annotation 직접 만들기</h2>
<pre><code class="language-java">package hello.core.annotataion;

import org.springframework.beans.factory.annotation.Qualifier;
import java.lang.annotation.*;

@Target({ElementType.FIELD, ElementType.METHOD,ElementType.PARAMETER,ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Qualifier(&quot;mainDiscountPolicy&quot;)
public @interface MainDiscountPolicy {
}</code></pre>
<ul>
<li>애노테이션에는 상속이라는 개념이 없다. 이렇게 여러 애노테이션을 모아서 사용하는 기능은 스프링이 지원해주는 기능이다. - <code>@Qulifier</code> 뿐만 아니라 다른 애노테이션들도 함께 조합해서 사용할 수 있다. <ul>
<li>단적으로 <code>@Autowired</code>도 재정의 할 수 있다. 물론 스프링이 제공하는 기능을 뚜렷한 목적 없이 무분별하게 재정의 하는 것은 유지보수에 더 혼란만 가중할 수 있다.</li>
</ul>
</li>
</ul>
<br>

<h2 id="spring과-전략-패턴">Spring과 전략 패턴</h2>
<ul>
<li>의도적으로 정말 해당 타입의 스프링 빈이 다 필요한 경우도 있다. 예를 들어서 할인 서비스를 제공하는데, 클라이언트가 할인의 종류(rate, fix)를 선택할 수 있다고 가정해보자. </li>
<li>스프링을 사용하면, 정말 쉽게 전략 패턴을 사용할 수 있다.</li>
</ul>
<pre><code class="language-java">package hello.core.autowired;

import hello.core.AutoAppConfig;
import hello.core.discount.DiscountPolicy;
import hello.core.member.Grade;
import hello.core.member.Member;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.List;
import java.util.Map;

import static org.assertj.core.api.Assertions.assertThat;

public class AllBeanTest {

    @Test
    void findAllBean() {
        ApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class, DiscountService.class);

        DiscountService discountService = ac.getBean(DiscountService.class);
        Member member = new Member(1L, &quot;userA&quot;, Grade.VIP);
        int discountPrice = discountService.discount(member, 10000, &quot;fixDiscountPolicy&quot;);

        assertThat(discountService).isInstanceOf(DiscountService.class);
        assertThat(discountPrice).isEqualTo(1000);
    }

    static class DiscountService {
        private final Map&lt;String, DiscountPolicy&gt; policyMap;
        private final List&lt;DiscountPolicy&gt; policies;

        @Autowired
        public DiscountService(Map&lt;String, DiscountPolicy&gt; policyMap, List&lt;DiscountPolicy&gt; policies) {
            this.policyMap = policyMap;
            this.policies = policies;
            System.out.println(&quot;policyMap = &quot; + policyMap);
            System.out.println(&quot;policies = &quot; + policies);
        }

        public int discount(Member member, int price, String discountCode) {
            DiscountPolicy discountPolicy = policyMap.get(discountCode);

            System.out.println(&quot;discountCode = &quot; + discountCode);
            System.out.println(&quot;discountPolicy = &quot; + discountPolicy);

            return discountPolicy.discount(member, price);
        }
    }
}</code></pre>
<br>

<h2 id="자동-수동의-올바른-실무-운영-기준">자동, 수동의 올바른 실무 운영 기준</h2>
<h3 id="1-기본-권장---편리한-자동-기능-사용">1) 기본 권장 - 편리한 자동 기능 사용</h3>
<ul>
<li>스프링은 <code>@Component</code> 뿐만 아니라 <code>@Controller</code>, <code>@Service</code>, <code>@Repository</code> 처럼 계층에 맞추어 일반적인
애플리케이션 로직을 자동으로 스캔할 수 있도록 지원한다. </li>
<li>최근 스프링 부트는 컴포넌트 스캔을 기본으로 사용하고, 스프링 부트의 다양한 스프링 빈들도 조건이 맞으면 자동으로 등록하도록 설계했다.</li>
<li>결정적으로 자동 빈 등록을 사용해도 OCP, DIP를 지킬 수 있다.</li>
</ul>
<br>

<h3 id="2-그러면-수동-기능은-언제">2) 그러면, 수동 기능은 언제?</h3>
<h4 id="2-1-기술-지원-빈에-사용">2-1) 기술 지원 빈에 사용</h4>
<p>: 애플리케이션에 광범위하게 영향을 미치는 <strong>기술 지원 객체</strong>에 사용!</p>
<blockquote>
<p><strong>Tip</strong>
애플리케이션은 크게 업무 로직과 기술 지원 로직으로 나눌 수 있다.</p>
<ul>
<li>업무 로직 빈<ul>
<li>웹을 지원하는 컨트롤러, 핵심 비즈니스 로직이 있는 서비스, 데이터 계층의 로직을 처리하는 리포지토리 등등</li>
<li>보통 비즈니스 요구사항을 개발할 때 추가되거나 변경된다.</li>
</ul>
</li>
<li>기술 지원 빈<ul>
<li>기술적인 문제나 공통 관심사(AOP)를 처리할 때 주로 사용됨</li>
<li>데이터베이스 연결이나, 공통 로그 처리 처럼 업무 로직을 지원하기 위한 하부 기술이나 공통 기술들</li>
</ul>
</li>
</ul>
</blockquote>
<h4 id="업무-로직">업무 로직</h4>
<ul>
<li>숫자도 매우 많음</li>
<li>한번 개발해야 하면 컨트롤러, 서비스, 리포지토리 처럼 어느정도 유사한 패턴이 있음</li>
<li>보통 문제가 발생해도 어떤 곳에서 문제가 발생했는지 명확하게 파악하기 쉬움</li>
</ul>
<h4 id="기술-지원-로직">기술 지원 로직</h4>
<ul>
<li>업무 로직과 비교해서 그 수가 매우 적음</li>
<li>보통 애플리케이션 전반에 걸쳐서 광범위하게 영향을 미침 </li>
<li>적용이 잘 되고 있는지 아닌지 조차 파악하기 어려운 경우가 많음</li>
<li>이런 기술 지원 로직은 가급적 수동 빈 등록을 사용해서 명확하게 드러내는 것이 좋다.</li>
</ul>
<blockquote>
<p>👉🏻 <strong>정리</strong>
애플리케이션에 광범위하게 영향을 미치는 기술 지원 객체는 수동 빈으로 등록해서 딱! 설정 정보에 바로 나타나게 하는 것이 유지보수 하기 좋다.</p>
</blockquote>
<br>

<h4 id="2-2-특이-케이스--비즈니스-로직-중에서도-수동이-필요할-경우">2-2) 특이 케이스 : 비즈니스 로직 중에서도 수동이 필요할 경우</h4>
<p>: 다형성을 적극 활용할 때!</p>
<ul>
<li><p>위의 <code>AllBeanTest</code> 같은 경우, 어떤 빈들이 주입될지, 각 빈의 이름이 무엇일지 등은 코드만 보고 파악하기 어렵다.</p>
<ul>
<li>자동 등록을 사용하고 있기 때문에, 파악하려면 여러 코드를 찾아봐야 함!</li>
</ul>
</li>
<li><p>이럴 경우에는, <strong>수동 빈으로 등록하거나</strong> 또는 자동으로 하면 <strong>특정 패키지에 같이 묶어두는 게 좋다</strong>! </p>
<blockquote>
<p>👉🏻 <strong>핵심은, 딱 보고 이해가 되어야 한다!</strong></p>
</blockquote>
<ul>
<li><p>수동 빈으로 등록하기</p>
<pre><code class="language-java">@Configuration
public class DiscountPolicyConfig {

   @Bean
   public DiscountPolicy rateDiscountPolicy() {
        return new RateDiscountPolicy();
   }

   @Bean
   public DiscountPolicy fixDiscountPolicy() {
        return new FixDiscountPolicy();
   }
}</code></pre>
</li>
</ul>
</li>
</ul>
<blockquote>
<p>💡 <strong>참고!</strong></p>
<ul>
<li>스프링과 스프링 부트가 자동으로 등록하는 수 많은 빈들은 예외다.<ul>
<li>이런 부분들은 스프링 자체를 잘 이해하고 스프링의 의도대로 잘 사용하는게 중요하다. </li>
<li>ex) Spring Boot : DataSource 같은 데이터베이스 연결에 사용하는 기술 지원 로직까지 내부에서 자동으로 등록하는데, 이런 부분은 메뉴얼을 잘 참고해서 스프링 부트가 의도한 대로 편리하게 사용하면 된다. </li>
</ul>
</li>
<li>반면에 스프링 부트가 아니라 내가 직접 기술 지원 객체를 스프링 빈으로 등록한다면 수동으로 등록해서 명확하게 드러내는 것이 좋다.</li>
</ul>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] Component Scan, @Autowired]]></title>
            <link>https://velog.io/@sw_smj/Spring-Component-Scan</link>
            <guid>https://velog.io/@sw_smj/Spring-Component-Scan</guid>
            <pubDate>Sun, 16 Apr 2023 13:46:00 GMT</pubDate>
            <description><![CDATA[<h2 id="1-componentscan">1. @ComponentScan</h2>
<ul>
<li><p>스프링은 설정 정보가 없어도 자동으로 스프링 빈을 등록하는 컴포넌트 스캔이라는 기능을 제공한다.
<img src="https://velog.velcdn.com/images/sw_smj/post/f3c5d8b7-2ad7-4703-afc3-8435992d5f2a/image.png" alt=""></p>
</li>
<li><p>Bean 이름 : 기본설정) 클래스명을 사용하되 맨 앞글자만 소문자를 사용한다.</p>
</li>
<li><p>단, 이름을 직접 설정하고 싶으면<code>@Component(&quot;memberService2&quot;)</code> 처럼 애너테이션에다 입력하여 설정</p>
</li>
</ul>
<br>

<h3 id="1-1-탐색할-패키지-지정">1-1. 탐색할 패키지 지정</h3>
<ul>
<li><p>모든 자바 클래스를 다 컴포넌트 스캔하면 시간이 오래 걸린다. 그래서 꼭 필요한 위치부터 탐색하도록 시작 위치를 지정할 수 있다.</p>
</li>
<li><p><code>basePackages</code> : 탐색할 패키지의 시작 위치를 지정한다. 이 패키지를 포함해서 하위 패키지를 모두 탐색한다.</p>
<pre><code class="language-java">@Configuration      // Component Scan 사용하기 위해 붙이는 Annotation
@ComponentScan(
        basePackages = &quot;hello.core.member&quot;,
        excludeFilters = @ComponentScan.Filter(type= FilterType.ANNOTATION, classes = Configuration.class)
)
public class AutoAppConfig {
}</code></pre>
</li>
<li><p><code>basePackageClasses</code> : 지정한 클래스의 패키지를 탐색 시작 위치로 지정한다.</p>
</li>
<li><p>지정 X : <code>@ComponentScan</code>이 붙은 설정 정보 클래스의 패키지가 시작 위치가 된다.</p>
</li>
</ul>
<blockquote>
<p>⭐ <strong>권장하는 방법</strong>
패키지 위치를 지정하지 않고, <strong>설정 정보 클래스의 위치</strong>를 <strong>프로젝트 최상단에 두는 것</strong>이다. </p>
</blockquote>
<blockquote>
<p>💡 <strong>참고</strong>
스프링 부트도 위와 같다. 스프링 부트를 사용하면 스프링 부트의 대표 시작 정보인 <code>@SpringBootApplication</code>를 이 프로젝트 시작 루트 위치에 두는 것이 관례이다. 이 설정안에 바로 <code>@ComponentScan</code>이 들어있다.</p>
</blockquote>
<br>

<h3 id="1-2-filter">1-2. Filter</h3>
<ul>
<li><code>includeFilters</code> : 컴포넌트 스캔 대상을 추가로 지정한다.</li>
<li><code>excludeFilters</code> : 컴포넌트 스캔에서 제외할 대상을 지정한다</li>
</ul>
<h4 id="filtertype-옵션">FilterType 옵션</h4>
<ul>
<li><code>ANNOTATION</code> - 기본값, 애노테이션을 인식해서 동작한다. (<code>org.example.SomeAnnotation</code>)</li>
<li><code>ASSIGNABLE_TYPE</code> - 지정한 타입과 자식 타입을 인식해서 동작한다. (<code>org.example.SomeClass</code>)</li>
<li><code>ASPECTJ</code> - AspectJ 패턴 사용 (<code>org.example..*Service+</code>)</li>
<li><code>REGEX</code> - 정규 표현식 (<code>org\.example\.Default.*</code>)</li>
<li><code>CUSTOM</code> - <code>TypeFilter</code> 이라는 인터페이스를 구현해서 처리(<code>org.example.MyTypeFilter</code>)</li>
</ul>
<blockquote>
<p>💬 <strong>참고</strong></p>
<ul>
<li><code>@Component</code>면 충분하기 때문에, <code>includeFilters</code>를 사용할 일은 거의 없다. </li>
<li><code>excludeFilters</code>는 여러가지 이유로 간혹 사용할 때가 있지만 많지는 않다.</li>
<li>특히 최근 스프링 부트는 컴포넌트 스캔을 기본으로 제공하는데, 옵션을 변경하면서 사용하기보다는 스프링의 기본 설정에 최대한 맞추어 사용하는 것이 권장되는 편이다.</li>
</ul>
</blockquote>
<br>

<h3 id="1-3-component-scan-기본-대상">1-3. Component Scan 기본 대상</h3>
<ul>
<li><code>@Component</code> : 컴포넌트 스캔에서 사용</li>
<li><code>@Controlller</code> : 스프링 MVC 컨트롤러에서 사용</li>
<li><code>@Service</code> : 스프링 비즈니스 로직에서 사용</li>
<li><code>@Repository</code> : 스프링 데이터 접근 계층에서 사용</li>
<li><code>@Configuration</code> : 스프링 설정 정보에서 사용</li>
</ul>
<blockquote>
<p>💡 <strong>참고</strong>
사실 애노테이션에는 상속관계라는 것이 없다. 그래서 이렇게 애노테이션이 특정 애노테이션을 들고 있는 것을 인식할 수 있는 것은 자바 언어가 지원하는 기능은 아니고, 스프링이 지원하는 기능이다.</p>
</blockquote>
<br>

<h3 id="1-4-위의-annotation들의-스프링-부가-기능">1-4. 위의 Annotation들의 스프링 부가 기능</h3>
<ul>
<li><code>@Controller</code> : <strong>스프링 MVC 컨트롤러</strong>로 인식</li>
<li><code>@Repository</code> : <strong>스프링 데이터 접근 계층</strong>으로 인식하고, <strong>데이터 계층의 예외를 스프링 예외로 변환</strong>해준다.</li>
<li><code>@Configuration</code> : <strong>스프링 설정 정보로 인식</strong>하고, <strong>스프링 빈이 싱글톤을 유지하도록 추가 처리</strong>를 한다.</li>
<li><code>@Service</code> : 사실 특별한 처리를 하지 않는다. 대신 개발자들이 핵심 비즈니스 로직이 여기에 있겠구나 라고 비즈니스 계층을 인식하는데 도움이 된다.</li>
</ul>
<blockquote>
<p>💬 참고
<code>useDefaultFilters</code> 옵션은 기본으로 켜져있는데, 이 옵션을 끄면 기본 스캔 대상들이 제외된다. (그냥 알고만 넘어가기)</p>
</blockquote>
<br>

<h3 id="1-5-중복-등록과-충돌">1-5. 중복 등록과 충돌</h3>
<h4 id="case-1--자동-빈-등록-vs-자동-빈-등록">Case 1 : 자동 빈 등록 vs 자동 빈 등록</h4>
<ul>
<li>컴포넌트 스캔에 의해 자동으로 스프링 빈이 등록되는데, 그 이름이 같은 경우 스프링은 오류를 발생시킨다.</li>
<li>발생하는 예외 : <code>ConflictingBeanDefinitionException</code></li>
</ul>
<h4 id="case-2--수동-빈-등록-vs-자동-빈-등록">Case 2 : 수동 빈 등록 vs 자동 빈 등록</h4>
<ul>
<li><p>수동 빈 등록이 우선권을 가진다.
(수동 빈이 자동 빈을 오버라이딩 해버린다.)</p>
</li>
<li><p>의도했다면 모르겠지만, 보통은 여러 설정들이 꼬여서 이런 결과가 만들어진다. 그러면 정말 잡기 어려운 버그가 만들어진다. </p>
</li>
<li><p>그래서 최근 스프링 부트에서는 수동 빈 등록과 자동 빈 등록이 충돌나면 오류가 발생하도록 기본 값을 바꾸었다. </p>
<pre><code class="language-java">Consider renaming one of the beans or enabling overriding by setting 
spring.main.allow-bean-definition-overriding=true</code></pre>
<ul>
<li>오버라이딩하도록 하고 싶다면 <code>spring.main.allow-bean-definition-overriding=true</code> 설정하면 됨</li>
</ul>
</li>
</ul>
<blockquote>
<p>⭐ <strong>개발을 하다 보면 중요한 교훈</strong>
명확하지 않은 것은 피하라. </p>
<ul>
<li>어설픈 추상화나, 어설픈 우선 순위는 나중에 정말 잡기 힘든 버그를 만든다.</li>
</ul>
</blockquote>
<br>

<h2 id="2-autowired">2. @Autowired</h2>
<ul>
<li>스프링은 의존관계를 자동으로 주입하는 <code>@Autowired</code>라는 기능도 제공한다.
<img src="https://velog.velcdn.com/images/sw_smj/post/7b365e67-dcf2-488f-b2e3-0e24c314ed4e/image.png" alt=""></li>
<li>생성자에 <code>@Autowired</code>를 지정하면, 스프링 컨테이너가 자동으로 해당 스프링 빈을 찾아서 주입한다. </li>
<li>이때 기본 조회 전략은 타입이 같은 빈을 찾아서 주입한다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] Singleton Container]]></title>
            <link>https://velog.io/@sw_smj/Spring-Singleton-Container</link>
            <guid>https://velog.io/@sw_smj/Spring-Singleton-Container</guid>
            <pubDate>Sun, 16 Apr 2023 12:45:19 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>💡 <strong>Singleton Container가 필요한 이유?</strong>
스프링 없는 순수한 DI 컨테이너 : 요청을 할 때 마다 객체를 새로 생성</p>
<ul>
<li>고객 트래픽이 초당 100이 나오면 초당 100개 객체가 생성 / 소멸 : 메모리 낭비</li>
</ul>
<p>👉🏻 해결방안 : 해당 객체가 딱 1개만 생성되고, 공유하도록 설계하기 : <strong>싱글톤 패턴</strong></p>
</blockquote>
<h1 id="singleton-pattern">Singleton Pattern</h1>
<p>: 클래스의 인스턴스가 딱 1개만 생성되는 것을 보장하는 디자인 패턴</p>
<h4 id="구현-방법">구현 방법</h4>
<ul>
<li>객체 인스턴스를 2개 이상 생성하지 못하도록 막기<ul>
<li>간단한 방법 :<code>private</code> 생성자를 사용해서 외부에서 임의로 <code>new</code> 키워드를 사용하지 못하도록 함<blockquote>
<p>그러면 생성자 쓰면 Compile Error 터짐
세상에서 제일 좋은 오류 = 컴파일오류</p>
</blockquote>
</li>
</ul>
</li>
</ul>
<blockquote>
<p>💡 <strong>참고</strong>
싱글톤 패턴을 구현하는 방법은 여러 가지가 있다. 여기에서는 객체를 미리 생성해두는, 가장 단순하고 안전한 방법을 선택했다.</p>
</blockquote>
<h3 id="singleton-pattern의-문제점">Singleton Pattern의 문제점</h3>
<ul>
<li>싱글톤 패턴을 구현하는 코드 자체가 많이 들어간다.</li>
<li>의존관계상 클라이언트가 구체 클래스에 의존한다. → DIP를 위반한다.</li>
<li>클라이언트가 구체 클래스에 의존해서 OCP 원칙을 위반할 가능성이 높다.</li>
<li>테스트하기 어렵다.</li>
<li>내부 속성을 변경하거나 초기화 하기 어렵다.</li>
<li>private 생성자로 자식 클래스를 만들기 어렵다.</li>
<li>결론적으로 유연성이 떨어진다.</li>
<li>안티패턴으로 불리기도 한다.</li>
</ul>
<br>

<h1 id="singleton-container">Singleton Container</h1>
<ul>
<li>스프링 컨테이너는 싱글톤 패턴의 문제점을 해결하면서, 객체 인스턴스를 싱글톤(1개만 생성)으로
관리한다.</li>
<li>스프링 빈 : 싱글톤으로 관리됨</li>
</ul>
<h3 id="singletonregistry">SingletonRegistry</h3>
<p>: 싱글톤 객체를 생성하고 관리하는 기능</p>
<ul>
<li>싱글턴 패턴의 모든 단점을 해결하면서 객체를 싱글톤으로 유지할 수 있다.<ul>
<li>싱글톤 패턴을 위한 지저분한 코드가 들어가지 않아도 된다.</li>
<li>DIP, OCP, 테스트, private 생성자로부터 자유롭게 싱글톤을 사용할 수 있다.</li>
</ul>
</li>
</ul>
<blockquote>
<p>💡 <strong>참고</strong></p>
<ul>
<li>스프링의 기본 빈 등록 방식 = 싱글톤</li>
<li>단, 싱글톤 이외의 방식도 존재! 
요청때마다 새로운 객체를 생성해서 반환하는 기능도 제공</li>
</ul>
</blockquote>
<br>

<h1 id="singleton-방식의-주의점">Singleton 방식의 주의점</h1>
<ul>
<li>싱글톤 방식 : 무상태(stateless)로 설계해야 한다<ul>
<li>여러 클라이언트가 하나의 같은 객체 인스턴스를 공유하기 때문!</li>
<li>특정 클라이언트에 의존적인 필드가 있으면 안됨</li>
<li>가급적 읽기만 가능해야 함</li>
</ul>
</li>
<li>필드 대신에 자바에서 공유되지 않는 지역변수, 파라미터, ThreadLocal 등을 사용해야 한다.</li>
<li><strong>스프링 빈의 필드에 공유 값을 설정하면 정말 큰 장애가 발생할 수 있다!!!</strong></li>
</ul>
<blockquote>
<p>💡 <strong>정리</strong></p>
<ul>
<li>실무에서 이런 경우를 종종 보는데, 이로인해 정말 해결하기 어려운 큰 문제들이 터진다.(몇년에 한번씩 꼭 만난다.)</li>
<li>진짜 공유필드는 조심해야 한다! <strong>스프링 빈은 항상 무상태(stateless)로 설계하자.</strong></li>
</ul>
</blockquote>
<br>

<h1 id="configuration">@Configuration</h1>
<p>: 싱글톤을 위해 존재함!</p>
<h3 id="방법">방법</h3>
<ul>
<li><p>스프링은 클래스의 바이트코드를 조작하는 라이브러리를 사용한다.</p>
<ul>
<li><code>AnnotationConfigApplicationContext</code>에 파라미터로 넘긴 값은 스프링 빈으로 등록된다. 그래서 <code>AppConfig</code>도 스프링 빈이 된다.</li>
<li>단, 순수한 클래스로 등록되지 않는다.</li>
<li>스프링이 <code>CGLIB</code>라는 바이트코드 조작 라이브러리를 사용해서 <code>AppConfig</code> 클래스를 상속받은 임의의 다른 클래스를 만들고, 그 다른 클래스를 스프링 빈으로 등록한다.</li>
</ul>
</li>
<li><p>AppConfig@CGLIB 예상 코드</p>
<pre><code class="language-java">@Bean
public MemberRepository memberRepository() {

   if (memoryMemberRepository가 이미 스프링 컨테이너에 등록되어 있으면?) {
           return 스프링 컨테이너에서 찾아서 반환;
   } else { //스프링 컨테이너에 없으면
           기존 로직을 호출해서 MemoryMemberRepository를 생성하고 스프링 컨테이너에 등록
           return 반환
   }
}</code></pre>
<blockquote>
<p>💡 <strong>참고</strong>
AppConfig@CGLIB는 AppConfig의 자식 타입이므로, AppConfig 타입으로 조회 할 수 있다.</p>
</blockquote>
</li>
</ul>
<h3 id="그럼-configuration-적용하지-않을-경우">그럼, @Configuration 적용하지 않을 경우?</h3>
<ul>
<li>@Bean만 사용해도 스프링 빈으로 등록되지만, 싱글톤을 보장하지 않는다.</li>
</ul>
<blockquote>
<p>👉🏻 <strong>정리</strong>
크게 고민할 것이 없다. <strong>스프링 설정 정보는 항상 <code>@Configuration</code>을 사용하자</strong></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Effective Java] item 56 : 공개된 API 요소에는 항상 문서화 주석을 작성하라]]></title>
            <link>https://velog.io/@sw_smj/Effective-Java-item-56-%EA%B3%B5%EA%B0%9C%EB%90%9C-API-%EC%9A%94%EC%86%8C%EC%97%90%EB%8A%94-%ED%95%AD%EC%83%81-%EB%AC%B8%EC%84%9C%ED%99%94-%EC%A3%BC%EC%84%9D%EC%9D%84-%EC%9E%91%EC%84%B1%ED%95%98%EB%9D%BC</link>
            <guid>https://velog.io/@sw_smj/Effective-Java-item-56-%EA%B3%B5%EA%B0%9C%EB%90%9C-API-%EC%9A%94%EC%86%8C%EC%97%90%EB%8A%94-%ED%95%AD%EC%83%81-%EB%AC%B8%EC%84%9C%ED%99%94-%EC%A3%BC%EC%84%9D%EC%9D%84-%EC%9E%91%EC%84%B1%ED%95%98%EB%9D%BC</guid>
            <pubDate>Sun, 16 Apr 2023 09:52:31 GMT</pubDate>
            <description><![CDATA[<h2 id="api-문서">API 문서</h2>
<ul>
<li>API를 쓸모 있게 하려면 문서를 잘 작성해야 함</li>
<li>사람이 직접 작성하려면 코드가 수정될 때마다 매번 함께 수정해줘야 함</li>
</ul>
<h3 id="javadoc">Javadoc</h3>
<ul>
<li>Javadoc(자바독): API 문서 수정 등을 사람 대신 해줄 수 있는 자바의 유틸리티</li>
<li>소스코드 파일에서 <strong>문서화 주석</strong>(doc comment; 자바독 주석)이라는 특수한 형태로 기술된 부분을 추려서, API 문서로 변환함</li>
</ul>
<h3 id="doc-comment-업계-표준-규칙">doc comment 업계 표준 규칙</h3>
<ul>
<li>공식 언어 명세에는 속하지는 앟지만, 자바 프로그래머라면 응당 알아야 하는 업계 표준 API</li>
<li>「문서화 주석 작성법（How to Write Doc Comments）」웹페이지에 기술되어 있음
 👉🏻 <a href="https://www.oracle.com/kr/technical-resources/articles/java/javadoc-tool.html">How to Write Doc Comments for the Javadoc Tool</a></li>
<li>자바 버전이 올라가며 추가된 몇 가지 중요한 태그<ul>
<li>Java 5 - <code>@literal</code>, <code>@code</code></li>
<li>Java 8 - <code>@implSpec</code>, <code>@index</code></li>
<li>Java 9 - <code>@index</code></li>
</ul>
</li>
</ul>
<br>

<h3 id="api-문서화-주석-작성하기">API 문서화 주석 작성하기</h3>
<h4 id="공개-클래스">공개 클래스</h4>
<ul>
<li>API를 올바로 문서화하려면, 공개된 모든 클래스, 인터페이스, 메서드, 필드 선언에 문서화 주석을 달아야 함</li>
<li>직렬화할 수 있는 클래스라면 직렬화 형태에 관해서도 적어야 함</li>
<li>기본 생성자에는 문서화 주석을 달 방법이 없으니 공개 클래스는 절대 기본 생성자를 사용하면 안 됨</li>
</ul>
<blockquote>
<p>📌 <strong>문서화 주석을 제대로 작성하지 않으면?</strong></p>
<ul>
<li>문서화 주석이 없다면 Javadoc도 그저 공개 API 요소들의 선언만 나열해주는 것이 전부임!</li>
<li>문서가 잘 갖춰지지 않은 API는 쓰기 헷갈려서 오류의 원인이 되기 쉬움</li>
</ul>
</blockquote>
<h4 id="공개되지-않은-클래스">공개되지 않은 클래스</h4>
<ul>
<li>유지보수까지 고려한다면 대다수의 공개되지 않은 클래스, 인터페이스, 생성자, 메서드, 필드에도 주석을 달아야 함(공개 API보다는 덜 상세해도 됨)</li>
</ul>
<br>

<h3 id="메서드용-문서화-주석">메서드용 문서화 주석</h3>
<ul>
<li><p>해당 메서드와 클라이언트 사이의 규약을 명료하게 기술하기</p>
</li>
<li><p>상속용으로 설계된 클래스의 메서드가 아니라면, 무엇을 하는지를 기술하기 - <code>how (x), what (o)</code></p>
</li>
<li><p>메서드의 계약(contract)를 완벽히 기술하려면, </p>
<ul>
<li>모든 매개변수에 <code>@param</code> 태그</li>
<li>반환타입이 void가 아니라면 <code>@return</code> 태그</li>
<li>발생할 가능성이 있는 모든 예외에 <code>@throws</code> 태그 (검사 예외, 비검사 예외 모두)<blockquote>
<p>📌 <strong>참고!</strong>
만약 여러분이 따르는 코딩 표준에서 허락한다면 @return 태그의 설명이 메서드 설명과 같을 때에는 @return 태그 생략 가능</p>
</blockquote>
</li>
</ul>
</li>
<li><p><strong>전제조건(precondition)</strong></p>
<ul>
<li>클라이언트가 해당 메서드를 호출하기 위한 조건들</li>
<li>전제조건을 모두 나열해야 함</li>
<li><code>@throws</code> 태그 : 비검사 예외를 선언하여 암시적으로 기술함. 비검사예외 하나가 전제조건 하나와 연결됨!</li>
<li><code>@param</code> 태그 : 그 조건에 영향받는 매개변수에 기술함</li>
</ul>
</li>
</ul>
<ul>
<li><p><strong>사후조건(postcondition)</strong></p>
<ul>
<li>메서드가 성공적으로 수행된 후 만족해야 하는 조건들</li>
<li>사후조건도 모두 나열하기</li>
</ul>
</li>
<li><p><strong>부작용</strong></p>
<ul>
<li>사후조건으로 명확히 나타나지는 않지만 시스템의 상태에 어떠한 변화를 가져오는 것을 뜻함</li>
<li>ex) 백그라운드 스레드를 시작시키는 메서드 - 그 사실을 문서에 밝혀야 함</li>
</ul>
</li>
</ul>
<br>

<h2 id="태그-사용법">태그 사용법</h2>
<h3 id="메서드용-주석-태그들">메서드용 주석 태그들</h3>
<pre><code class="language-java">  /**
  * 이 리스트에서 지정한 위치의 원소를 반환한다.
  *
  * &lt;p&gt;이 메서드는 상수 시간에 수행됨올 보장하지 &lt;i&gt;않는다&lt;/i&gt;. 구현에 따라
  * 원소의 위치에 비례해 시간이 걸릴 수도 있다.
  *
  * @param  index 반환할 원소의 인덱스; 0 이상이고 리스트 크기보다 작아야 한다.
  * @return 이 리스트에서 지정한 위치의 원소
  * @throws IndexOutOfBoundsException index가 범위를 벗어나면,
  *         즉, ({@code index &lt; 0 || index &gt;= this.size()}》이면 발생한다.
  */
  E get(int index);</code></pre>
<p>  (영어 버전)</p>
<pre><code class="language-java">  /**
  * Returns the element at the specified position in this list.
  *
  * &lt;p&gt;This method is &lt;i&gt;not&lt;/i&gt; guaranteed to run in constant
  * time. In some implementations it may run in time proportional
  * to the element position.
  *
  * @param index index of element to return; must be
  *        non-negative and less than the size of this list
  * @return the element at the specified position in this list
  * @throws IndexOutOfBoundsException if the index is out of range
  *         ({@code index &lt; 0 || index &gt;= this.size()})
  */
  E get(int index);</code></pre>
<blockquote>
<p>💬 Javadoc 유틸리티는 문서화 주석을 HTML로 변환함</p>
<ul>
<li>문서화 주석에 HTML 태그를 사용 - <code>&lt;p&gt;</code>, <code>&lt;i&gt;</code></li>
<li>HTML 표(table)까지 집어넣는 프로그래머도 있음</li>
</ul>
</blockquote>
<ul>
<li><p><strong><code>@param</code></strong></p>
<ul>
<li>해당 매개변수가 뜻하는 값이나 반환값을 설명하는 명사구를 씀</li>
<li>드물게는 명사구 대신 산술 표현식을 쓰기도 함</li>
<li>관례상 설명에 마침표를 붙이지 않음</li>
</ul>
</li>
<li><p><strong><code>@return</code></strong></p>
<ul>
<li>해당 매개변수가 뜻하는 값이나 반환값을 설명하는 명사구를 씀</li>
<li>드물게는 명사구 대신 산술 표현식을 쓰기도 함</li>
<li>관례상 설명에 마침표를 붙이지 않음</li>
</ul>
</li>
<li><p><strong><code>@throws</code></strong></p>
<ul>
<li>if로 시작해 해당 예외를 던지는 조건을 설명하는 절이 뒤따름</li>
<li>관례상 설명에 마침표를 붙이지 않음</li>
</ul>
</li>
<li><p><strong><code>{@code} 태그</code></strong></p>
<ul>
<li>첫번째 효과 : 태그로 감싼 내용을 코드용 폰트로 렌더링함</li>
<li>두번째 효과 : 태그로 감싼 내용에 포함돈 HTML 요소나 다른 자바독 태그를 무시함 (HTML 메타 문자도 사용 가능)<blockquote>
<p>📌 <strong>여러 줄로 코드 예시를 넣으려면?</strong></p>
<ul>
<li><code>{@code}</code> 태그를 다시 <code>&lt;pre&gt;</code> 태그로
감싸면 됨 (<code>&lt;pre&gt;</code> <code>{@code ... 코드 ... }</code> <code>&lt;/pre&gt;</code> 형태)</li>
<li>단，<code>@</code> 기호에는 무조건 탈출문자를 붙여야 하니 문서화 주석 안의 코드에서 애너테이션을 사용한다면 주의!</li>
</ul>
</blockquote>
</li>
</ul>
</li>
<li><p><strong><code>this</code></strong></p>
<ul>
<li>관례상 인스턴스 메서드의 문서화 주석에 쓰인 this는 호출된 메서드가 자리하는 객체를 가리킴</li>
</ul>
</li>
</ul>
<br>

<h3 id="상속용-클래스">상속용 클래스</h3>
<ul>
<li>자기사용 패턴(self-use pattern)에 대해서도 문서에 남겨 다른 프로그래머들에게 그 메서드를 올바로 재정의하는 방법을 알려줘야 함</li>
</ul>
<pre><code class="language-java">/**
* 이 컬렉션이 비었다면 true를 반환한다.
*
* @implSpec
* 이 구현은 {@code this.sizeO = 0}의 결과를 반환한다.
*
* @return o| 컬렉션이 비었다면 true, 그렇지 않으면 false
*/
public boolean isEmpty() { ... }</code></pre>
<p>(원어 버전)</p>
<pre><code class="language-java">/**
* Returns true if this collection is empty.
*
* @implSpec
* This implementation returns {@code this.size() = 0}.
*
* @return true if this collection is empty
*/
public boolean isEmpty() { ... }</code></pre>
<ul>
<li><p><strong><code>@impleSpec</code></strong></p>
<ul>
<li>해당 메서드와 하위 클래스 사이의 계약을 설명함</li>
<li>하위 클래스들이 그 메서드를 상속하거나, super 키워드를 이용하여 호출할 때 그 메서드가 어떻게 동작하는지를 명확히 인지하고 사용하기</li>
</ul>
<blockquote>
<p>💬 <strong>impleSpec이 독특한 케이스!</strong>
일반적인 문서화 주석은 해당 메서드와 클라이언트 사이의 계약을 설명함</p>
</blockquote>
<blockquote>
<p>💬 <strong><code>@impleSpec</code> 활용 방법</strong>
자바 11까지도 자바독 명령줄에서 -tag &quot;implSpec:a:Implementation Requirements:&quot; 스위치를 켜주지 않으면<code>@implSpec</code> 태그를 무시해버린다. 다음 버전에
서는 기본값으로 적용되길 기대해본다.</p>
</blockquote>
</li>
</ul>
<br>

<h2 id="주석에----등의-html-메타문자-포함시키기">주석에 &lt;, &gt;, &amp; 등의 HTML 메타문자 포함시키기</h2>
<p>특별한 처리가 필요함!</p>
<ul>
<li><strong><code>{@literal}</code></strong><ul>
<li>가장 좋은 방법</li>
<li>HTML 마크업이나 자바독 태그를 무시하게 해줌</li>
<li>앞서 본 <code>{@code}</code> 태그와 비슷하지만, 코드 폰트로 렌더링하지는 않음
```java</li>
<li>{@literal |r| &lt; 1}이면 기하 수열이 수렴한다.
```</li>
<li>기호만 <code>{@literal}</code>로 감싸도 결과는 같지만, 그러면 코드에서의 가독성이 떨어짐<blockquote>
<p><strong>💡 원칙</strong></p>
<ul>
<li>문서화 주석은 코드에서건 변환된 API 문서에서건 읽기 쉬워야 한다!</li>
<li>단, 양쪽을 만족하지 못하겠다면 API문서에서의 가독성을 우선시!</li>
</ul>
</blockquote>
</li>
</ul>
</li>
</ul>
<br>

<h2 id="문서화-주석-form">문서화 주석 form</h2>
<pre><code class="language-java">  /**
  * 이 리스트에서 지정한 위치의 원소를 반환한다.
  *
  * &lt;p&gt;이 메서드는 상수 시간에 수행됨올 보장하지 &lt;i&gt;않는다&lt;/i&gt;. 구현에 따라
  * 원소의 위치에 비례해 시간이 걸릴 수도 있다.
  *
  * @param  index 반환할 원소의 인덱스; 0 이상이고 리스트 크기보다 작아야 한다.
  * @return 이 리스트에서 지정한 위치의 원소
  * @throws IndexOutOfBoundsException index가 범위를 벗어나면,
  *         즉, ({@code index &lt; 0 || index &gt;= this.size()}》이면 발생한다.
  */
  E get(int index);</code></pre>
<h4 id="첫-번째-문장--summary-descripsion">첫 번째 문장 : summary descripsion</h4>
<ul>
<li><p>해당 요소의 요약 설명</p>
<ul>
<li>반드시 대상의 기능을 고유하게 설명해야 함</li>
<li>헷갈리지 않으려면, 한 클래스/인터페이스 안에서 요약 설명이 똑같은 멤버/생성자가 둘 이상이면 안 됨</li>
<li>다중정의된 메서드는 특히 더 조심하기! 같은 문장으로 시작하는 것이 허용되지 않음</li>
</ul>
</li>
<li><p>마침표(<code>.</code>) 주의하기!</p>
<ul>
<li><p>첫 번째 마침표가 나오는 부분까지만 요약 설명이 됨</p>
<pre><code class="language-java">* 머스터드 대령이나 Mrs. 피콕 같은 용의자.</code></pre>
<blockquote>
<p><strong>📌 요약 설명이 끝나는 판단 기준</strong></p>
<ul>
<li>{&lt;마침표&gt;&lt;공백&gt;&lt;다음 문장 시작&gt;} 패턴의&lt;마침표&gt;</li>
<li><code>&lt;다음 문장 시작&gt;</code>은 ‘소문자가 아닌’문자</li>
<li>예시에서는 “Mrs.” 다음에 공백이 나오고 다음 단어인 ‘피’가 소문자가 아니므로 요약 설명이 끝났다고 판단한 것!</li>
</ul>
</blockquote>
</li>
<li><p>가장 좋은 해결책은 의도치 않은 마침표를 포함한 텍스트를 <code>{@literal}</code>로 감싸주는 것</p>
<pre><code class="language-java">/**
 * 머스타드 대령이나 {@literal Mrs. 피콕} 같은 용의자.
 */</code></pre>
<blockquote>
<p><strong>💡 Tip</strong></p>
<ul>
<li>자바 10부터는 <code>{@summary}</code>라는 요약 설명 전용 태그가 추가되어, 다음처럼 한결 깔끔하게 처리할 수 있다.
```java
/**</li>
<li>{@summary 머스타드 대령이나 Mrs. 피콕 같은 용의자.}</li>
<li>/
public enum Suspect { ... }
```</li>
</ul>
</blockquote>
</li>
</ul>
</li>
<li><p>주석 작성 규약에 따르면, 요약 설명은 완전한 문장이 되는 경우가 드뭄(즉, 주어가 없을 때가 많음)</p>
<ul>
<li>메서드/생성자의 요약 설명 : 해당 메서드와 생성자의 동작을 설명하는 (주어가 없는) 동사구<ul>
<li><code>ArrayList(int initialcapacity)</code> : Constructs an empty list with the specified initial capacity.</li>
<li><code>Collection.size()</code> : Returns the number of elements in this collection.</li>
<li>2인칭 문장(return the number)이 아닌 3인칭 문장(returns the number)으로 써야 한다.</li>
</ul>
</li>
<li>클래스/인터페이스의 요약 설명 : 인스턴스를 설명하는 명사절<ul>
<li><code>Instant</code> : 타임라인상의 특정 순간(지점)</li>
</ul>
</li>
<li>필드의 요약 설명 : 필드 자신을 설명하는 명사절<ul>
<li><code>Math.PI</code> : 원주율(pi)에 가장 가까운 double 값</li>
</ul>
</li>
</ul>
</li>
</ul>
<br>

<h2 id="javadoc과-색인-기능">JavaDoc과 색인 기능</h2>
<ul>
<li>Java 9부터 추가됨</li>
<li>API 문서 페이지 오른쪽 위에 있는 검색창에 키워드를 입력하면 관련 페이지들이 드롭다운 메뉴로 </li>
</ul>
<h3 id="방법">방법</h3>
<ul>
<li>클래스，메서드，필드 같은 API 요소의 색인은 자동으로 만들어짐</li>
<li>원하면 {@index} 태그를 사용해 색인으로 만들 용어를 태그로 감싸 중요한 용어를 추가로 색인화할 수 있음<pre><code class="language-java">* 이 메서드는 {@index IEEE 754} 표준을 준수한다.</code></pre>
</li>
</ul>
<br>

<h2 id="제네릭">제네릭</h2>
<p>제네릭 타입이나 제네릭 메서드를 문서화할 때는 모든 타입 매개변수에 주석을 달아야 한다.</p>
<pre><code class="language-java">/**
* 키와 값을 매핑하는 객체. 맵은 키를 중복해서 가질 수 없다.
* 즉，키 하나가 가리킬 수 있는 값은 최대 1개다.
*
* （나머지 설명은 생략》
*
* @param &lt;K&gt; 이 맵이 관리하는 키의 타입
* Qparam &lt;V&gt; 매핑된 값의 타입
*/
public interface Map&lt;K, V&gt; { ... }</code></pre>
<h2 id="열거-타입">열거 타입</h2>
<p>열거 타입을 문서화할 때는 상수들에도 주석을 달아야 한다. 열거 타입 자체와 그 열거 타입의 public 메서드도 물론이다. 설명이 짧다면 주석 전체를 한 문장으로 써도 된다.</p>
<pre><code class="language-java">/**
* 심포니 오케스트라의 악기 세션.
*/
public enum Orchestrasection {
    /** 폴루트，클라리넷, 오보 같은 목관악기. */
    WOODWIND,

    /** 프렌치 호른，트럼펫 같은 금관악기. */
    BRASS,

    /** 탐파니, 심벌즈 같은 타악기. */
    PERCUSSION,

    /** 바이울린，젤로 같은 현악기. */
    STRING；
}</code></pre>
<h2 id="애너테이션">애너테이션</h2>
<p>애너테이션 타입을 문서화할 때는 멤버들에도 모두 주석을 달아야 한다. 애너테이션 타입 자체도 물론이다. </p>
<ul>
<li>필드 설명은 명사구로 한다. </li>
<li>애너테이션 타입의 요약 설명은 프로그램 요소에 이 애너테이션을 단다는 것이 어떤 의미인지를 설명하는 동사구로 한다. (한글로 쓴다면 동사로 끝나는 평범한 문장이면 된다.)</li>
</ul>
<pre><code class="language-java">/**
* 이 애너테이션이 달린 메서드는 명시한 예외를 던져야만 성공하는
* 테스트 메서드임을 나타낸다.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ExceptionTest {
    /**
    * 이 애너테이션을 단 테스트 메서드가 성공하려면 던져야 하는 예외.
    * (이 클래스의 하위 타입 예외는 모두 허용된다.》
    */
    Class&lt;? extends Throwable&gt; valueO;
}</code></pre>
<br>

<h2 id="패키지--모듈">패키지 &amp; 모듈</h2>
<ul>
<li><p>패키지를 설명하는 문서화 주석은 package-info.java 파일에 작성한다.</p>
<ul>
<li>이 파일은 패키지 선언을 반드시 포함해야 하며 패키지 선언 관련 애너테이션을 추가로 포함할 수도 있다. </li>
</ul>
</li>
<li><p>자바 9부터 지원하는 모듈 시스템을 사용한다면 모듈 관련 설명은 module-info.java 파일에 작성하면 된다</p>
</li>
</ul>
<br>

<h2 id="유의-사항">유의 사항</h2>
<blockquote>
<p>API 문서화에서 자주 누락되는 설명이 두 가지 있으니，바로 스레드 안전성과 직렬화 가능성이다. </p>
</blockquote>
<ul>
<li><p>클래스 혹은 정적 메서드가 스레드 안전하든 그렇지 않든, <strong>스레드 안전 수준</strong>을 반드시 API 설명에 포함해야 한다.</p>
</li>
<li><p>직렬화할 수 있는 클래스라면 <strong>직렬화 형태</strong>도 API 설명에 기술해야 한다.</p>
</li>
<li><p>자바독은 메서드 주석을 ‘상속’시킬 수 있다.</p>
<ul>
<li>문서화 주석이 없는 API 요소를 발견하면 자바독이 가장 가까운 문서화 주석을 찾아준다. 이때 상위 ‘클래스’보다 그 클래스가 구현한 ‘인터 페이스’를 먼저 찾는다.</li>
<li><code>{@inheritDoc}</code> 태그를 사용해 상위 타입의 문서화 주석 일부를 상속할 수 있다. 클래스는 자신이 구현한 인터페이스의 문서화 주석을 (복사해 붙여넣지 않고) 재사용할 수 있다는 뜻이다. 이 기능을 활용하면 거의 똑같은 문서화 주석 여러 개를 유지보수하는 부담을 줄일 수 있지만，사용하기 까다롭고 제약도 조금 있다.</li>
</ul>
</li>
<li><p>비록 공개된 모든 API 요소에 문서화 주석을 달았더라도，여러 클래스가 상호작용하는 복잡한 API라면 문서화 주석 외에도 <strong>전체 아키텍처를 설명하는 별도의 설명</strong>이 필요할 때가 왕왕 있다. </p>
<ul>
<li>이런 설명 문서가 있다면 관련 클래스나 패키지의 문서화 주석에서 그 문서의 링크를 제공해주면 좋다.</li>
</ul>
</li>
</ul>
<h2 id="javadoc-1">JavaDoc</h2>
<ul>
<li>자바독은 프로그래머가 자바독 문서를 올바르게 작성했는지 확인하는 기능을 제공하며，이번 아이템에서 소개한 권장사항 중 상당수를 검사해준다. </li>
<li>자바 9와 10의 자바독은 기본적으로 HTML4.01 문서를 생성하지만，명령줄에서 -htmI5 스위치를 켜면 HTML 5 버전으로 만들어준다.</li>
</ul>
<h3 id="검사-방법">검사 방법</h3>
<ul>
<li>자바 7에서는 명령줄에서 -Xdoclint 스위치를 켜주면 이 기능이 활성화되고，자바 8부터는 기본으로 작동한다. </li>
<li>체크스타일(checkstyle) 같은 IDE 플러그인을 사
용하면 더 완벽하게 검사된다.</li>
</ul>
<h3 id="html-유효성-검사기">HTML 유효성 검사기</h3>
<ul>
<li>자바독이 생성한 HTML 파일을 HTML 유효성 검사기로 돌리면 문서화 주석의 오류를 한층 더 줄일 수 있다. </li>
<li>HTML 유효성 검사기는 잘못 사용한 HTML 태그를 찾아준다. </li>
<li>로컬에 내려받아 사용할 수 있는 설치형 검사기도 있고，웹에서 바로 사용할 수 있는 W3C 마크업 검사 서비스[W3C-validator]도 있다. </li>
</ul>
<br>

<h2 id="참고-사이트">참고 사이트</h2>
<ul>
<li><a href="https://www.oracle.com/technical-resources/articles/java/javadoc-tool.html">문서화 주석 작성법</a></li>
</ul>
<br>

<h2 id="정리">정리</h2>
<ul>
<li><p>문서화 주석은 여러분 API를 문서화하는 가장 훌륭하고 효과적인 방법이다. </p>
</li>
<li><p>공개 API라면 빠짐없이 설명을 달아야 한다. </p>
</li>
<li><p>표준 규약을 일관되게 지키자. </p>
<ul>
<li>문서화 주석에 임의의 HTML 태그를 사용할 수 있음을 기억하라. </li>
<li>단, HTML 메타문자는 특별하게 취급해야 한다.</li>
</ul>
</li>
<li><p>잘 쓰인 문서인지를 확인하는 유일한 방법은 자바독 유틸리티가 생성한 웹페이지를 읽어보는 길뿐이다. </p>
</li>
<li><p>다른 사람이 사용할 API라면 반드시 모든 API 요소를 검토하라.</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] Spring Container, Bean]]></title>
            <link>https://velog.io/@sw_smj/Spring-%EC%8A%A4%ED%94%84%EB%A7%81-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88</link>
            <guid>https://velog.io/@sw_smj/Spring-%EC%8A%A4%ED%94%84%EB%A7%81-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88</guid>
            <pubDate>Wed, 12 Apr 2023 10:07:41 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>스프링 컨테이너와 빈</strong></p>
<ul>
<li>이전 포스팅까지는 개발자가 <code>AppConfig</code>를 사용해서 직접 조회했지만, 이제는 스프링 컨테이너에서 필요한 스프링 빈(객체)을 찾는다.</li>
<li>찾는 방법 : <code>applicationContext.getBean()</code> 메서드 이용</li>
</ul>
</blockquote>
<br>

<h1 id="spring-container">Spring Container</h1>
<ul>
<li><code>ApplicationContext</code> : 스프링 컨테이너</li>
<li><code>@Configuration</code>을 설정(구성) 정보로 사용</li>
<li>스프링 컨테이너는 설정 정보를 참고해서 의존관계를 주입(DI)한다.</li>
<li>단순히 자바 코드를 호출하는 것 같지만, 차이가 있다. 이 차이는 뒤에 싱글톤 컨테이너에서 설명한다.</li>
</ul>
<h3 id="applicationcontext">ApplicationContext</h3>
<ul>
<li>스프링 컨테이너</li>
<li>인터페이스</li>
<li>XML을 기반으로 만들 수 있고, 애노테이션 기반의 자바 설정 클래스로 만들 수도 있다.<pre><code class="language-java">// 스프링 컨테이너 생성
// 애노테이션 기반의 자바 설정을 하겠다는 코드
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);</code></pre>
</li>
<li>자바 설정 클래스를 기반으로 스프링 컨테이너를 만들 수 있다.<ul>
<li>단, 그러기 위해서는 스프링 컨테이너를 생성할 때 구성 정보를 지정해주어야 한다.</li>
</ul>
</li>
</ul>
<h3 id="spring-container의-생성-과정">Spring Container의 생성 과정</h3>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/5627735d-295a-4c40-a0e1-033282685f38/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/2bdcfddd-4a86-4483-8ca1-8e748d14c816/image.png" alt=""></p>
<blockquote>
<p>💡 <strong>참고</strong>
정확하게는, 스프링 컨테이너를 부를 때는 <code>BeanFactory</code>와 <code>ApplicationContext</code>를 구분해서 이야기한다.
단, <code>BeanFactory</code>를 직접 사용하는 경우는 거의 없으므로, 일반적으로 <code>ApplicationContext</code> = 스프링 컨테이너라고 이야기한다.</p>
</blockquote>
<br>

<h1 id="spring-bean">Spring Bean</h1>
<ul>
<li><code>@Bean</code>이라 적힌 메서드를 모두 호출해서, 반환된 객체를 스프링 컨테이너에 등록한다.</li>
<li><strong>스프링 컨테이너에 등록된 객체</strong>를 <strong>스프링 빈</strong>이라고 한다.</li>
<li><code>@Bean</code>이 붙은 메서드 명을 스프링 빈의 이름으로 사용</li>
</ul>
<h3 id="빈-이름">빈 이름</h3>
<ul>
<li>빈 이름은 메서드 이름을 사용한다.</li>
<li>빈 이름을 직접 부여할 수도 있다.</li>
<li>설정 방법 : <code>@Bean (name=&quot;memberService2)&quot;</code></li>
</ul>
<blockquote>
<p>💡 <strong>주의</strong>
단, <strong>빈 이름</strong>은 <strong>항상 다른 이름을 부여해야 한다.</strong>
같은 이름을 부여하면, 다른 빈이 무시되거나 기존 빈을 덮어버리거나 등 설정에 따라 오류가 발생한다.</p>
</blockquote>
<h3 id="의존관계-주입">의존관계 주입</h3>
<ul>
<li>스프링은 ①빈을 생성하고, ②의존관계를 주입하는 단계가 나누어져 있다.</li>
<li>그런데 이렇게 자바 코드로 스프링 빈을 등록하면 생성자를 호출하면서 의존관계 주입도 한번에 처리된다.
<img src="https://velog.velcdn.com/images/sw_smj/post/a4c96dc6-1cce-4287-9bb0-6de2b89ef032/image.png" alt=""></li>
<li>여기서는 이해를 돕기 위해 개념적으로 나누어 설명했다. 자세한 내용은 의존관계 자동 주입에서 다시 설명하겠다.</li>
</ul>
<h3 id="빈-조회">빈 조회</h3>
<ul>
<li>부모 타입으로 조회하면, 자식 타입도 함께 조회된다.</li>
<li>그래서 모든 자바 객체의 최고 부모인 <code>Object</code> 타입으로 조회하면, 모든 스프링 빈이 조회된다.</li>
</ul>
<br>

<h1 id="application--beanfactory">Application &amp; BeanFactory</h1>
<h3 id="beanfactory">BeanFactory</h3>
<ul>
<li>스프링 컨테이너의 최상위 인터페이스</li>
<li>스프링 빈을 관리하고 조회하는 역할을 담당</li>
</ul>
<h3 id="applicationcontext-1">ApplicationContext</h3>
<ul>
<li>BeanFactory 기능을 모두 상속받아서 제공</li>
</ul>
<blockquote>
<p><strong>그럼 BeanFactory와 ApplicationContext의 차이점은?</strong></p>
<ul>
<li>Application을 개발할 때, 빈을 관리하고 검색해주는 기능 외에도 수많은 부가기능이 필요하다.</li>
</ul>
</blockquote>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/7204fd64-4605-4510-8e84-2a9216e58ce5/image.png" alt=""></p>
<ul>
<li><strong>MessageSource</strong> : 국제화 기능
ex) 한국에서 들어오면 한국어로, 영어권에서 들어오면 영어로 출력</li>
<li><strong>EnvironmentCapable</strong> : 환경변수
로컬 / 개발 / 운영 등을 구분해서 처리</li>
<li><strong>ApplicationEventPublisher</strong> : 애플리케이션 이벤트
이벤트를 발행하고 구독하는 모델을 편리하게 지원</li>
<li><strong>ResourceLoader</strong> : 편리한 리소스 조회
파일, 클래스패스, 외부 등에서 리소스를 편리하게 조회</li>
</ul>
<blockquote>
<p>💬 <strong>요약</strong> </p>
<ul>
<li><code>BeanFactory</code>나 <code>ApplicationContext</code>를 스프링 컨테이너라 한다.</li>
<li><code>BeanFactory</code>를 직접 사용할 일은 거의 없다. 부가기능이 포함된 <code>ApplicationContext</code>를 사용한다.<ul>
<li><code>ApplicationContext</code>는 <code>BeanFactory</code>의 기능을 상속받는다.</li>
<li><code>ApplicationContext</code>는 빈 관리기능 + 편리한 부가 기능을 제공한다.</li>
</ul>
</li>
</ul>
</blockquote>
<br>

<h1 id="spring-container-설정">Spring Container 설정</h1>
<p>스프링 컨테이너는 다양한 형식의 설정 정보를 받아들일 수 있게 유연하게 설계되어 있음</p>
<ul>
<li>Java 코드</li>
<li>XML</li>
<li>GRoovy ...</li>
</ul>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/c6499c00-ed7a-4dbe-8d91-31c3495b460a/image.png" alt=""></p>
<br>

<blockquote>
<p><strong>스프링은 어떻게 이런 다양한 설정 형식을 지원하는 것일까?</strong>
-&gt;  <strong><code>BeanDefinition</code></strong> 이라는 추상화 덕분!</p>
</blockquote>
<h2 id="beandefinition">BeanDefinition</h2>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/c0fd5869-81b8-4783-aeae-9d4535c3abed/image.png" alt=""></p>
<h3 id="beandefinition-정보">BeanDefinition 정보</h3>
<ul>
<li><code>BeanClassName</code>: 생성할 빈의 클래스 명(자바 설정 처럼 팩토리 역할의 빈을 사용하면 없음)</li>
<li><code>factoryBeanName</code>: 팩토리 역할의 빈을 사용할 경우 이름, 예) appConfig</li>
<li><code>factoryMethodName</code> : 빈을 생성할 팩토리 메서드 지정, 예) memberService</li>
<li><code>Scope</code>: 싱글톤(기본값)</li>
<li><code>lazyInit</code> : 스프링 컨테이너를 생성할 때 빈을 생성하는 것이 아니라, 실제 빈을 사용할 때 까지 최대한 생성을 지연처리 하는지 여부</li>
<li><code>InitMethodName</code> : 빈을 생성하고, 의존관계를 적용한 뒤에 호출되는 초기화 메서드 명</li>
<li><code>DestroyMethodName</code> : 빈의 생명주기가 끝나서 제거하기 직전에 호출되는 메서드 명</li>
<li><code>Constructor arguments</code>, <code>Properties</code>: 의존관계 주입에서 사용한다. (자바 설정처럼 팩토리 역할의
빈을 사용하면 없음)</li>
</ul>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/cadd92f3-801e-463f-b96d-0e8c407b5607/image.png" alt=""></p>
<ol>
<li><strong><code>AnnotationConfigApplicationContext</code></strong> : <code>AnnotatedBeanDefinitionReader</code> 를 사용해서 <code>AppConfig.class</code>를 읽고 <code>BeanDefinition</code>을 생성</li>
<li><strong><code>GenericXmlApplicationContext</code></strong> : <code>XmlBeanDefinitionReader</code>를 사용해서 <code>appConfig.xml</code> 설정 정보를 읽고 <code>BeanDefinition</code> 을 생성</li>
<li>새로운 형식의 설정 정보를 추가하려면, <code>XxxBeanDefinitionReader</code>를 만들어서 <code>BeanDefinition</code>을 생성하면 됨!</li>
</ol>
<br>

<blockquote>
<p>💬 <strong>정리</strong></p>
<ul>
<li><strong>BeanDefinition을 직접 생성해서 스프링 컨테이너에 등록할 수도 있다.</strong> 
(하지만 실무에서 BeanDefinition을 직접 정의하거나 사용할 일은 거의 없다.)</li>
<li><strong>스프링이 다양한 형태의 설정 정보를 BeanDefinition으로 추상화해서 사용하는 것 정도만 이해하면 된다.</strong> 
(가끔 스프링 코드나 스프링 관련 오픈 소스의 코드를 볼 때, BeanDefinition 이라는 것이 보일 때가 있다. 이때 이러한 메커니즘을 떠올리면 된다.)</li>
</ul>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] IoC, DI, Ioc/DI Container]]></title>
            <link>https://velog.io/@sw_smj/Spring-IoC-DI-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88</link>
            <guid>https://velog.io/@sw_smj/Spring-IoC-DI-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88</guid>
            <pubDate>Wed, 12 Apr 2023 09:47:28 GMT</pubDate>
            <description><![CDATA[<h2 id="1-ioc-inversion-of-control">1. IoC (Inversion of Control)</h2>
<p><strong>제어의 역전</strong></p>
<ul>
<li>Spring에만 국한된 용어는 아님</li>
<li>프로그램의 제어 흐름을 직접 제어하는 것이 아니라, 외부에서 관리하는 것<ul>
<li>ex) <code>AppConfig</code>가 프로그램의 제어 흐름을 가져감</li>
</ul>
</li>
</ul>
<blockquote>
<p>📌 <strong>Framework vs Library</strong></p>
<ul>
<li>프레임워크 : 내가 작성한 코드를 제어하고, 대신 실행함 (ex: JUnit)</li>
<li>라이브러리 : 내가 작성한 코드가 직접 제어의 흐름을 담당함</li>
</ul>
</blockquote>
<br>

<h2 id="2-di-dependency-injection">2. DI (Dependency Injection)</h2>
<p><strong>의존성 주입</strong></p>
<h3 id="2-1-정적인-클래스-의존관계">2-1. 정적인 클래스 의존관계</h3>
<ul>
<li>클래스가 사용하는 import 코드만 보고도 의존 관계를 쉽게 파악할 수 있다.</li>
<li>애플리케이션을 실행하지 않아도 분석할 수 있다.</li>
</ul>
<h3 id="2-2-동적인-객체인스턴스-의존-관계">2-2. 동적인 객체(인스턴스) 의존 관계</h3>
<ul>
<li><p>애플리케이션 실행 시점에 실제 생성된 객체 인스턴스의 참조가 연결된 의존 관계</p>
</li>
<li><p><strong>Dependency Injection(의존관계 주입)</strong> : 애플리케이션 런타임(실행 시점)에 외부에서 실제 구현 객체를 생성하고, 클라이언트에 전달해서, 클라이언트와 서버의 실제 의존 관계가 연결되는 것</p>
</li>
<li><p>객체 인스턴스를 생성하고, 그 참조값을 전달해서 연결된다.</p>
</li>
</ul>
<blockquote>
<p>💡 <strong>의존관계 주입을 사용하면?</strong></p>
<ul>
<li>클라이언트 코드를 변경하지 않고, 클라이언트가 호출하는 대상의 타입 인스턴스를 변경할 수 있다.</li>
<li>정적인 클래스 의존관계를 변경하지 않고(Application 코드를 손 대지 않고), 동적인 객체 인스턴스의 의존관계를 쉽게 변경할 수 있다.</li>
</ul>
</blockquote>
<br>

<h2 id="3-ioc-컨테이너-di-컨테이너">3. IoC 컨테이너, DI 컨테이너</h2>
<p>: <code>AppConfig</code>처럼 객체를 생성하고 관리하면서 의존관계를 연결해주는 것</p>
<blockquote>
<p>📌 <strong>모두 동의어!</strong></p>
<ul>
<li>의존관계 주입에 초점을 맞추어 최근에는 주로 DI 컨테이너라고 함!</li>
<li>Assembler라고도 불림 (레고를 조립하듯이 해서)</li>
<li>Object Factory라고도 불림 (오브젝트를 만들어낸다고 해서)</li>
</ul>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] 스프링 핵심 원리의 이해 - 예제 개선하기]]></title>
            <link>https://velog.io/@sw_smj/Spring-%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC%EC%9D%98-%EC%9D%B4%ED%95%B4-%EC%98%88%EC%A0%9C-%EA%B0%9C%EC%84%A0%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@sw_smj/Spring-%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC%EC%9D%98-%EC%9D%B4%ED%95%B4-%EC%98%88%EC%A0%9C-%EA%B0%9C%EC%84%A0%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 11 Apr 2023 12:21:26 GMT</pubDate>
            <description><![CDATA[<h2 id="0-프로젝트-기획-변경">0. 프로젝트 기획 변경</h2>
<h3 id="새로운-할인-정책-개발">새로운 할인 정책 개발</h3>
<ul>
<li>악덕 기획자 : 고정 금액 할인이 아닌, 10% 정률 할인으로 변경하고자 한다. </li>
</ul>
<blockquote>
<p>📣 <strong>참고 : 애자일 소프트웨어 개발 선언</strong>
<img src="https://velog.velcdn.com/images/sw_smj/post/c8e34b01-93ba-4427-b2e3-cfe31d2872d2/image.png" alt=""></p>
</blockquote>
<h3 id="0-1-설계">0-1. 설계</h3>
<p><strong>RateDiscountPolicy</strong></p>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/67ae649c-f693-44f5-872c-0da4b8360abe/image.png" alt=""></p>
<h3 id="0-2-설계-변경에서-발견한-문제들">0-2. 설계 변경에서 발견한 문제들!</h3>
<ul>
<li>현재의 코드는 OCP, DIP를 위반하고 있다.</li>
</ul>
<pre><code class="language-java">public class OrderServiceImpl implements OrderService {
    private final MemberRepository memberRepository = new MemoryMemberRepository();
    private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
    // ↑ 변경 전
    // OCP 위반! - 결국 코드를 변경해야 하기 때문
    // DIP 위반! - 추상(인터페이스)에만 의존해야 하는데 구현(클래스)에도 의존하고 있기 때문

    // 그러면 이렇게 바꾸면?
    private DiscountPolicy discountPolicy;
    // =&gt; 당연히 NPE 발생!

    ...
    }
}</code></pre>
<br>

<h2 id="1-관심사의-분리">1. 관심사의 분리</h2>
<ul>
<li>배우는 본인의 배역을 수행하는 것에만 집중해야 한다.</li>
<li>남배우는 어떤 여자 주인공이 되더라도 똑같이 공연할 수 있어야 한다.</li>
<li>공연을 구성하고, 담당 배우를 섭외하고, 역할에 맞는 배우를 지정하는 <strong>공연 기획자</strong>가 필요하다.</li>
</ul>
<h3 id="1-1-appconfig--공연기획자">1-1. AppConfig = 공연기획자</h3>
<ul>
<li><p>애플리케이션의 전체 동작 방식을 구성(config)하기 위해, 구현 객체를 <strong>생성</strong>하고 <strong>연결</strong>하는 <strong>책임</strong>을 가지는 별도의 <strong>설정 클래스</strong>를 만들자.</p>
</li>
<li><p>애플리케이션의 실제 동작에 필요한 &quot;구현 객체를 생성&quot;한다.</p>
</li>
<li><p>생성한 객체 인스턴스의 참조(레퍼런스)를 생성자를 통해 주입(연결)한다.</p>
</li>
</ul>
<h3 id="1-2-이제는-dip-ocp를-지키는-것이다">1-2. 이제는 DIP, OCP를 지키는 것이다.</h3>
<pre><code class="language-java">public class OrderServiceImpl implements OrderService {

    private final MemberRepository memberRepository;
    private final DiscountPolicy discountPolicy;

    public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy;
    }

    @Override
    public Order createOrder(Long memberId, String itemName, int itemPrice) {
        Member member = memberRepository.findById(memberId);
        int discountPrice = discountPolicy.discount(member, itemPrice);
        return new Order(memberId, itemName, itemPrice, discountPrice);
    }
}</code></pre>
<ul>
<li><code>MemberServiceImpl</code> 입장에서 이제는 생성자를 통해 어떤 구현 객체가 들어올지는 알 수 없다.</li>
<li>어떤 구현 객체를 주입할지는 오직 외부(<code>AppConfig</code>)에서 결정한다.</li>
<li>이제 의존 관계에 대한 고민은 외부에 맡기고, 담당 배우들은 기능을 실행하는 책임만 지면 된다!</li>
</ul>
<h3 id="1-3-변경된-클래스-다이어그램">1-3. 변경된 클래스 다이어그램</h3>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/30f69526-3092-4ae0-ab7a-009be18f0dd3/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/d8940b3d-da0d-4cd7-85e5-972285707f57/image.png" alt=""></p>
<ul>
<li>클라이언트인 <code>memberServiceImpl</code> 입장에서 보면, 의존관계를 마치 외부에서 주입해주는 것 같다고 해서 <strong>DI(Dependency Injection)</strong>, 우리 말로 <strong>의존관계 주입</strong> 또는 <strong>의존성 주입</strong>이라고 한다.</li>
</ul>
<br>

<h2 id="2-리팩터링">2. 리팩터링</h2>
<h3 id="2-1-appconfig-리팩토링">2-1. AppConfig 리팩토링</h3>
<p><strong>변경 후</strong></p>
<pre><code class="language-java">public class AppConfig {
    public MemberService memberService() {
        return new MemberServiceImpl(memberRepository());
    }

    private MemoryMemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }

    public OrderService orderService() {
        return new OrderServiceImpl(memberRepository(), discountPolicy());
    }

    public DiscountPolicy discountPolicy() {
        return new RateDiscountPolicy();
    }
}</code></pre>
<h4 id="장점">장점</h4>
<ul>
<li>나중에 DB를 바꾸고 싶더라도, 이 AppConfig만 변경하면 됨!</li>
<li>AppConfig를 통해, 역할과 구현 클래스가 한 눈에 들어옴. 또, 애플리케이션 전체 구성이 어떻게 되어 있는지 빠르게 파악할 수 있음</li>
</ul>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/acc5f572-6817-4999-9e0d-0c8ffc08abdd/image.png" alt=""></p>
<ul>
<li>즉, 변경이 생기더라도 구성 영역만 손대면 되고, 사용 영역의 어떠한 코드도 변경할 필요가 없음!</li>
<li>구성 영역은 요구사항의 변경에 따라 당연히 변경됨!</li>
</ul>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/a4021a75-7485-4a01-96a2-6c9e083ff06d/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] 스프링 핵심 원리의 이해 - 예제 만들기]]></title>
            <link>https://velog.io/@sw_smj/Spring-%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC%EC%9D%98-%EC%9D%B4%ED%95%B4-%EC%98%88%EC%A0%9C-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@sw_smj/Spring-%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC%EC%9D%98-%EC%9D%B4%ED%95%B4-%EC%98%88%EC%A0%9C-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Tue, 11 Apr 2023 11:08:21 GMT</pubDate>
            <description><![CDATA[<h2 id="1-비즈니스-요구사항">1. 비즈니스 요구사항</h2>
<h3 id="회원">회원</h3>
<ul>
<li>기능 : 회원 가입, 회원 조회</li>
<li>등급 : 일반 회원, VIP 회원 (2가지 등급)</li>
<li>회원 데이터는 자체 DB를 구축할 수도 있고, 외부 시스템과 연동할 수도 있다. (미정)</li>
</ul>
<h3 id="주문할인-정책">주문/할인 정책</h3>
<ul>
<li>회원은 상품을 주문할 수 있다.</li>
<li>회원 등급에 따라 할인 정책을 적용할 수 있다.</li>
<li>모든 VIP는 1000원을 할인해주는 고정 할인이 있다. (추후 변경 가능)</li>
<li>할인 정책 : 변경 가능성이 높다. 오픈 직정까지 고민을 미루고 싶다 (미확정)</li>
</ul>
<blockquote>
<p>📌 <strong>참고</strong>
이번 프로젝트는 스프링 없는 순수한 자바로만 개발을 진행한다.</p>
</blockquote>
<br>

<h2 id="2-설계">2. 설계</h2>
<h3 id="2-1-회원-관련-설계">2-1. 회원 관련 설계</h3>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/9d461851-1ee8-4cc4-bc1e-f25a3880ce3b/image.png" alt=""></p>
<ul>
<li>기획자들도 볼 수 있는 다이어그램<ul>
<li>이를 바탕으로, 개발자들이 클래스 다이어그램을 그림</li>
</ul>
</li>
<li>DB를 어떻게 구축할지가 미정이기 때문에, 각 저장소 구현체들을 다양하게 만들어본다.<ul>
<li>메모리 회원 저장소 : 서버 켜면 그냥 메모리에만 저장되는, 개발용으로 사용하는 저장소</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/62697406-9e50-4c4d-8418-1a31692e902b/image.png" alt=""></p>
<ul>
<li>객체(구현체) 다이어그램 : 사실 동적으로 결정됨. 서버가 뜨면 사용자가 &#39;실제로&#39; 사용하는, 유효한 인스턴스와 관련된 다이어그램</li>
</ul>
<blockquote>
<p>📣 <strong>백문이불여일타</strong>
코드도 직접 쳐보는 것이 가장 좋다!</p>
</blockquote>
<h3 id="2-2-주문과-할인-설계">2-2. 주문과 할인 설계</h3>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/3190ae5d-6d83-4d27-9b80-6ac5d73a7294/image.png" alt=""></p>
<blockquote>
<p>📌 <strong>참고 1</strong>
여기에서는, 예제를 단순히 하기 위해 상품 클래스를 만들지 않고 그냥 상품 데이터를 넘겨 주문을 하기로 한다. 실무에서는 당연히 &#39;Item&#39; 등의 객체로 만들어서 하는 것이 일반적이다.</p>
</blockquote>
<blockquote>
<p>📌 <strong>참고 2</strong>
주문 정보를 DB에 저장하는 로직도, 예제를 단순히 하기 위해 생략한다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/cb13ee40-dfb6-409b-96b1-95b3cd148bfd/image.png" alt=""></p>
<blockquote>
<p>👉🏻 역할과 구현이 이렇게 명확하게 구분되면, 회원 저장소와 할인 정책을 마치 레고 조립하듯이 자유롭게 조립할 수 있게 된다!</p>
</blockquote>
<h4 id="클래스-다이어그램">클래스 다이어그램</h4>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/749700ea-feea-4bab-ab2d-09035cb61b92/image.png" alt=""></p>
<h4 id="객체-다이어그램들">객체 다이어그램들</h4>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/090cab2b-9af9-4e3f-aa8e-53a3a6f7c9f4/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/6cd8d6a2-f8aa-4bfb-b3a5-c9606422e70f/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] 스프링과 객체 지향 프로그래밍]]></title>
            <link>https://velog.io/@sw_smj/Spring-Spring%EA%B3%BC-%EA%B0%9D%EC%B2%B4-%EC%A7%80%ED%96%A5-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</link>
            <guid>https://velog.io/@sw_smj/Spring-Spring%EA%B3%BC-%EA%B0%9D%EC%B2%B4-%EC%A7%80%ED%96%A5-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</guid>
            <pubDate>Mon, 10 Apr 2023 12:13:19 GMT</pubDate>
            <description><![CDATA[<h2 id="0-spring의-핵심-컨셉">0. Spring의 핵심 컨셉</h2>
<blockquote>
<p><strong>📌 Spring과 Java</strong></p>
<ul>
<li>Spring : Java 언어 기반의 Framework</li>
<li>Java : 객체 지향 언어라는 특징이 가장 대표적인 프로그래밍 언어</li>
</ul>
</blockquote>
<p>👉🏻 <strong>객체 지향 언어가 가진 강력한 특징을 살려내는</strong> Framework
(= <strong>좋은 객체 지향 애플리케이션을 개발</strong>할 수 있게 도와주는 Framework)</p>
<br>

<h2 id="1-객체-지향-프로그래밍object-oriented-programming">1. 객체 지향 프로그래밍(Object Oriented Programming)</h2>
<p>: 컴퓨터 프로그램을 여러 개의 독립된 단위, 즉 &quot;객체&quot;들의 모임으로 파악하고자 하는 것</p>
<ul>
<li>각각의 객체는 메시지를 주고 받고, 데이터를 처리할 수 있다.</li>
<li>프로그램을 유연하고 변경이 용이하게 만듦 → 대규모 소프트웨어 개발에 많이 사용됨<blockquote>
<p>👀 <strong>&#39;유연하고 변경이 용이하다&#39;란?</strong></p>
<ul>
<li>레고 블록을 조립하듯이</li>
<li>컴포넌트를 쉽고 유연하게 변경하면서 개발할 수 있는 방법</li>
</ul>
</blockquote>
</li>
</ul>
<br>

<h2 id="1-polymorphism-다형성">1. Polymorphism (다형성)</h2>
<blockquote>
<p>📌 <strong>객체 지향의 특징</strong></p>
<ul>
<li>추상화</li>
<li>캡슐화</li>
<li>상속</li>
<li>다형성</li>
</ul>
</blockquote>
<p>우선, 세상을 역할과 구현으로 구분해보자.</p>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/67b126cb-a5cc-45aa-a50b-ad1b3680fcef/image.png" alt=""></p>
<ul>
<li>운전자는 다른 자동차를 아무 문제 없이 운전할 수 있다.</li>
<li>이 말은 즉, 자동차들은 클라이언트에 영향을 주지 않고도 계속 출시 (확장)할 수 있다는 것!</li>
</ul>
<h4 id="핵심--역할과-구현을-분리한다">핵심 : 역할과 구현을 분리한다.</h4>
<ul>
<li>세상이 단순해지고 유연해지며 변경도 편리해진다.</li>
<li>대상의 역할(인터페이스)만 알면 된다.</li>
<li>구현 대상의 내부 구조를 몰라도 된다.</li>
<li>구현 대상의 내부 구조가 변경되어도 영향을 받지 않는다.</li>
<li>구현 대상 자체를 변경해도 영향을 받지 않는다.</li>
</ul>
<br>

<h2 id="2-java와-다형성">2. Java와 다형성</h2>
<ul>
<li>역할 = Interface</li>
<li>구현 = Interface를 구현한 Class, 구현 객체(Instance)</li>
</ul>
<blockquote>
<p><strong>💡 핵심</strong>
구현보다 역할이 더 중요하다. 
객체 설계 시에도 인터페이스가 더 먼저다!</p>
</blockquote>
<ul>
<li>Overriding과 관련 깊음</li>
</ul>
<h3 id="다형성의-본질">다형성의 본질</h3>
<ul>
<li>인터페이스를 구현한 <strong>객체 인스턴스를 실행 시점에 유연하게 변경할 수 있음</strong></li>
<li>협력이라는 객체 사이의 관계에서 시작해야 함</li>
<li><strong>확장 가능한 설계</strong><ul>
<li>클라이언트를 변경하지 않고 서버의 구현 기능을 유연하게 변경 가능</li>
<li>인터페이스를 안정적으로 잘 설계하는 것이 매우 중요</li>
</ul>
</li>
</ul>
<blockquote>
<p>📌 <strong>객체의 협력</strong></p>
<ul>
<li>혼자 있는 객체는 없다.<ul>
<li>클라이언트 : 요청</li>
<li>서버 : 응답</li>
</ul>
</li>
<li>수많은 객체 클라이언트와 객체 서버는 서로 협력 관계를 가짐</li>
</ul>
</blockquote>
<blockquote>
<p>👀 
<strong>&quot;의존한다&quot;</strong> = &quot;알고 있다.&quot;</p>
</blockquote>
<h3 id="다형성의-한계">다형성의 한계</h3>
<ul>
<li>역할(인터페이스) 자체가 변하면, 클라이언트/서버 모두에 큰 변경 발생</li>
<li>인터페이스를 안정적으로 잘 설계하는 것이 매우 중요!</li>
</ul>
<br>

<h2 id="3-spring과-객체-지향">3. Spring과 객체 지향</h2>
<ul>
<li><p>다형성이 가장 중요하다!</p>
<blockquote>
<p>&quot;객체지향의 꽃은 다형성이에요.&quot;</p>
</blockquote>
</li>
<li><p>스프링 컨테이너 : 다형성을 편리하게 사용할 수 있도록 지원하는 기능. 그것이 거의 전부임</p>
</li>
</ul>
<br>

<h2 id="4-객체지향과-solid-원칙">4. 객체지향과 SOLID 원칙</h2>
<p>Robert Martin이 정리한 좋은 객체 지향 설계의 5가지 원칙</p>
<h3 id="srp-single-reponsibility-principle">SRP (Single Reponsibility Principle)</h3>
<p><strong>단일 책임 원칙</strong></p>
<ul>
<li>한 클래스는 하나의 책임만 가져야 한다.</li>
<li>중요한 기준 : 변경<ul>
<li>변경이 있을 때 파급 효과가 적으면 단일 책임 원칙을 잘 따른 것</li>
<li>ex: 객체의 생성과 사용을 분리</li>
</ul>
</li>
</ul>
<br>

<h3 id="ocp-open-closed-principle">OCP (Open-Closed Principle)</h3>
<p><strong>개방-폐쇄 원칙</strong></p>
<blockquote>
<p>가장 중요한 원칙!</p>
</blockquote>
<ul>
<li>소프트웨어는 <strong>확장에는 열려있으나</strong>, <strong>변경에는 닫혀있어야</strong> 한다.</li>
<li>다형성을 활용해보자.<ul>
<li>인터페이스를 구현한 새로운 클래스 만드는 것 : 확장</li>
<li>인터페이스는 바뀌지 않는 것 : 변경에 닫혀있음</li>
</ul>
</li>
</ul>
<blockquote>
<p><strong>💡 문제점</strong></p>
<ul>
<li>분명히 다형성을 사용했지만, OCP 원칙을 지킬 수 없다.</li>
<li>기존 코드를 변경해야만 새로운 구현 클래스를 선택할 수 있게 된다.
👉🏻 <strong>객체를 생성하고, 연관관계를 맺어주는 별도의 조립, 설정자가 필요하다.</strong></li>
</ul>
</blockquote>
<br>

<h3 id="lsp-liskov-substitution-principle">LSP (Liskov Substitution Principle)</h3>
<p><strong>리스코프 치환 원칙</strong></p>
<ul>
<li><p>프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다.</p>
</li>
<li><p>단순히 컴파일에 성공하는 것을 넘어서는 이야기</p>
<ul>
<li>ex) 자동차 인터페이스의 엑셀 : 앞으로 가는 기능! 따라서 뒤로 가게 구현하면 LSP 위반. 속도와는 상관 없이 앞으로 가야 함!</li>
</ul>
</li>
</ul>
<br>

<h3 id="isp-interface-segregation-principle">ISP (Interface Segregation Principle)</h3>
<p><strong>인터페이스 분리 원칙</strong></p>
<ul>
<li>특정 클라이언트를 위한 인터페이스 여러 개가, 범용 인터페이스 하나보다 낫다.<ul>
<li>자동차 인터페이스 -&gt; 운전 인터페이스, 정비 인터페이스</li>
<li>사용자 클라이언트 -&gt; 운전자 클라이언트, 정비사 클라이언트</li>
</ul>
</li>
<li>인터페이스가 명확해지고, 대체 가능성이 높아진다.</li>
</ul>
<br>

<h3 id="dip-dependency-inversion-principle">DIP (Dependency Inversion Principle)</h3>
<p><strong>의존 관계 역전 원칙</strong></p>
<ul>
<li><strong>추상화에 의존</strong>해야지, <strong>구체화에 의존</strong>하면 안 된다.</li>
<li>구현 클래스에 의존하지 말고, 인터페이스에 의존하라는 뜻! 즉, <strong>역할(Role)에 의존</strong>하라! 구현체에 의존하게 되면, 변경이 아주 어려워진다.</li>
</ul>
<blockquote>
<p>💡 <strong>주의</strong>
MemeberService 클라이언트가 구현 클래스를 직접 선택하고 있음</p>
<pre><code class="language-java">MemberRepository m = new MemoryMemberRepository();</code></pre>
<p>👉🏻 <strong>DIP 위반!</strong></p>
<ul>
<li>MemberService는 MemberRepository 인터페이스만 의존하도록 설계해야 함</li>
</ul>
</blockquote>
<br>

<blockquote>
<p>💡 <strong>요약</strong></p>
</blockquote>
<ul>
<li>객체 지향의 핵심은 다형성</li>
<li>다형성만으로는 쉽게 부품을 갈아 끼우듯이 개발할 수는 없음</li>
<li>다형성만으로는 OCP, DIP를 지킬 수 없는 경우도 있다. 무언가 더 필요하다.</li>
</ul>
<br>

<h2 id="5-spring과-객체-지향-설계">5. Spring과 객체 지향 설계</h2>
<ul>
<li>OCP, DIP 원칙을 지키면서 개발을 하려다 보면, 구현해둘 것이 너무 많았음 → 아예 프레임워크로 만들어둠</li>
</ul>
<h3 id="할-것">할 것</h3>
<ul>
<li>모든 설계에 역할과 구현을 분리하자</li>
<li>이상적으로는 모든 설계에 인터페이스를 부여하자</li>
</ul>
<h3 id="실무-고민">실무 고민</h3>
<ul>
<li>인터페이스를 도입하면, 추상화라는 비용이 발생한다.</li>
<li>기능을 확장할 가능성이 없다면, 우선은 구체 클래스를 직접 사용하고, 향후 꼭 필요할 때 리팩토링해서 인터페이스를 도입하는 것도 방법!!</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] 스프링이란?]]></title>
            <link>https://velog.io/@sw_smj/Spring-%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B0%9C%EC%9A%94</link>
            <guid>https://velog.io/@sw_smj/Spring-%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B0%9C%EC%9A%94</guid>
            <pubDate>Mon, 10 Apr 2023 10:58:40 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>💡 스프링 제대로 공부하는 방법</strong></p>
</blockquote>
<ul>
<li>단순히 스프링 기능을 배우고 사용하는 것은 어렵지 않다</li>
<li>그러나 IoC, DI 등의 용어 및 SOLID 객체지향 설계 원칙도 이해해야 스프링의 진정한 핵심 가치를 알 수 있게 됨</li>
</ul>
<blockquote>
<p><strong>📌 스프링과 객체지향 프로그래밍</strong></p>
</blockquote>
<ul>
<li>스프링 컨테이너가 왜 필요할까?</li>
</ul>
<br>

<h2 id="1-spring의-탄생">1. Spring의 탄생</h2>
<h3 id="enterprise-java-beansejb">Enterprise Java Beans(EJB)</h3>
<p>: Java 진영의 표준 기술 중 최고봉</p>
<ul>
<li>당시에는 EJB가 보급도 잘 되고, 가장 잘 나갔었음</li>
<li>Container 기술, 설정에 의한 Transaction 관리, 분산 기술 등이 특징<ul>
<li>Entity Bean(ORM 기술)도 있었음</li>
</ul>
</li>
<li>단, 매우 비쌌고, 매우 복잡하고 어렵다는 단점이 있었음<ul>
<li>나중에는 옛날 자바 오브젝트로 돌아가자(POJO, Plain Old Java Object)라는 말까지 나왔음</li>
</ul>
</li>
</ul>
<blockquote>
<p>💡 <strong>ORM (Object Relational Mapping, 객체-관계-매핑)</strong>
: Java 객체를 쿼리를 사용하지 않고 DB에 편하게 CRUD할 수 있는 기술! </p>
</blockquote>
<br>

<h3 id="spring">Spring</h3>
<ul>
<li>Rod Johnson이 제안</li>
<li>EJB 컨테이너 대체 기술</li>
<li>단순함의 승리</li>
<li>현재 사실상 표준 기술</li>
</ul>
<h3 id="hibernate">Hibernate</h3>
<ul>
<li>Gavin King이 제안</li>
<li>EJB Entity Bean 기술 대체</li>
<li>JPA 표준에서, JPA (Java Persistence API)를 새로운 표준으로 정의</li>
</ul>
<h3 id="jpa와-구현체">JPA와 구현체</h3>
<ul>
<li>JPA : 표준 인터페이스</li>
<li>Hibernate, EclipseLink ... : JPA 구현체들</li>
</ul>
<br>

<h2 id="2-spring의-역사">2. Spring의 역사</h2>
<h3 id="탄생">탄생</h3>
<p><strong>| 2002년 : Rod Johnson이 책 출간</strong></p>
<ul>
<li>EJB의 문제점 지적</li>
<li>EJB 없이도 충분히 고품질의 확장 가능한 애플리케이션을 개발할 수 있음을 보여주고, 30,000라인 이상의 기반 기술을 예제 코드로 선보임 (지금의 스프링 핵심 개념과 기반 코드)</li>
<li>들어있는 개념들<ul>
<li>BeanFactory</li>
<li>ApplicationContext</li>
<li>POJO</li>
<li>제어의 역전</li>
<li>의존관계 주입</li>
</ul>
</li>
</ul>
<p><strong>| 책 출간 직후 오픈소스로 개발</strong>  </p>
<ul>
<li>Juergen Hoeller (유겐 휠러), Yahn Caroff(얀 카로프)가 로드 존슨에게 오픈소스 프로젝트를 제안</li>
<li>Spring의 핵심 코드의 상당수는 유겐 휠러가 지금도 개발 중</li>
<li>Spring : 전통적인 J2EE(EJB)라는 겨울을 넘어, 새로운 시작이라는 뜻</li>
</ul>
<h3 id="release">Release</h3>
<ul>
<li>2003 : Spring Framework 1.0 - XML</li>
<li>2006 : Spring Framework 2.0 - XML 편의 기능 지원</li>
<li>2009 : Spring Framework 3.0 - 자바 코드로 설정</li>
<li>2013 : Spring Framework 4.0 - 자바 8</li>
<li>2014 : Spring Boot 1.0 </li>
<li>2017 : Spring Framework 5.0, Spring Boot 2.0 - Reactive Programming 지원</li>
<li>2023 현재 : Spring 6.1.x, Spring Boot 3.1.x</li>
</ul>
<br>

<h2 id="3-spring이란">3. Spring이란?</h2>
<h3 id="spring-생태계">Spring 생태계</h3>
<ul>
<li>Spring Framework : 이 모든 것들 중 핵심</li>
<li>Spring Boot : 아래의 모든 기술들을 사용하기 편리하도록 도와주는 것</li>
<li>Spring Data : DBMS에서 CRUD를 편리하게 할 수 있도록 도와주는 기술. 가장 많이 쓰는 건 Spring Data JPA</li>
<li>Spring Session : 세션 기술을 편리하게 사용하도록 도와줌</li>
<li>Spring Security : 보안과 관련된 것</li>
<li>Spring Rest Docs : API 문서화를 편리하게 해주는 것</li>
<li>Spring Batch : 데이터를 대량으로 처리하기 위해, 단위를 나눠 배치처리를 하는 데에 특화된 기술</li>
<li>Spring Cloud : 클라우드 기술에 특화된 기술</li>
</ul>
<p><img src="https://velog.velcdn.com/images/sw_smj/post/ef18a6c8-2d44-4d09-af41-04448783b500/image.png" alt=""></p>
<h3 id="spring-framework">Spring Framework</h3>
<ul>
<li><strong>핵심 기술</strong><ul>
<li>Spring DI container</li>
<li>AOP</li>
<li>이벤트</li>
<li>etc<br><br></li>
</ul>
</li>
<li><strong>웹 기술</strong><ul>
<li>Spring MVC</li>
<li>Spring WebFlux<br><br></li>
</ul>
</li>
<li><strong>데이터 접근 기술</strong><ul>
<li>트랜잭션</li>
<li>JDBC</li>
<li>ORM 지원</li>
<li>XML 지원<br><br></li>
</ul>
</li>
<li><strong>기술 통합</strong><ul>
<li>캐시</li>
<li>이메일</li>
<li>원격 접근</li>
<li>스케줄링<br><br></li>
</ul>
</li>
<li><strong>테스트</strong><ul>
<li>스프링 기반 테스트 지원<br><br></li>
</ul>
</li>
<li><strong>언어</strong><ul>
<li>Kotlin</li>
<li>Groovy<br><br></li>
</ul>
</li>
</ul>
<h3 id="spring-boot">Spring Boot</h3>
<p>: 스프링을 편리하게 사용할 수 있도록 지원</p>
<ul>
<li>최근에는 기본으로 사용</li>
<li>단독으로 실행할 수 있는 스프링 애플리케이션을 쉽게 생성<ul>
<li>Tomcat 같은 웹 서버를 내장해서, 별도의 웹 서버를 설치하지 않아도 됨</li>
<li>손쉬운 빌드 구성을 위한 starter 종속성 제공</li>
<li>스프링과 3rd parth(외부) 라이브러리 자동 구성</li>
<li>메트릭, 상태 확인, 외부 구성 같은 프로덕션 준비 기능 제공</li>
</ul>
</li>
<li>관례에 의한 간결한 설정</li>
</ul>
<blockquote>
<p><strong>💡 Spring Boot는 Spring과 별개?</strong>
NO!!
Spring Boot는 Spring Framework를 꼭 사용하면서 사용이 편리하게 도와주는 기술임!</p>
</blockquote>
<br>

<h3 id="spring이라는-단어">Spring이라는 단어</h3>
<p>문맥에 따라 다르게 사용된다.</p>
<ul>
<li>Spring DI Container 기술</li>
<li>Spring Framework</li>
<li>Spring Boot, Spring Framework 등을 모두 포함한 스프링 생태계</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Effective Java] item 54 : null이 아닌, 빈 컬렉션이나 배열을 반환하라]]></title>
            <link>https://velog.io/@sw_smj/Effective-Java-item-54-null%EC%9D%B4-%EC%95%84%EB%8B%8C-%EB%B9%88-%EC%BB%AC%EB%A0%89%EC%85%98%EC%9D%B4%EB%82%98-%EB%B0%B0%EC%97%B4%EC%9D%84-%EB%B0%98%ED%99%98%ED%95%98%EB%9D%BC</link>
            <guid>https://velog.io/@sw_smj/Effective-Java-item-54-null%EC%9D%B4-%EC%95%84%EB%8B%8C-%EB%B9%88-%EC%BB%AC%EB%A0%89%EC%85%98%EC%9D%B4%EB%82%98-%EB%B0%B0%EC%97%B4%EC%9D%84-%EB%B0%98%ED%99%98%ED%95%98%EB%9D%BC</guid>
            <pubDate>Sun, 26 Mar 2023 02:32:34 GMT</pubDate>
            <description><![CDATA[<h2 id="null값-반환을-피해야-하는-이유">null값 반환을 피해야 하는 이유</h2>
<blockquote>
<p>💬 <strong>한 줄 요약</strong>
null을 반환하는 API는 사용하기 어렵고, 오류 처리 코드도 늘어난다. 성능이 더 좋은 것도 아니다.</p>
</blockquote>
<p>다음은 컬렉션이 비었다면 null을 반환하는 코드이다.</p>
<pre><code class="language-java">private final List&lt;Cheese&gt; chessesInStock = ...;

/**
* @return 매장 안의 모든 치즈 목록을 반환한다.
*         단, 재고가 하나도 없다면 null을 반환한다.
*/
public List&lt;Cheese&gt; getCheeses() {
    return cheesesInStock.isEmpty() ? null : new ArrayList&lt;&gt;(cheesesInStock);
}</code></pre>
<h3 id="클라이언트-입장">클라이언트 입장</h3>
<p>위와 같은 코드에서 만약 null값을 반환하게 된다면, 클라이언트는 이 null 상황을 처리하는 코드를 추가로 작성해야 한다.</p>
<p>ex)</p>
<pre><code class="language-java">List&lt;Cheese&gt; cheeses = shop.getCheeses();
if(cheeses != null &amp;&amp; cheeses.contains(Cheese.STILTON))
    System. out. printIn(&quot;좋았어, 바로 그거야广》;</code></pre>
<p>클라이언트에서 위와 같이 방어하는 코드를 항상 써야 하며, 이걸 빼먹으면 오류가 발생할 수 있따. 
실제 객체가 0개일 가능성이 거의 없는 상황에서는 (계속 방치되다가) 수년 뒤에야 오류가 발생하기도 한다.</p>
<h3 id="개발자">개발자</h3>
<p><strong>Collection</strong>
null을 반환하려면, 반환하는 쪽에서도 이 상황을 특별히 취급해줘야 해서 코드도 더 복잡해진다. 따라서 빈 컬렉션을 반환하자.</p>
<p><strong>배열</strong>
절대 null을 반환하지 말고, 다음과 같이 길이가 0인 배열을 반환하라. </p>
<pre><code class="language-java">public Cheese[] getCheeses {
    return cheesesInStock.toArray(new Cheese[0]);
}</code></pre>
<p>위의 방식이 성능을 떨어뜨릴 것 같다면, 길이 0짜리 배열을 미리 선언해두고 매번 그 배열을 반환하면 된다. <strong><em>길이 0인 배열은 모두 불변이기 때문!</em></strong></p>
<pre><code class="language-java">public static final Cheese[] EMPTY_CHEESE_ARRAY = new Cheese[0];

public Cheese[] getCheeses {
    return cheesesInStock.toArray(EMPTY_CHEESE_ARRAY);
}</code></pre>
<p>단순히 성능을 개선할 목적이라면 다음과 같이 toArray에 넘기는 배열을 미리 할당하는 건 추천하지 않는다. 오히려 성능이 떨어진다는 연구 결과가 있다.</p>
<pre><code class="language-java">return cheesesInStock.toArray(new Cheese[cheesesInStock.size()]);</code></pre>
<blockquote>
</blockquote>
<br>

<h2 id="반박-의견--빈-컨테이너를-할당하는-데에도-비용이-드니-null-반환이-낫다">반박 의견 : 빈 컨테이너를 할당하는 데에도 비용이 드니, null 반환이 낫다!</h2>
<p>👉🏻 이는 두 가지 면에서 틀린 주장이다.</p>
<h3 id="1-성능-차이-거의-없음">1. 성능 차이 거의 없음</h3>
<p>성능 분석 결과 이 할당이 성능 저하의 주범이라고 확인되지 않는 한, 이 정도의 성능 차이는 신경 쓸 수준이 못 된다.</p>
<h4 id="확실한-해법">확실한 해법</h4>
<p>단, 작은 가능성으로 사용 패턴에 따라 빈 컬렉션 할당이 성능을 눈에 띄게 떨어뜨릴 수도 있다. 이는 다행히 <strong>매번 똑같인 빈 &#39;불변&#39; 컬렉션을 반환하는 것</strong>으로 간단히 해결이 가능하다. 알다시피 불변 객체는 자유롭게 공유해도 안전하다.</p>
<ul>
<li>Collections.emptySet</li>
<li>Collections.emptyMap</li>
</ul>
<p>단, 이 역시 최적화에 해당되니 꼭 필요할 때에만 사용하자. 그리고 최적화가 필요하다고 판단되면, 수정 전과 후의 성능을 측정하여 실제로 성능이 개선되는지 꼭 확인하자.</p>
<pre><code class="language-java">public List&lt;Cheese&gt; getCheeses() {
    return cheesesInStock.isEmpty() ? Collections.emptyList() : new ArrayList&lt;&gt; (cheesesInStock);
}</code></pre>
<h3 id="2-빈-컬렉션과-배열은-굳이-새로-할당하지-않고도-반환할-수-있다">2. 빈 컬렉션과 배열은 굳이 새로 할당하지 않고도 반환할 수 있다.</h3>
<p>대부분의 상황에서는 아래와 같이 하면 된다.</p>
<pre><code class="language-java">public List&lt;Cheese&gt; getCheeses() {
    return new ArrayList&lt;&gt;(cheesesInStock)
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Effective Java] item 49 : 매개변수가 유효한지 검사하라]]></title>
            <link>https://velog.io/@sw_smj/Effective-Java-item-49-%EB%A7%A4%EA%B0%9C%EB%B3%80%EC%88%98%EA%B0%80-%EC%9C%A0%ED%9A%A8%ED%95%9C%EC%A7%80-%EA%B2%80%EC%82%AC%ED%95%98%EB%9D%BC</link>
            <guid>https://velog.io/@sw_smj/Effective-Java-item-49-%EB%A7%A4%EA%B0%9C%EB%B3%80%EC%88%98%EA%B0%80-%EC%9C%A0%ED%9A%A8%ED%95%9C%EC%A7%80-%EA%B2%80%EC%82%AC%ED%95%98%EB%9D%BC</guid>
            <pubDate>Mon, 20 Mar 2023 09:21:43 GMT</pubDate>
            <description><![CDATA[<h2 id="매개변수의-유효성-검사">매개변수의 유효성 검사</h2>
<ul>
<li>메서드와 생성자 대부분은 입력 매개변수의 값이 특정 조건을 만족하기를 바람</li>
<li>제약사항은 반드시 문서화해야 함</li>
<li><strong>메서드 몸체가 시작되기 전에 검사해야 함</strong></li>
<li>&quot;오류는 가능한 한 빨리 (발생한 곳에서) 잡아야 한다&quot;는 일반 원칙</li>
</ul>
<br>

<h3 id="📌-제약사항은-반드시-문서화해야-함">📌 제약사항은 반드시 문서화해야 함</h3>
<ul>
<li>특히, public, protected 메서드는 매개변수 값이 잘못되었을 때 던지는 예외는 문서화해야 함</li>
<li><code>@throws</code> 자바독 태그 사용하여 정리</li>
<li>보통은 IllegalArgumentException, IndexOutOfBoundsException, NullPointerException 중 하나</li>
<li>매개변수의 제약을 문서화하면 그 제약을 어겼을 때 발생하는 예외도 함께 기술해야 함</li>
</ul>
<pre><code class="language-java">/**
* (현재 값 mod m) 값을 반환한다. 이 메서드는 항상 음이 아닌 Biginteger률 반환하다는 점에서 remainder 메서드와 다르다.
*
* @param m 계수(양수여야 한다.)
* @return 현재 값 mod m
* @throws ArithmeticException mo| 0보다 작거나 같으면 발생한다.
*/
public Biginteger mod(Biginteger m) {
if (m.signum() &lt;= 0)
throw new ArithmeticException (&quot;계수 (m)는 양수여야 합니다. &quot; + m);
... // 계산 수행
}</code></pre>
<ul>
<li>이 메서드는 m이 <code>null</code>이면 m.signum() 호출 때 <code>NullPointerException</code>을 던진다. 그런데 “m이 <code>null</code>일 때 <code>NullPointerException</code>을 던진다”라는 말은 메서드 설명 어디에도 없다.</li>
<li>이 설명을 (개별 메서드가 아닌) Biginteger 클래스 수준에서 기술했기 때문</li>
</ul>
<p><strong>클래스 수준 주석이 필요한 이유</strong></p>
<ul>
<li>클래스 수준 주석은 그 클래스의 모든 public 메서드에 적용되므로 각 메서드에 일일이 기술하는 것보다 훨씬 깔끔한 방법</li>
</ul>
<br>

<h3 id="📌-메서드-몸체가-시작되기-전에-검사해야-함">📌 메서드 몸체가 시작되기 전에 검사해야 함</h3>
<ul>
<li>잘못된 값이 넘어왔을 때 즉각적이고 깔끔한 방식으로 예외를 던질 수 있음</li>
</ul>
<p><strong>이게 안 될 경우</strong></p>
<ul>
<li><p>메서드 수행 중간에 모호한 예외를 던지며 실패할 수 있음.</p>
</li>
<li><p>더 최악은, 메서드는 문제 없이 수행되었지만 어떤 객체를 이상한 상태로 만들어두어서, 미래의 알 수 없는 시점에 관련 없는 오류를 발생시킬 수 있음.</p>
</li>
<li><p>즉, 매개변수 검사에 실패하면 <strong>failure atomicity(실패 원자성)</strong>을 어기는 결과를 낳을 수 있음!</p>
</li>
<li><p>예외는 있다. 유효성 검사 비용이 지나치게 높거나 실용적이지 않을 때, 혹은 계산과정에서 암묵적으로 검사가 수행될 때 등이 있음</p>
<ul>
<li>ex) Collections.sort(List) - 리스트 안의 객체들은 모두 상호 비교할 수 있어야 하며, 정렬 과정에서 이 비교가 이루어짐</li>
<li>만약 상호 비교될 수 없는 타입의 객체가 들어있다면, 그 객체와 비교할 때 ClassCastException을 던짐
=&gt; 이럴 경우, 비교하기에 앞서 리스트 안의 모든 객체가 상호 비교될 수 있는지 검사해보는 것보다는 버리는 게 나음<blockquote>
<p>하지만, 암묵적 유효성 검사에 너무 의존했다가는 실패 원자성을 해칠 수 있으니 주의!</p>
</blockquote>
</li>
</ul>
</li>
</ul>
<br>

<h3 id="📌-오류는-가능한-한-빨리-발생한-곳에서-잡아야-한다">📌 오류는 가능한 한 빨리 (발생한 곳에서) 잡아야 한다</h3>
<ul>
<li>오류를 발생한 즉시 잡지 못하면 해당 오류를 감지하기 어려워지고, 감지하더라도 오류의 발생 지점을 찾기 어려워지기 때문</li>
</ul>
<br>

<h2 id="기본적인-유효성-검사들">기본적인 유효성 검사들</h2>
<h3 id="null-검사"><strong>Null 검사</strong></h3>
<ul>
<li><p><code>@Nullable</code>이나 이와 비슷한 애너테이션을 사용해 특정 매개변수는 <code>null</code>이 될 수 있다고 알려줄 수도 있지만，표준적인 방법은 아니다. 그리고 같은 목적으로 사용할 수 있는 애너테이션도 여러 가지다</p>
</li>
<li><p>자바 7에 추가된 <code>java.util.Objects.requireNonNull</code> 메서드는 유연하고 사용하기도 편하니，더 이상 null 검사를 수동으로 하지 않아도 된다. 원하는 예외 메시지도 지정할 수 있다. 또한 입력을 그대로 반환하므로 값을 사용하는 동시에 null 검사를 수행할 수 있다.</p>
<pre><code class="language-java">this.strategy = Objects.requireNonNull(strategy, &quot;전략&quot;);</code></pre>
<ul>
<li>반환값은 그냥 무시하고 필요한 곳 어디서든 순수한 null 검사 목적으로 사용
해도 됨</li>
</ul>
</li>
</ul>
<br>

<h3 id="범위-검사">범위 검사</h3>
<p>Objects의 <code>checkFromlndexSize</code>, <code>checkFromToIndex</code>, <code>checkindex</code>라는 메서드들을 사용하면 됨 (null 검사 메서드만큼 유연하지는 않음)</p>
<p><strong>한계들</strong></p>
<ul>
<li>예외 메시지를 지정할 수 없고，리스트와 배열 전용으로 설계됐다.</li>
<li>닫힌 범위 (closed range； 양 끝단 값을 포함하는)는 다루지 못한다.</li>
</ul>
<p>그래도 이런 제약이 걸림돌이 되지 않는 상황에서는 아주 유용하고 편하다</p>
<br>

<h3 id="assert을-사용한-유효성-검사"><strong>assert을 사용한 유효성 검사</strong></h3>
<ul>
<li>public이 아닌 메서드라면 단언문(assert)을 사용해 매개변수 유효성을 검증할 수 있다.</li>
</ul>
<pre><code class="language-java">private static void sort(long a[], int offset, int length) {
  assert a != null;
  assert offset &gt;= 0 &amp;&amp; offset &lt;= a.length;
  assert length &gt;= 0 &amp;&amp; length &lt;= a.length - offset;
... // 계산 수행
}</code></pre>
<ul>
<li>여기서의 핵심은 이 단언문들은 자신이 단언한 조건이 무조건 참이라고 선언한다는 것</li>
<li>이 메서드가 포함된 패키지를 클라이언트가 어떤 식으로 지지고 볶든 상관없다. </li>
</ul>
<p><strong>유의사항</strong>
단언문은 몇 가지 면에서 일반적인 유효성 검사와 다르다. </p>
<ol>
<li>실패하면 AssertionError를 던진다. </li>
<li>두 번째, 런타임에 아무런 효과도, 아무런 성능 저하도 없다(단，java를 실행할 때 명령줄에서 -ea 혹은 --enableassertions 플래그 설정하면 런타임에 영향을 준다).💬</li>
</ol>
<br>

<h3 id="📌-나중에-쓰려고-저장하는-매개변수의-유효성을-검사하라">📌 “나중에 쓰려고 저장하는 매개변수의 유효성을 검사하라”</h3>
<ul>
<li>이들은 특히 더 신경써서 검사해야 함</li>
<li>메서드가 유효하지 않은 값을 돌려주고, 나중에 그 인스턴스를 사용하려면 비로소 NullPointerException이 발생함</li>
<li>이 때가 되면 이 List를 어디서 가져왔는지 추적하기 어려워 디버깅이 상당히 괴로워질 수 있다.</li>
</ul>
<p><strong>생성자의 유효성 검사</strong></p>
<blockquote>
<p>생성자는 “나중에 쓰려고 저장하는 매개변수의 유효성을 검사하라”는 원칙의 특수한 사례</p>
</blockquote>
<ul>
<li>클래스 불변식을 어기는 객체가 만들어지지 않게 하는 데 꼭 필요함</li>
</ul>
<br>

<h3 id="📌-계산-중-잘못된-매개변수-값을-사용해-발생한-예외와-api-문서에서-던지기로-한-예외가-다를-수-있음">📌 계산 중 잘못된 매개변수 값을 사용해 발생한 예외와 API 문서에서 던지기로 한 예외가 다를 수 있음</h3>
<ul>
<li>이럴 경우, 예외 번역(exception translate) 관용구를 사용하여 API 문서에 기재된 예외로 번역해줘야 함</li>
</ul>
<h3 id="📌-매개변수에-제약을-두는-게-좋다">📌 매개변수에 제약을 두는 게 좋다?</h3>
<p>-&gt; NO!</p>
<ul>
<li><p>메서드는 최대한 범용적으로 설계해야 함</p>
</li>
<li><p>메서드가 건네받은 값으로 무언가 제대로 된 일을 할 수 있다면, 매개변수 제약은 적을수록 좋다.</p>
</li>
<li><p>단, 구현하려는 개념 자체가 특정한 제약을 내재한 경우도 드물지 않다!</p>
</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>