<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>jay_k56.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Wed, 29 May 2024 13:18:42 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. jay_k56.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/jay_k56" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Spring] @Transactional의 rollback과 주의점]]></title>
            <link>https://velog.io/@jay_k56/Spring-Transactional%EC%9D%98-rollback%EA%B3%BC-%EC%A3%BC%EC%9D%98%EC%A0%90</link>
            <guid>https://velog.io/@jay_k56/Spring-Transactional%EC%9D%98-rollback%EA%B3%BC-%EC%A3%BC%EC%9D%98%EC%A0%90</guid>
            <pubDate>Wed, 29 May 2024 13:18:42 GMT</pubDate>
            <description><![CDATA[<h1 id="📖-transaction이란">📖 Transaction이란??</h1>
<p>트랜잭션이란 간단히 말해,</p>
<blockquote>
<p>데이터베이스의 상태를 변환시키는 하나의 논리적 기능을 수행하기 위한 작업의 단위 또는 한꺼번에 모두 수행되어야 할 일련의 연산</p>
</blockquote>
<p>을 뜻한다.</p>
<p>예를 들자면, 100만원을 계좌이체를 할 때 아래와 같이 2가지 작업으로 나눌 수 있는데,
<strong>1. A계좌에서 돈을 빼내는 작업 (-100만원)
2. B계좌에 돈을 넣는 작업 (+100만원)</strong></p>
<p>만약 1번 작업은 실행이 되었지만 2번 작업에서 오류가 발생했을 때, 1번 작업을 다시 되돌리지 않으면, 그냥 100만원이 사라지는 결과를 낳게된다.</p>
<h3 id="이와-같이-반드시-한꺼번에-수행되어야-하는-연산을-뜻하는-것이-트랜잭션이다">이와 같이 반드시 한꺼번에 수행되어야 하는 연산을 뜻하는 것이 트랜잭션이다.</h3>
<hr>
<h1 id="❗️-transactional-사용-시-주의점">❗️ @Transactional 사용 시 주의점</h1>
<p>Spring에서는 @Transactional 어노테이션을 사용하여 특정 메소드에 트랜잭션을 걸 수 있다.
@Transactional을 사용할 때, 몇가지 주의해야할 점이 있는데,</p>
<h2 id="📍-transactional의-rollbackfor-속성">📍 @Transactional의 rollbackFor 속성</h2>
<p>@Trasactional 어노테이션은 기본 적으로 RuntimeException과 Error에 대하여 Rollback처리를 하도록 되어 있다.
때문에, @Transactional의 rollbackFor 속성의 기본값은 RuntimeException.class, Error.class 로 되어 있다.</p>
<pre><code class="language-java">@Transactional
public void publicMethod() {}</code></pre>
<pre><code class="language-java">@Transactional(rollbackFor = {RuntimeException.class, Error.class})
public void publicMethod() {}</code></pre>
<p><strong>그렇기 때문에 @Transactional만 적용하게 되면, 동작 중 발생되는 오류에 대해서는 Rollback처리가 되지 않는다.</strong>
왜냐하냐...!
동작 중 발생되는 오류는 대부분 Exception.class를 상속받는 예외 클래스인데, RuntimeException.class, Error.class는 Exception.class를 상속받는 클래스가 아니기 때문이다.
때문에 동작 중 발생되는 오류를 잡아서 Rollback을 시키고 싶다면 아래와 같이 rollbackFor 속성을 적용해야한다.</p>
<pre><code class="language-java">@Transactional(rollbackFor = {Exception.class})
public void publicMethod() {}</code></pre>
<h3 id="❓-만약-trycatch-구문을-사용하면-rollback처리가-될까">❓ 만약 try/catch 구문을 사용하면 Rollback처리가 될까?</h3>
<p>어떻게 쓰냐에 따라 다르다</p>
<h4 id="case-1">Case 1</h4>
<pre><code class="language-java">/*
 * (Rollback 안되는 case)
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ExServiceClass {
    private final ExRepo exRepo;

    @Transactional(rollbackFor = {Exception.class})
    public void publicMethod() {
        try {
            exRepo.doSomething();

        } catch (Exception e) {
            log.error(e.getMessage());

        }
    }
}</code></pre>
<p>위의 경우, doSomething()에서 에러 발생 시에도 <strong>Rollback 되지 않는다!!</strong>
위의 코드는 <em>catch절에서 예외처리를 모두 끝냈으니까 신경쓰지마~</em> 라는 말과 동일하다.
때문에 try/catch 절 바깥 부분에서는 예외에 대해 신경쓰지 않기 때문에 Rollback이 동작되지 않는다.</p>
<h4 id="case-2">Case 2</h4>
<pre><code class="language-java">/*
 * (Rollback 되는 case)
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ExServiceClass {
    private final ExRepo exRepo;

    @Transactional(rollbackFor = {Exception.class})
    public void publicMethod() {
        try {
            exRepo.doSomething();

        } catch (Exception e) {
            log.error(e.getMessage());
            throw e;

        }
    }
}</code></pre>
<p>위의 경우에는 doSomething()에서 에러 발생 시 <strong>Rollback이 된다!!!</strong>
catch 구문에서 예외 처리를 try/catch 구문 바깥으로 다시 넘겼기 때문이다.</p>
<h2 id="📍-transactional-메소드-셀프-호출">📍 @Transactional 메소드 셀프 호출</h2>
<p>다음은 아는 사람은 안다는 바로 그 <strong>@Trasactional 메소드 셀프 호출</strong> 이다.
사실,,,&#39;메소드 셀프 호출&#39; 이라는 말은 그냥 방금 내가 만든 말이다...(이걸 뭐라고 설명해야될지 모르겠어서..🤦‍♂️)
풀어서 말하자면, @Transactional가 적용된 메소드를 같은 클래스에서 호출하는걸 뜻한다.
결론부터 말하면,</p>
<blockquote>
<p><strong>@Transactional가 적용된 메소드를 같은 클래스에서 호출하면 안된다!!</strong></p>
</blockquote>
<pre><code class="language-java">/*
 * (Rollback 안되는 case)
 */
@Service
@RequiredArgsConstructor
public class ExService {
    private final ExRepo exRepo;

    public void publicMethod() {
        this.privateMethod();

    }

    @Transactional(rollbackFor = {Exception.class})
    private void privateMethod() {
        exRepo.doSomething();

    }</code></pre>
<p>이 경우에는 의도와는 다르게 privateMethod()에 트랜잭션 적용이 되지 않고, 무시한다.
(IntelliJ에서는 &#39;private&#39; 부분에 빨간줄을 그어주기 때문에, 아마 IntelliJ를 사용하는 사람이라면 알거다)</p>
<h3 id="❓-그러면-메소드를-public으로만-바꾸면">❓ 그러면 메소드를 public으로만 바꾸면??</h3>
<pre><code class="language-java">/*
 * (Rollback 안되는 case)
 * public으로 바꿔도 실행 주체가 같은 객체라면 안된다.
 */
@Service
@RequiredArgsConstructor
public class ExService {
    private final ExRepo exRepo;

    public void publicMethod() {
        this.privateMethod();

    }

    @Transactional(rollbackFor = {Exception.class})
    public void privateMethod() {
        exRepo.doSomething();

    }</code></pre>
<p>안된다.(단호)
이제 이유를 설명해보겠다.</p>
<p>Spring은 AOP를 사용해서 @Transactional 어노테이션을 처리한다.
Spring은 기본적으로 AOP할 때, proxy 패턴을 사용하기 때문에, 이 과정에서 동적으로 해당 클래스를 프록시 객체로 생성하고, 생성된 프로시 객체를 원래의 Bean 객체를 대신해서 호출하게된다.
때문에 클래스 내부에서 호출하게되면 외부에서 접근하여 프록시 객체를 생성할 수 없게 되는 것이다.
이 경우를 많이 놓치는 이유가 Spring에서 에러를 발생시키지 않고, 그냥 무시하고 실행하기 때문이다.</p>
<h3 id="❓-그러면-transactional이-걸려있는-public-메소드에서-private-메소드를-실행하면">❓ 그러면 @Transactional이 걸려있는 public 메소드에서 private 메소드를 실행하면??</h3>
<pre><code class="language-java">/*
 * (Rollback 되는 case)
 */
@Service
@RequiredArgsConstructor
public class ExService {
    private final ExRepo exRepo;

    @Transactional(rollbackFor = {Exception.class})
    public void publicMethod() {
        this.privateMethod();

    }

    public void privateMethod() {
        exRepo.doSomething();

    }</code></pre>
<p>된다!
위의 설명과 동일하다. publicMethod()를 실행할 때, 이미 프록시 객체를 생성했기 때문이다.
때문에, exRepo.doSomething()에서 오류가 발생하더라도 publicMethod()의 트랜잭션에 걸리게 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[IntelliJ] Terminal 툴 변경 방법]]></title>
            <link>https://velog.io/@jay_k56/IntelliJ-Terminal-%ED%88%B4-%EB%B3%80%EA%B2%BD-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@jay_k56/IntelliJ-Terminal-%ED%88%B4-%EB%B3%80%EA%B2%BD-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Fri, 10 Nov 2023 01:44:20 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/jay_k56/post/33ecd8ee-87d3-42a8-a1e5-1d06e93013ae/image.png" alt=""></p>
<p>윈도우 환경에서 Terminal을 사용하는 경우, 사용할 수 있는 명령어가 제한적이라 불편한 점이 많다.
이럴 때, Git에서 사용하는 Git bash를 사용하면 리눅스 환경에서 사용하는 명령어 들을 윈도우 환경에서도 사용할 수 있게 되어 편리하다.</p>
<blockquote>
<p>[윈도우 기본 CMD] - ls 명령어도 사용 못한다..</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jay_k56/post/ffe93282-6886-40f2-b00e-2fbb69d3ba29/image.png" alt=""></p>
<blockquote>
<p>[Git bash] - ls 명령어 사용 잘된다</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jay_k56/post/e6a5eca4-35f4-4d0c-b63e-a7ece13f52ff/image.png" alt=""></p>
<p><strong>IntelliJ 툴에서 Terminal을 사용할 때도 마찬가지이기 때문에, IntelliJ에서 Git bash를 사용하는 방법을 알아보자</strong></p>
<p>시작하기에 앞서 Git을 설치하여 Git bash가 설치되어 있어야한다.
<a href="https://git-scm.com/downloads">https://git-scm.com/downloads</a></p>
<p>Git이 설치가 되었다면,</p>
<p>1) IntelliJ에서 <code>Settings</code> 창을 연다.
2) <code>Settings</code> 창에서 <code>terminal</code> 키워드를 검색해서 <code>Tools &gt; Terminal</code> 항목으로 이동한다.
3) <code>Application Settings &gt; Shell path</code> 항목에 Git이 설치된 경로의 <code>bin/sh.exe</code> 파일을 선택한다.
4) 그 뒤에 <code>-login -i</code> 를 추가로 입력해준다.</p>
<p><img src="https://velog.velcdn.com/images/jay_k56/post/35b38bab-0d12-4d01-9b6b-f38fd109c305/image.png" alt=""></p>
<p>끝.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JUnit Annotation]]></title>
            <link>https://velog.io/@jay_k56/JUnit-Annotation</link>
            <guid>https://velog.io/@jay_k56/JUnit-Annotation</guid>
            <pubDate>Tue, 25 Jul 2023 13:06:01 GMT</pubDate>
            <description><![CDATA[<h1 id="junit5-lifecycle-annotation">JUnit5 LifeCycle Annotation</h1>
<blockquote>
<p>JUnit5는 아래와 같은 Test LifeCycle을 갖는다.</p>
</blockquote>
<h2 id="test">@Test</h2>
<ul>
<li>테스트 용 메소드를 표현하는 어노테이션<h2 id="beforeeach">@BeforeEach</h2>
</li>
<li>각 테스트 메소드가 시작되기 전에 실행되어야 하는 메소드를 표현하는 어노테이션<h2 id="aftereach">@AfterEach</h2>
</li>
<li>각 테스트 메소드가 시작된 후 실행되어야 하는 메소드를 표현하는 어노테이션<h2 id="beforeall">@BeforeAll</h2>
</li>
<li>테스트 시작 전에 실행되어야 하는 메소드를 표현</li>
<li>static 처리가 필요함<h2 id="afterall">@AfterAll</h2>
</li>
<li>테스트 종료 후에 실행되어야 하는 메소드를 표현</li>
<li>static 처리가 필요함</li>
</ul>
<h1 id="junit-main-annotation">JUnit Main Annotation</h1>
<h2 id="springboottest">@SpringBootTest</h2>
<ul>
<li>통합 테스트 용도로 사용됨 (때문에 단위 테스트에서 사용하기에는 부적합함)</li>
<li>@SpringBootApplication 어노테이션을 찾아, 하위의 모든 Bean을 스캔하여 로드함</li>
<li>Bean 스캔 및 로드 후 Test용 Application Context를 만들어 Bean을 추가하고, MockBean을 찾아 교체함<h2 id="extendwith">@ExtendWith</h2>
</li>
<li>JUnit4에서 @RunWith로 사용되던 어노테이션이 JUnit5에서는 ExtendWith로 변경됨</li>
<li>@ExtendWith 어노테이션으로 메인으로 실행될 Class를 지정할 수 있음</li>
<li>@SpringBootTest에는 @ExtendWith이 포함되어 있음<h2 id="webmvctestclass명class">@WebMvcTest(Class명.class)</h2>
</li>
<li>파라미터로 작성된 클래스만 실제로 로드하여 테스트를 진행</li>
<li>파라미터를 지정해주지 않으면, @Controller @RestController @RestControllerAdvice 등 컨트롤러와 연관된 Bean을 전부 로드함</li>
<li>컨트롤러 관련 코드만 테스트할 경우 사용<h2 id="autowired-mockbean용">@Autowired (Mockbean용)</h2>
</li>
<li>Controller의 API를 테스트하는 용도인 MockMvc 객체를 주입 받음</li>
<li>여러 메소드를 사용하여 컨트롤러 동작을 확인할 수 있음<ul>
<li>perform(), andExpect(), andDo(), andReturn()<h2 id="mockbean">@MockBean</h2>
</li>
</ul>
</li>
<li>테스트할 클래스에서 주입받고 있는 객체에 대해 가짜 객체를 생성해주는 어노테이션</li>
<li>해당 객체는 실제 행위를 하지 않음</li>
<li>given() 메소드를 활용하여 가짜 객체의 동작에 대해 정의하여 사용할 수 있음<h2 id="autoconfiguremockmvc">@AutoConfigureMockMvc</h2>
</li>
<li>spring.test.mockmvc의 설정을 로드하면서 MockMvc의 의존성을 자동으로 주입</li>
<li>MockMvc클래스는 REST API 테스트를 할 수 있는 클래스<h2 id="import">@Import</h2>
</li>
<li>필요한 Class들을 Configuration으로 만들어 사용할 수 있음</li>
<li>Configuration Component 클래스도 의존성 설정할 수 있음</li>
<li>Import된 클래스는 주입으로 사용 가능</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[TDD]]></title>
            <link>https://velog.io/@jay_k56/TDD</link>
            <guid>https://velog.io/@jay_k56/TDD</guid>
            <pubDate>Mon, 24 Jul 2023 13:21:51 GMT</pubDate>
            <description><![CDATA[<h2 id="tdd-란">TDD 란?</h2>
<ul>
<li>테스트 주도 개발(Test Driven Development) 이라는 의미</li>
<li>단순하게 <strong>테스트를 먼저 설계 및 구축 후</strong> 테스트를 통과할 수 있는 코드를 짜는 것</li>
<li>애자일(Agile) 개발 방식 중 하나<ul>
<li>코드 설계 시 원하는 단계적 목표에 대해 설정하여 진행하고자 하는 것에 대한 결정 방향의 갭을 줄이고자 함</li>
<li>최초 목표에 맞춘 테스트를 구축하여, 그에 맞게 코드를 설계하기 때문에 보다 적은 의견 충돌을 기대할 수 있음</li>
</ul>
</li>
</ul>
<h2 id="테스트-코드의-작성-목적">테스트 코드의 작성 목적</h2>
<ul>
<li>코드의 안정성을 높일 수 있음</li>
<li>기능을 추가하거나 변경하는 과정에서 발생할 수 있는 Side-Effect를 줄일 수 있음</li>
<li>해당 코드가 작성된 목적을 명확하게 표현할 수 있음<ul>
<li>테스트 코드는 동작 코드의 설계 도면과 같기 때문</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[JAR, WAR, EAR  차이]]></title>
            <link>https://velog.io/@jay_k56/JAR-WAR-EAR-%EC%B0%A8%EC%9D%B4</link>
            <guid>https://velog.io/@jay_k56/JAR-WAR-EAR-%EC%B0%A8%EC%9D%B4</guid>
            <pubDate>Tue, 11 Jul 2023 13:38:43 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/jay_k56/post/bc9aab76-1c57-4478-bd5b-90899b3b8569/image.png" alt=""></p>
<h2 id="jar">JAR</h2>
<ul>
<li>Java Application Resource / Java Application Archive의 약자</li>
<li>JAR 파일은 Java 어플리케이션과 관련된 class 파일, meta-data, resource 파일 등을 하나의 압축 파일로 묶은 것을 말한다.</li>
<li>JAR 파일은 Java Library를 포함할 수 있어, 재사용 가능한 코드 모듈을 효율적으로 관리할 수 있다.</li>
<li>개발자가 개발하기 위해 필요한 기능을 압축한 것을 JAR 파일로 주로 사용한다.</li>
</ul>
<h2 id="war">WAR</h2>
<ul>
<li>Web Application Resource / Web Application Archive의 약자</li>
<li>WAR 파일은 웹 어플리케이션과 관련된 파일 들을 하나의 압축 파일로 묶은 것을 말한다.</li>
<li>JSP, Servlet, class파일, XML 설정 파일, 웹 리소스 등 웹 어플리케이션 구성 요소를 포함한다.</li>
</ul>
<h2 id="ear">EAR</h2>
<ul>
<li>Enterprise Application Resource / Enterprise Application Archive의 약자</li>
<li>EAR 파일은 Java 기반의 엔터프라이즈 어플리케이션을 패키징하는데 사용되는 파일 형식이다.</li>
<li>EAR 파일은 웹 어플리케이션(WAR파일), EJB(Enterprise Java Bean) 모듈, Java 어플리케이션 (JAR파일) 및 관련 리소스를 포함하며, 이 들은 각각 서로 다른 계층의 구성 요소를 나타낸다.</li>
<li>EAR 파일을 사용하면 여러 모듈과 리소스가 포함된 대규모 엔터프라이즈 어플리케이션을 하나의 파일로 통합하여 배포하고 관리할 수 있다.</li>
</ul>
<p>[참고] (<a href="https://yozm.wishket.com/magazine/detail/1979/">https://yozm.wishket.com/magazine/detail/1979/</a>)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JDK, JRE 이 뭘까?]]></title>
            <link>https://velog.io/@jay_k56/JDK-JRE%EC%9D%B4-%EB%AD%98%EA%B9%8C</link>
            <guid>https://velog.io/@jay_k56/JDK-JRE%EC%9D%B4-%EB%AD%98%EA%B9%8C</guid>
            <pubDate>Tue, 11 Jul 2023 12:58:13 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/jay_k56/post/cf28cd73-4e28-4294-877b-0f730a9b165d/image.png" alt=""></p>
<h2 id="jdk란">JDK란?</h2>
<ul>
<li>Java Development Kit의 약자</li>
<li>Java 언어를 사용하여 프로그램을 개발하기 위한 도구 모음</li>
<li>JDK는 JRE와 JVM을 포함하며, 컴파일러(javac), 디버거, Java Library, 문서 생성 도구(javadoc) 등을 포함한다.</li>
<li>때문에 개발자는 JDK를 사용하여 자바 프로그램 작성, 컴파일, 테스트 및 디버깅할 수 있다.</li>
</ul>
<h2 id="jre란">JRE란?</h2>
<ul>
<li>Java Runtime Environment의 약자</li>
<li>Java 프로그램을 실행하기 위한 환경을 제공한다.</li>
<li>JRE는 JVM과 Java Class Library로 구성되어 있으며, 사용자는 JRE를 통해 Java 어플리케이션을 실행할 수 있다.</li>
<li>JRE는 개발이 아닌 실행을 위한 환경을 제공하기 때문에 개발 도구는 포함하지 않는다.</li>
</ul>
<p>[참고] (<a href="https://yozm.wishket.com/magazine/detail/1979/">https://yozm.wishket.com/magazine/detail/1979/</a>)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JVM이란?]]></title>
            <link>https://velog.io/@jay_k56/JVM%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@jay_k56/JVM%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Tue, 11 Jul 2023 12:53:09 GMT</pubDate>
            <description><![CDATA[<h2 id="jvm이란">JVM이란?</h2>
<ul>
<li>JVM은 Java Virtual Machine의 약자</li>
<li>Java로 작성된 프로그램을 실행하는데 사용되는 가상 머신이다.</li>
<li>JVM은 Java 코드를 바이트 코드로 변환하고, 이 바이트 코드를 운영체제에 상관 없이 실행할 수 있게 해준다.
<img src="https://velog.velcdn.com/images/jay_k56/post/b3b760a8-e87b-4c35-958e-9e34e937982e/image.png" alt=""></li>
</ul>
<h2 id="jvm의-장점">JVM의 장점</h2>
<p>1) 플랫폼에 독립적</p>
<ul>
<li>JVM은 Java 실행 환경이 설치된 모든 운영체제에서 실행이 가능하기 때문에 Java 프로그램은 운영체제에 관계 없이 실행이 가능하다.</li>
</ul>
<p>2) 메모리 관리</p>
<ul>
<li>JVM의 Garbage Collection을 통해 메모리 관리를 수행하기 때문에 개발자가 메모리를 직접 관리하지 않아도 된다.</li>
</ul>
<h2 id="jvm의-단점">JVM의 단점</h2>
<p>1) 느린 실행 속도</p>
<ul>
<li>JVM을 사용하면 바이트 코드로 변환하는 작업이 필요하기 때문에 다른 네이티브 코드에 비해 상대적으로 느린 실행 속도를 가진다.</li>
</ul>
<p>2) 메모리 소비</p>
<ul>
<li>JVM이 Garbage Collection을 수행하면서 더 많은 메모리를 사용할 수 있고, Garbage Collection이 완벽하지 않기 때문에 상황에 따라 메모리 문제가 발생할 수 있다.</li>
</ul>
<p>[참고] (<a href="https://yozm.wishket.com/magazine/detail/1979/">https://yozm.wishket.com/magazine/detail/1979/</a>)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Java란?]]></title>
            <link>https://velog.io/@jay_k56/Java%EB%9E%80</link>
            <guid>https://velog.io/@jay_k56/Java%EB%9E%80</guid>
            <pubDate>Tue, 11 Jul 2023 12:44:15 GMT</pubDate>
            <description><![CDATA[<h2 id="java란">Java란?</h2>
<ul>
<li>1991년 썬 마이크로시스템즈(Sun MicroSystems)에서 제임스 고슬링(James Gosling)이 고안한 프로그래밍 언어</li>
<li>초기에는 오크(Oak)라고 불렸으며, 처음 개발될 때는 가전제품에 쓰일 프로그램의 개발이 목적이였음</li>
<li>인터넷을 출현으로 웹 프로그래밍 언어로 노선을 변경하고 1995년 Java로 이름을 변경</li>
</ul>
<h2 id="java의-특징">Java의 특징</h2>
<ul>
<li>객체지향 언어<ul>
<li>객체지향 프로그래밍(OOP, Object Oriented Programming)이란, 프로그램을 개발하는 기법으로 부품에 해당되는 객체 들을 먼저 만들고, 객체 들을 조립, 연결하여 프로그램을 완성하는 것</li>
<li>객체지향 언어의 특징인 캡슐화, 상속성, 다형성을 지원함</li>
<li>객체를 생성할 때는 클래스라는 설계도를 기반으로 생성함</li>
</ul>
</li>
<li>이식성이 높음<ul>
<li>Java는 자바 실행환경(JRE)가 설치되어 있는 모든 운영체제에서 실행이 가능</li>
</ul>
</li>
<li>메모리를 자동으로 관리<ul>
<li>객체 생성 시 자동으로 메모리 영역을 찾아서 할당하고, 사용이 완료되면 Garbage Collector가 할당된 메모리를 해제함</li>
<li>이 특징은 Java의 장점이자 단점이 될 수 있음</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Factory Pattern]]></title>
            <link>https://velog.io/@jay_k56/Factory-Pattern</link>
            <guid>https://velog.io/@jay_k56/Factory-Pattern</guid>
            <pubDate>Wed, 05 Jul 2023 13:35:49 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>Factory Pattern은 객체 생성을 대신 수행해주는 공장(Factory)가 있는 패턴이다.</p>
</blockquote>
<p>Factory Pattern은 아래와 같은 장단점이 있다.
<strong>[장점]</strong></p>
<ul>
<li>생성할 클래스를 미리 알지 못해도 Factory 클래스가 객체 생성을 담당한다.</li>
<li>객체의 자료형이 하위클래스에 의해서 결정이 되기 때문에 확장이 용이하며, 결합도가 느슨해진다.(Loosely coupled)</li>
</ul>
<p><strong>[단점]</strong></p>
<ul>
<li>새로 생성할 객체가 늘어날 때마다, Factory 클래스에 추가해야하기 때문에 불필요하게 많은 클래스가 생성될 수 있음</li>
</ul>
<p>위와 같은 특성 때문에 아래와 같은 상황에 주로 사용된다.</p>
<ul>
<li>어떤 클래스가 자신이 생성해야 하는 객체의 클래스를 예측할 수 없을 때</li>
<li>생성할 객체를 기술하는 책임을 자신의 자식 클래스가 지정해야할 때</li>
</ul>
<h3 id="java-example">Java Example</h3>
<blockquote>
<p>Figure.java</p>
</blockquote>
<pre><code class="language-java">public interface Figure {
    void draw();
}</code></pre>
<blockquote>
<p>Circle.java</p>
</blockquote>
<pre><code class="language-java">public class Circle implements Figure {
    @Override
    public void draw() {
        System.out.println(&quot;Circle DRAW&quot;);
    }
}</code></pre>
<blockquote>
<p>Rectangle.java</p>
</blockquote>
<pre><code class="language-java">public class Rectangle implements Figure {
    @Override
    public void draw() {
        System.out.println(&quot;Rectangle DRAW&quot;);
    }
}</code></pre>
<blockquote>
<p>Square.java</p>
</blockquote>
<pre><code class="language-java">public class Square implements Figure {
    @Override
    public void draw() {
        System.out.println(&quot;Square DRAW&quot;);
    }
}</code></pre>
<blockquote>
<p>FigureFactory.java</p>
</blockquote>
<pre><code class="language-java">public class FigureFactory {
    public Figure getFigure(String type) {
        if (&quot;CIRCLE&quot;.equalsIgnoreCase(type) {
            return new Circle();

        } else if (&quot;RECTANGLE&quot;.equalsIgnoreCase(type) {
            return new Rectangle();

        }
         else if (&quot;SQUARE&quot;.equalsIgnoreCase(type) {
            return new Square();

        }
        return null;
    }
}</code></pre>
<blockquote>
<p>Main.java</p>
</blockquote>
<pre><code class="language-java">public class Main {
    public static void main(String[] args) {
        FigureFactory factory = new FigureFactory();
        Figure fig1 = factory.getFigure(&quot;CIRCLE&quot;);
        Figure fig2 = factory.getFigure(&quot;RECTANGLE&quot;);
        Figure fig3 = factory.getFigure(&quot;SQUARE&quot;);

        fig1.draw();
        fig2.draw();
        fig3.draw();
    }
}</code></pre>
<blockquote>
<p>main 실행 결과</p>
</blockquote>
<pre><code>Circle DRAW
Rectangle DRAW
Square DRAW</code></pre><p><em>참조</em>
<a href="https://velog.io/@lsj8367/%EC%9E%90%EB%B0%94-%ED%8C%A9%ED%86%A0%EB%A6%AC%ED%8C%A8%ED%84%B4">[Java] 디자인 패턴 - 팩토리 패턴(Factory pattern)</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Design Pattern]]></title>
            <link>https://velog.io/@jay_k56/Design-Pattern</link>
            <guid>https://velog.io/@jay_k56/Design-Pattern</guid>
            <pubDate>Wed, 05 Jul 2023 13:02:37 GMT</pubDate>
            <description><![CDATA[<p><a href="https://velog.io/@jay_k56/Factory-Pattern">1. Factory Pattern</a>
2. Observer Pattern
3. Singleton Pattern
4. Decorator Pattern
5. Facade Pattern
6. Builder Pattern
7. Proxy Pattern
8. Composite Pattern</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[@Primary와 @Qualifier]]></title>
            <link>https://velog.io/@jay_k56/Primary%EC%99%80-Qualifier</link>
            <guid>https://velog.io/@jay_k56/Primary%EC%99%80-Qualifier</guid>
            <pubDate>Tue, 04 Jul 2023 14:12:45 GMT</pubDate>
            <description><![CDATA[<p>지난 포스트에 이어서 같은 상황일 때, @Primary 어노테이션을 사용한다면 어떻게 될까?</p>
<pre><code class="language-java">@Configuration
public class InjectionConfig {
    @Primary
    @Bean
    public ObjectMapper aaaObjectMapper() {
        return new ObjectMapper();
    }

    @Bean
    public ObjectMapper bbbObjectMapper() {
        return new ObjectMapper();
    }
}</code></pre>
<pre><code class="language-java">public class InjectionTest {
    @Autowired
    private ObjectMapper aaaObjectMapper;

    @Autowired
    private ObjectMapper bbbObjectMapper;

    @Test
    void test() {
        System.out.println(&quot;&gt;&gt;&gt; &quot; + aaaObjectMapper);
        System.out.println(&quot;&gt;&gt;&gt; &quot; + bbbObjectMapper);
    }
}</code></pre>
<pre><code>&gt;&gt;&gt; com.fasterxml.jackson.databind.ObjectMapper@280a258d
&gt;&gt;&gt; com.fasterxml.jackson.databind.ObjectMapper@280a258d</code></pre><p>결과는 놀랍게도(?) 같은 값이 나온다.</p>
<p>이유는 다음과 같다.</p>
<ul>
<li>@Primary 어노테이션을 사용하면, bean name을 무시하고 Type만으로 Bean을 주입한다.</li>
</ul>
<p>이번엔 @Primary와 @Qualifier를 둘 다 써보자</p>
<pre><code class="language-java">@Configuration
public class InjectionConfig {
    @Primary
    @Bean
    public ObjectMapper aaaObjectMapper() {
        return new ObjectMapper();
    }

    @Bean
    public ObjectMapper bbbObjectMapper() {
        return new ObjectMapper();
    }
}</code></pre>
<pre><code class="language-java">public class InjectionTest {
    @Autowired
    private ObjectMapper aaaObjectMapper;

    @Autowired
    @Qualifier(&quot;bbbObjectMapper&quot;)
    private ObjectMapper bbbObjectMapper;

    @Test
    void test() {
        System.out.println(&quot;&gt;&gt;&gt; &quot; + aaaObjectMapper);
        System.out.println(&quot;&gt;&gt;&gt; &quot; + bbbObjectMapper);
    }
}</code></pre>
<pre><code>&gt;&gt;&gt; com.fasterxml.jackson.databind.ObjectMapper@280a258d
&gt;&gt;&gt; com.fasterxml.jackson.databind.ObjectMapper@bae32f</code></pre><p>이번엔 각각 다른 bean이 주입된 것을 볼 수 있다.
@Qualifier의 우선 순위가 @Primary 보다 높기 때문이다.</p>
<ul>
<li>aaaObjectMapper는 @Primary로 선언된 Bean으로 주입된다. (같은 Type이기 때문)</li>
<li>bbbObjectMapper는 @Qualifier에 명시된 &quot;bbbObjectMapper&quot; Bean name을 가진 Bean으로 주입된다.</li>
</ul>
<p>*참고(<a href="https://tech.kakaopay.com/post/martin-dev-honey-tip-2/">https://tech.kakaopay.com/post/martin-dev-honey-tip-2/</a>)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring의 Bean Injection 방식]]></title>
            <link>https://velog.io/@jay_k56/Spring%EC%9D%98-Bean-Injection-%EB%B0%A9%EC%8B%9D</link>
            <guid>https://velog.io/@jay_k56/Spring%EC%9D%98-Bean-Injection-%EB%B0%A9%EC%8B%9D</guid>
            <pubDate>Tue, 04 Jul 2023 14:02:54 GMT</pubDate>
            <description><![CDATA[<ul>
<li>Spring framework에서는 bean injection 시 bean name / field name을 매칭하여 bean을 찾고, 만약 없으면 Type으로 매칭하여 Bean을 주입한다.</li>
<li>Spring framework에서 @Bean 어노테이션을 사용하여 bean을 생성하게 되면, 어노테이션이 붙은 method의 이름이 bean name으로 생성된다.</li>
</ul>
<p>위와 같은 특성 때문에, Bean Injection 할 때, 아래와 같은 현상이 발생된다.</p>
<pre><code class="language-java">@Configuration
public class InjectionConfig {
    @Bean
    public ObjectMapper aaaObjectMapper() {
        return new ObjectMapper();
    }

    @Bean
    public ObjectMapper bbbObjectMapper() {
        return new ObjectMapper();
    }
}</code></pre>
<pre><code class="language-java">public class InjectionTest {
    @Autowired
    private ObjectMapper aaaObjectMapper;

    @Autowired
    private ObjectMapper bbbObjectMapper;

    @Test
    void test() {
        System.out.println(&quot;&gt;&gt;&gt; &quot; + aaaObjectMapper);
        System.out.println(&quot;&gt;&gt;&gt; &quot; + bbbObjectMapper);
    }
}</code></pre>
<p>테스트 결과를 보면 다른 bean이 주입된 것을 알 수 있다.</p>
<pre><code>&gt;&gt;&gt; com.fasterxml.jackson.databind.ObjectMapper@280a258d
&gt;&gt;&gt; com.fasterxml.jackson.databind.ObjectMapper@bae32f</code></pre><p>여기서 configuration은 그대로 두고, autowired를 하나 더 넣으면 어떻게 될까?</p>
<pre><code class="language-java">public class InjectionTest {
    @Autowired
    private ObjectMapper aaaObjectMapper;

    @Autowired
    private ObjectMapper bbbObjectMapper;

    @Autowired
    private ObjectMapper cccObjectMapper;

    @Test
    void test() {
        System.out.println(&quot;&gt;&gt;&gt; &quot; + aaaObjectMapper);
        System.out.println(&quot;&gt;&gt;&gt; &quot; + bbbObjectMapper);
        System.out.println(&quot;&gt;&gt;&gt; &quot; + cccObjectMapper);
    }
}</code></pre>
<p>아래와 같이 에러가 발생된다.</p>
<pre><code>Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type &#39;com.fasterxml.jackson.databind.ObjectMapper&#39; available: expected single matching bean but found 2: aaaObjectMapper,bbbObjectMapper</code></pre><p>아래와 같은 이유로 에러가 발생되었다.</p>
<ul>
<li>bean injection을 위해 cccObjectMapper라는 Bean name을 찾았지만, 없음</li>
<li>Bean type (ObjectMapper)로 찾아봤더니 2개나 있음 (aaaObjectMapper / bbbObjectMapper)</li>
<li>둘 중 어떤걸로 injection을 해야할지 모르겠음</li>
</ul>
<p>때문에 만약에 bbbObjectMapper Bean 선언 부분을 제거하면 에러가 발생되지 않고, 셋 모두 같은 aaaObjectMapper를 사용하는 것을 확인할 수 있다.
(bean name으로 찾았을 때 없으면 bean type으로 찾기 때문)</p>
<pre><code class="language-java">@Configuration
public class InjectionConfig {
    @Bean
    public ObjectMapper aaaObjectMapper() {
        return new ObjectMapper();
    }
}</code></pre>
<pre><code class="language-java">public class InjectionTest {
    @Autowired
    private ObjectMapper aaaObjectMapper;

    @Autowired
    private ObjectMapper bbbObjectMapper;

    @Autowired
    private ObjectMapper cccObjectMapper;

    @Test
    void test() {
        System.out.println(&quot;&gt;&gt;&gt; &quot; + aaaObjectMapper);
        System.out.println(&quot;&gt;&gt;&gt; &quot; + bbbObjectMapper);
        System.out.println(&quot;&gt;&gt;&gt; &quot; + cccObjectMapper);
    }
}</code></pre>
<pre><code>&gt;&gt;&gt; com.fasterxml.jackson.databind.ObjectMapper@280a258d
&gt;&gt;&gt; com.fasterxml.jackson.databind.ObjectMapper@280a258d
&gt;&gt;&gt; com.fasterxml.jackson.databind.ObjectMapper@280a258d</code></pre><p>*참고(<a href="https://tech.kakaopay.com/post/martin-dev-honey-tip-2/">https://tech.kakaopay.com/post/martin-dev-honey-tip-2/</a>)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[@Autowird를 활용한 Field Injection 방식이 deprecated되고 생성자를 활용한 Constructor Injection이 권장되는 이유]]></title>
            <link>https://velog.io/@jay_k56/Spring-Bean-Injection</link>
            <guid>https://velog.io/@jay_k56/Spring-Bean-Injection</guid>
            <pubDate>Tue, 04 Jul 2023 13:36:17 GMT</pubDate>
            <description><![CDATA[<p>Spring framework에서 Bean 주입 시 아래와 같은 내부 코드를 통해 Bean을 찾게되는데,</p>
<pre><code class="language-java">Map&lt;String, Object&gt; matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
    if (isRequired(descriptor)) {
        raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
    }
    return null;</code></pre>
<p>만약 Bean을 찾지 못하게 되면
Field Injection의 경우에는 해당 field의 값이 null로 들어가게 되어, 결국 runtime 에러가 발생되게 되고</p>
<pre><code class="language-java">@Autowired
private BeanTestService beanTestService;

public void beanTest() {
    // beanTestService에 값이 null이 들어갈 경우, 여기서 NullPointerException이 발생된다.
    this.beanTestService.run();
}</code></pre>
<p>Constructor Injection의 경우에는 final 접근자를 사용하기 때문에 Spring context loading 시에 에러가 발생된다.</p>
<pre><code class="language-java">private final BeanTestService beanTestService;

// 요즘은 보통 Lombok의 @RequiredArgsContructor 어노테이션을 사용하여 생성자 코드를 대체한다.
public BeanTestClass(BeanTestService beanTestService) {
    this.beanTestService = beanTestService;
}

public void beanTest() {
    // beanTestService에 값이 null이 들어갈 경우, 이미 생성자에서 에러가 발생되기 때문에 여기까지 오지 않는다.
    this.beanTestService.run();
}</code></pre>
<p>때문에 Bean 관련 에러가 발생될 때는 해당 프로그램이 실행될 때 에러를 발생시켜 버그를 줄일 수 있게 하기 위해 Constructor Injection이 권장된다.</p>
]]></description>
        </item>
    </channel>
</rss>