Spring
[Spring 3.1] Aspect Oriented Programming
[Spring 3.1] Aspect Oriented Programming
2023.04.28Service 계층에서 비즈니스 로직과 트랜잭션 설정 관련 로직을 분리했지만, 여전히 트랜잭션 경계 설정을 위해 비즈니스 로직의 앞뒤로 관련된 코드가 붙어 있는 상황이다. 두 부분을 분리할 수는 없을까? Service 계층에는 비즈니스 로직만 포함하면 좋을 텐데.. Service 계층을 인터페이스로 설계하고 두 가지 클래스를 구현 클래스로 설정해보자. 하나는 비즈니스 관련 로직만을 다루고, 나머지 하나는 트랜잭션 관련 설정 로직만을 다룬다. ServiceTx 구현체에서는 ServiceImpl에게 작업을 위임한다. 트랜잭션 관련 설정은 알아서 처리하고, 비즈니스 관련 로직을 처리해야 하는 경우 ServiceImpl을 DI 받아서 해당 구현체가 처리하도록 설계한다. 작업을 거듭할수록 Service 계층이 점..
[Spring 3.1] 트랜잭션과 서비스 추상화
[Spring 3.1] 트랜잭션과 서비스 추상화
2023.04.23스프링은 트랜잭션을 구현할 때 TransactionSynchronizations 방식을 사용한다. Connection 객체를 특별한 저장소에 보관해두고 이후 하나의 트랜잭션 내부에서 호출되는 다른 메서드를 수행할 때는 저장소에 저장된 Connection을 가져가서 사용하는 방식이다. Service에서 Connection을 생성하고 저장소에 Connection을 저장한 후 트랜잭션을 시작한다. 이후 서비스의 메서드를 수행할 때는 저장소에 Connection 객체가 있는지 확인한다. 트랜잭션 내부의 작업이 모두 끝났을 때 커밋을 호출해 트랜잭션을 완료시킨 후 Connection을 제거한다. 작업 스레드마다 독립적으로 Connection을 사용하기에 멀티스레드 환경에서도 충돌이 나지 않는다. JdbcTempl..
[Spring 3.1] 스프링과 예외처리
[Spring 3.1] 스프링과 예외처리
2023.04.20자바에서 예외는 세 가지 종류로 구분된다. 1. Error 클래스 OutOfMemoryError, ThreadDeath 같이 시스템에 비정상적인 상황이 발생한 경우 나타나는 예외이다. 애플리케이션에서는 신경쓰지 않아도 된다. 2. Exception 체크 예외 Exception 클래스의 하위 클래스 중 RuntimeException 클래스를 상속받지 않은 클래스를 의미한다. 3. Exception 언체크 예외 Exception 클래스의 하위 클래스 중 RuntimeException 클래스를 상속받은 클래스를 의미한다. 체크 예외가 발생할 수 있는 메서드에서는 반드시 예외를 처리하는 코드를 추가해야 한다. (컴파일 시점에서 검증된다) 언체크 예외를 처리하는 코드는 강제되지 않는다. 언체크 예외에 대해 알고 ..
[Spring 3.1] 템플릿과 콜백
[Spring 3.1] 템플릿과 콜백
2023.04.19템플릿은 코드 중에서 변하지 않는 부분을 변하는 부분으로부터 독립시켜 효과적으로 활용하는 기법을 말한다. 스프링 프레임워크에 적용된 템플릿 기법을 살펴보고 Data Access Object에 적용해보자. DAO는 데이터베이스와 연결하는 부분이 필수적으로 포함된다. 데이터베이스와의 연결은 Connection Pool을 통해 이루어지고, 커넥션을 모두 사용했다면 반환해 다시 풀에 넣어 줘야 한다. try { // connect.. } catch (Exception e) { } finally { // close.. } 어떤 상황에서도 가져온 리소스를 반환할 수 있도록 try-catch-finally 구문을 사용한다. 제대로 작성한다면 커넥션 풀이 꽉 차는 현상은 막을 수 있지만.. DAO를 작성할 때 마다 t..
[Spring 3.1] 스프링과 테스트
[Spring 3.1] 스프링과 테스트
2023.04.16웹 애플리케이션을 제작하고 제대로 동작하는지 테스트하려면 어떻게 해야 할까? 특정 기능을 테스트하기 위해 해당 테스트와 연계된 서비스, 컨트롤러, 뷰, 웹 서버 환경을 모두 구축해야 테스트 할 수 있다. 여기서 테스트가 실패한다면? 테스트하려는 특정 기능에서 오류가 발생했는지, 아니면 다른 연계된 기능에서 오류가 발생했는지 확인하기 전에 알 수 없다. 즉, 웹 서버를 띄워서 테스트하는 경우 디버깅 비용이 매우 많이 발생한다. 테스트하려는 대상이 명확한 경우 그 대상에만 집중해서 테스트를 진행하는 편이 합리적이다. 이렇게 작은 단위의 코드에 대해 진행하는 테스트를 단위 테스트라고 부른다. 자바는 JUnit 테스트 프레임워크를 제공해 개발자가 단위 테스트를 쉽게 진행할 수 있도록 도와준다. (개발의 전반적인..
[Spring 3.1] 관심사의 분리와 스프링
[Spring 3.1] 관심사의 분리와 스프링
2023.04.13추후 유지 보수를 고려했을 때 관심사 (도메인) 를 작업 단위로 소스코드를 분리해서 작성하는 편이 합리적이다. 이런 측면에서 추상 클래스와 인터페이스는 매우 중요하다. 확장성 있는 애플리케이션을 구현하기 위해 디자인패턴 중 템플릿 메서드 패턴을 사용한다. abstract class Car { public void doorOpen() { } public abstract void drive() { } } class ACar extends Car { public void drive() {...} } 슈퍼 클래스에 기본적인 로직을 만들어 놓고, 일부 기능을 추상 메서드로 만든다. 이후 서브 클래스에서 해당 메서드를 필요에 따라 구현해서 사용하도록 하는 패턴이다. 변화의 성격이 다른 것들을 분리해서 서로 영향을 ..
[QueryDSL] 활용 (Spring Data JPA + QueryDSL)
[QueryDSL] 활용 (Spring Data JPA + QueryDSL)
2023.01.11웬만한 기능은 Spring Data JPA가 제공해주고, 동적 쿼리 등 복잡한 구현이 필요할 때 QueryDSL 기술을 사용한다. 따로 Repository를 하나 만들어서 기능을 구현하자. MemberRepositoryCustom을 인터페이스로 만들고 구현할 기능을 선언한 후 MemerRepositoryImpl에 기능을 구현한다. public class MemberRepositoryImpl implements MemberRepositoryCustom { private final JPAQueryFactory queryFactory; public MemberRepositoryImpl(EntityManager em) { this.queryFactory = new JPAQueryFactory(em); } @Ov..
[QueryDSL] 활용 (JPA + QueryDSL)
[QueryDSL] 활용 (JPA + QueryDSL)
2023.01.11실제로 애플리케이션을 설계할 때는 Repository 계층을 만들고 Repository를 통해 데이터베이스와 상호작용한다. 먼저 Spring Data JPA 기술 없이 순수 JPA와 QueryDSL 만 사용해서 Repository를 설계해보자. @Repository public class MemberJpaRepository { private final EntityManager em; private final JPAQueryFactory queryFactory; public MemberJpaRepository(EntityManager em) { this.em = em; this.queryFactory = new JPAQueryFactory(em); } public void save(Member member..
[QueryDSL] 중급 문법
[QueryDSL] 중급 문법
2023.01.101. 프로젝션 프로젝션 대상이 하나인 경우 대상 타입을 명확하게 지정할 수 있다. 제네릭스를 String으로 설정하고 값을 받아온다. (객체도 가능) 프로젝션 대상이 둘 이상인 경우 QueryDSL이 제공하는 Tuple 자료구조나 DTO를 따로 정의해서 반환값을 가져올 수 있다. 왼쪽은 Tuple을 사용하는 예시이다. 일단은 Tuple도 QueryDSL에 종속적인 타입이기 때문에, 바깥 계층으로 반환될 때를 생각하면 DTO를 사용하는 편이 합리적이다. (Repository 내부에서만 사용하는 경우는 괜찮다) JPA를 사용할 때 DTO를 따로 정의해서 반환값을 가져오려면 new 명령어를 사용해 DTO의 생성자를 호출하는 방식을 사용해야 한다. QueryDSL 기술을 사용하면 좀 더 간단하게 처리할 수 있다..
[QueryDSL] 기본 문법
[QueryDSL] 기본 문법
2023.01.09QueryDSL은 Query Domain Specific Language의 약자로 간단하게 JPQL을 만들어주는 역할을 한다고 생각하면 된다. @Test public void startJPQL() { String qlString = "select m from Member m " + "where m.username = :username"; Member findMember = em.createQuery(qlString, Member.class) .setParameter("username", "member1") .getSingleResult(); assertThat(findMember.getUsername()).isEqualTo("member1"); } @Test public void startQuerydsl..
[Spring Data JPA] 내부 동작 원리
[Spring Data JPA] 내부 동작 원리
2023.01.03Spring Data JPA 기술이 제공하는 공통 인터페이스의 구현체를 살펴보자. SimpleJpaRepository 클래스가 공통 인터페이스를 구현한다. @Repository 애너테이션이 붙어있다. 따라서 Spring의 Component Scan의 대상이 되고, 특정 계층에서 예외가 터진 경우 Spring이 다루기 쉬운 예외로 변환한다. 덕분에 구현 기술을 바꾸더라도 기존 기술에 영향을 주지 않는다. @Transaction 애너테이션도 붙어있다. 모든 데이터의 변경은 Transaction 내부에서 진행되어야 한다. Spring Data JPA는 기본으로 제공하는 기능에 모두 @Transaction 애너테이션을 붙이기 때문에 개발자가 좀 더 편하게 개발할 수 있다. 단순히 조회만 하는 작업에서 @Tran..
[Spring Data JPA] 사용자 정의 리포지토리와 확장 기능
[Spring Data JPA] 사용자 정의 리포지토리와 확장 기능
2023.01.03Spring Data JPA 가 제공하는 기능을 사용하면 개발이 생산성이 증가하지만, 상황에 따라 특정 기능은 Spring Data JPA가 제공하는 방법 대신 다른 방법을 사용해야 하는 경우가 생긴다. (JPA를 직접 사용한다던가, MyBatis를 사용한다던가...) 이럴 때는 어떻게 해야 할까? Spring Data JPA는 이런 경우 Custom Repository를 사용할 수 있도록 한다. 사용자가 직접 인터페이스를 만들고, 필요한 기능을 원하는 방법으로 구현한 후 Spring Data JPA와 합치는 방식으로 문제를 해결한다. MemberRepositoryCustom에 구현하려는 기능을 선언하고, MemberRepositoryImpl에서 기능을 구현한다. (둘 다 인터페이스이다) 이후 JpaRe..