분류 전체보기
[Spring] 스프링 부트에서 Chat GPT API 사용해보기
OPEN AI에서 지원하는 Chat GPT의 API를 사용해서 프롬프트에 대해 응답을 받는 경험을 공유하고자 쓰는 글입니다. 준비 사항 저는 아래의 라이브러리를 사용했습니다. https://github.com/TheoKanning/openai-java GitHub - TheoKanning/openai-java: OpenAI GPT-3 Api Client in Java OpenAI GPT-3 Api Client in Java. Contribute to TheoKanning/openai-java development by creating an account on GitHub. github.com 그리고, 프로젝트에서는 gradle을 사용하기 때문에 아래 의존성을 추가해줍니다. implementation '..
[Spring] IoC와 DI (2/2)
DI 구현 방법 필드 주입 @Service public class BurgerService { @Autowired private BurgerRecipe burgerRecipe; } 변수 선언부에 @Autowired 어노테이션을 붙인다. 장점 사용하기 편하다 단점 단일 책임 원칙 위반의 가능성이 있다. @Autowired 선언만 하면 되므로 의존성을 주입하기 쉽다. 따라서, 하나의 클래스가 많은 책임을 갖게 될 가능성이 높다. 의존성이 숨는다. 생성자 주입에 비해 의존 관계를 한 눈에 파악하기 어렵다. DI 컨테이너와의 결합도가 커지고, 테스트하기 어렵다. 불변성을 보장할 수 없다. 순환 참조가 발생할 수 있다. 수정자 주입 @Service public class BurgerService { private..

[Spring] IoC와 DI (1/2)
Inversion of Control 제어의 역전이라고 한다. 스프링 애플리케이션에서 스프링 빈의 생성과 의존관계 설정, 사용 및 제거 등의 작업을 애플리케이션 코드가 아닌 스프링 컨테이너가 담당한다. 이를 스프링 컨테이너가 코드 대신 빈에 대한 제어권을 갖고 있다고 해서 IoC라고 부른다. 스프링 컨테이너를 IoC 컨테이너라고 부르기도 한다. IoC 컨테이너 스프링에서 IoC를 담당하는 컨테이너를 빈 팩토리, DI 컨테이너, Application Context라고 부른다. 빈(오브젝트)의 생성과 빈 사이의 런타임 관계를 설정하는 DI의 관점에서 컨테이너를 빈 팩토리 또는 DI 컨테이너라고 부른다. 그러나 스프링 컨테이너는 단순히 DI작업보다 더 많은 작업을 하는데, DI를 위한 빈 팩토리에 여러가지 기..
[Spring] 스프링 빈 스코프 (2/2)
스프링 빈 스코프 스프링에서 싱글톤과 프로토타입 빈 스코프를 제공하고 있으며, 스프링 MVC 웹 애플리케이션을 사용할 경우 웹 스코프를 제공한다. 싱글톤 싱글톤 빈은 스프링 컨테이너에서 한 번만 생성되며, 컨테이너가 사라질 때 제거된다. 생성된 하나의 인스턴스는 Spring Beans Cache에 저장되고, 해당 빈에 대한 요청과 참조가 있으며 캐시된 객체를 반환한다. 하나만 생성되기 떄문에 동일 참조를 보장한다. 기본적으로 모든 빈은 스코프가 명시적으로 지정되지 않으면 싱글톤이다. 대상 클래스에 @Scope("singletone")을 붙이면 된다. 싱글톤으로 적합한 객체는 아래와 같다. 상태가 없는 공유 객체 읽기 전용으로만 상태를 가진 객체 쓰기가 가능한 상태를 지니면서도 사용 빈도가 매우 높은 객체..
[Spring] 스프링 빈 (1/2)
스프링 빈 스프링 컨테이너에 의해 관리되는 POJO 자바 객체 스프링 컨테이너 스프링 빈의 생명 주기를 관리하며, 생성된 스프링 빈에게 추가 기능을 제공한다. IoC와 DI 원리가 여기에 적용된다. 개발자는 객체를 생성할 때 new 연산자, 팩토리 메서드 호출 등을 사용하지만, 스프링 컨테이너를 사용하면 해당 역할을 대신해준다. 즉 제어의 흐름을 외부에서 관리한다. 또한, 객체들의 의존 관계를 스프링 컨테이너가 런타임 과정에서 알아서 만들어 준다. 스프링 빈 등록 컴포넌트 스캔 @Component 어노테이션이 붙은 클래스를 스캔해서 빈으로 등록한다. @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Indexed publ..

[트러블 슈팅] 도메인 설계에 대한 고민
제가 첫 프로젝트에 참여함으로써 고민했던 도메인 설계에 대한 내용을 공유하고자합니다. AS - IS 프로젝트 초기 단계에서 "퍼디"의 핵심 기능 중 하나인 "전문가" 기능에 대해 고민하게 되었습니다. "전문가"는 일반 사용자와 다르게 특정 조건을 만족한 사용자만이 등록할 수 있는 기능으로, 자신의 전문성을 바탕으로 다른 사용자들의 질문에 답변을 제공하는 역할을 합니다. 이를 표현하기 위한 초기 도메인 모델 설계는 "전문가"를 사용자 도메인 내의 추가적인 정보, 즉 일종의 부가적인 속성으로 생각했습니다. 즉, 기본적으로 모든 사용자는 "전문가"가 될 가능성을 가지고 있으므로, 그에 따른 전문가 정보를 포함하는 사용자 테이블을 생성하는 것이 자연스러워 보였습니다. 그러나, 이렇게 설계할 경우 아래와 같은 몇..

[Java] url 변수 동적으로 받도록 개선하기
MVC 프레임워크를 구현하던 중, url 변수를 동적으로 받도록 기능을 개선한 점을 공유하고자 합니다. AS-IS 문제가 된 예제 코드 Rq 클래스의 메서드는 다음과 같습니다. public String getPathParam(String paramName, String defaultValue) { if ( routeInfo == null ) { return defaultValue; } String path = routeInfo.getPath(); String[] pathBits = path.split("/"); int index = -1; for ( int i = 0; i < pathBits.length; i++ ) { String pathBit = pathBits[i]; if ( pathBit.equ..

[트러블 슈팅] url 패턴이 같을 경우에 Controller 메서드 구별하기
제가 구현중인 MVC 프레임 워크 프로젝트는 DI 컨테이너를 맵의 형태로 직접 구현하게 되었습니다. public class ControllerManager { private static Map controllerMap = new HashMap(); static { Reflections reflections = new Reflections(DbConfig.BASE_PACKAGE_PATH); Set

[PUDDY] 연관관계를 고려한 JPA N+1 문제 개선하기
제 퍼디 프로젝트의 ERD는 아래와 같습니다. Question 테이블은 User 테이블과 다대일 관계(@ManyToOne)에 있고, 한 질문에 답변 글을 여러 개 작성할 수 있기 때문에 일대다 관계(@OneToMany)로 있으며, 한 질문당 이미지를 최대 3개까지 첨부할 수 있기 때문에 Image 테이블과도 일대다 관계(@OneToMany)를 가지고 있습니다. 그리고 User 테이블은 전문가일 경우 Expert 테이블과 일대일 관계(@OneToOne)를, 한 유저당 한 마리의 반려동물을 소유할 수 있기 때문에 Pet 테이블과도 일대일 관계(@OneToOne)를, 한 유저의 프로필 사진 한장을 가지기 때문에 Image 테이블과도 일대일(@OneToOne) 관계를 가지고 있습니다. AS-IS 퍼디 프로젝트의..

[Spring] 테스트 클렌징시 deleteAll()을 사용할 때의 주의점
테스트 코드를 작성하면서, 테스트 간 독립성을 보장하기 위해 트랜잭션 롤백 클렌징을 사용하지 않고 @AfterEach를 통해 리포지토리 레벨에서 delete 메서드를 통해 given 절에서 생성했던 픽스쳐를 제거한다고 해보자. 우선 나의 경우 Order 엔티티 픽스쳐를 지우기 위해 아무 의심 없이 deleteAll() 메서드를 사용했다. 그래서 @AfterEach의 메서드를 아래와 같이 작성했다. @AfterEach void tearDown() { orderRepository.deleteAll(); productRepository.deleteAll(); } AS-IS 내가 테스트를 할 메서드는 아래와 같다. @DisplayName("주문번호 리스트를 받아 주문을 생성한다.") @Test void crea..