[Java Spring] 입문 2 주차 강의 - PART 1
Layer Architecture
- 하나의 controller에서 모든 API를 처리하면 코드 이해하기도 힘들고 변경을 할 때 문제가 발생할 수 있다.
- 그래서 Spring 에서는 3개로 분리했는데 Controller, Service, Repository다.
- Controller
- Client에게서 오는 요청을 받는다.
- 요청을 받으면 Service에 전달한다. - request 데이터가 있으면 같이 전달하게 된다.
- Service에서 처리한 결과를 Client에게 응답한다.
- Service
- 강의에서는 실세라 했다.
- 비즈니스 로직을 처리하고 코드의 양이 점점 많아진다.
- DB에 저장하거나 조회가 필요하면 Repository에 전달한다.
- Repositoty
- DB를 관리한다.
- DB CURD 작업을 처리한다.
- CRUD = Create, Read, Update, Delete
IoC와 DI 이해하기
IoC는 제어의 역전을 뜻하고 DI는 의존성 주입이다.
2가지는 객체지향의 SOLID원칙과 GoF의 디자인 패턴과 같은 설계원칙 및 디자인 패턴이다.
구분을 하면 IoC는 설계 원칙이고 DI는 디자인 패턴이라고 구분할 수 있다.
Spring에서 두 가지를 사용해서 좋은 코드를 작성할 수 있게 해 준다.
DI 패턴을 사용해서 IoC 설계 원칙을 구현한다라고 이해하면 좋다.
- IoC - 설계원칙
- 요리로 따지면 재료, 비율, 재료의 순서 등을 이야기할 수 있다.
- 제어의 역전 - 프로그램의 흐름이 뒤바뀜.
- 일반적으로 개발자가 객체를 직접 제어해야만 하지만 제어의 역전이 일어나면 Spring에서는 객체에 대한 제어권이 컨테이너로 역전된다. - Bean(객체)을 등록하기만 하면 된다.
- Spring 에서 Controller → Service → Repository 순으로 흐름이 진행되었다면 제어의 역전이 일어나면 Repository → Service → Controller 순으로 흐름이 바뀐다.
- DI - 디자인 패턴
- 요리로 치면 볶고, 풍미를 내는 과정이라 할 수 있다.
- 의존성 주입
- 의존성이 강하면 코드를 수정해야 할 때 관련된 코드를 전부 수정해야 한다. 그래서 의존성을 낮춰야 한다. Interface 다형성의 원리를 사용해서 구현하면 의존성이 낮아진다. = 결합을 약하게 한다, 약한 의존성
- 강한 결합을 해결하려면 각 객체에 대한 생성은 1번만 하고 모든 곳에서 재사용하고 생성자 주입을 사용해서 필요로 하는 객체에 해당 객체를 주입하는 방법이다.
- 주입은 여러 가지 방법을 사용해서 필요로 하는 객체를 해당 객체에 전달하는 것이다. 주입하는 방법은 필드에 직접적으로 주입하거나 메서드를 사용하거나 생성자를 사용해서 주입할 수 있다.
- 좋은 코드
- 논리가 간단해야 한다.
- 중복제거 및 표현이 명확해야 한다.
- 코드를 처음 보는 사람도 쉽게 이해하고 수정할 수 있어야 한다.
- 의존성을 최소화해야 한다.
- 기능을 추가할 때 크게 구조의 변경이 없어야 한다.
IoC Container와 Bean
IoC Container는 Bean을 모아둔 컨테이너고 Bean은 Spring 이 관리하는 객체를 말한다.
모든 객체가 다 Bean이 되는 것이 아니고 등록을 해줘야 한다.
Bean으로 등록 하고자 하는 클래스 위에 @Component를 적어준다.
Spring 서버가 동작할 때 IoC Container에 Bean을 저장한다.
등록하면 옆에 콩처럼 생긴 아이콘이 뜬다. Spring IoC에서 관리하는 Bean클래스라는 표시다.
Bean을 사용하려면 사용하고자 하는 메서드 위에 @Autowired를 적어주는데
Spring 4.3 버전부터는 생략이 가능해졌고 생략이 가능할 때는 생성자가 1개 일 때만 생략이 가능하다.
2개 이상이면 써줘야 한다.
그런데 앞에서 3 Layer Architecture에서 이미 3개의 층으로 분리했고
각각 Controller, Service, Repository의 역할이 있기 때문에
@Component가 아니라 각각 @Controller, @Service, @Repository로 사용하는 것이 좋다
그 안에 @Component가 추가되어 있기 때문이다.
JPA CORE
- JPA
- DB를 다룰 때는 직접 쿼리를 짜서 테이블을 만들고 Application에 저장하고 JDBC를 이용해서 직접 실행한 후에 객체로 직접 만들어야 해서 SQL에 대한 의존성이 높았다.
- 그래서 ORM = Object-Relational Mapping - 객체 관계 매핑이라 하며 SQL 작업을 줄여주는 기술이 나왔다. 많은 작업을 자동으로 처리해 준다.
- JPA는 Java Persistence API로 자바 ORM 기술에 대한 표준 명세를 말한다.
- JPA는 Application과 JDBC 사이에서 동작한다.
- JPA를 사용하면 DB연결 과정 개발을 하지 않아도 자동으로 처리해 준다.
- 객체를 통해 간접적으로 DB데이터를 다룰 수 있어서 매우 쉽게 작업처리를 할 수 있다.
- Hibernate
- JPA는 표준 명세라고 이야기했고 이것을 실제로 구현한 프레임 워크 중 사실상 표준이라고 말할 수 있는 게 하이버네이트다.
- Spring Boot에서 기본적으로 Hibernate구현체를 사용한다.
Entity 이해하기
- JPA에서 관리되는 클래스 즉, 객체를 의미한다.
- Entity 클래스는 DB의 테이블과 매핑되어 JPA에 의해 관리된다.
- @ 을 써서 Entity 클래스를 지정할 수 있다.
- @Entity
- JPA가 관리할 수 있는 Entity클래스로 선언할 때 사용한다.
- @Entity(name = "이름") Entity클래스 이름을 지정할 때 사용하고 Default는 클래스명이다.
- JPA가 Entity클래스를 인스턴스화할 때 기본 생성자를 사용한다. 그래서 현재 Entity클래스에서 기본 생성자가 됐는지 확인해야 한다.
- @Table
- 매핑할 테이블을 지정할 때 사용한다.
- @Table(name = "이름") 매핑할 테이블의 이름을 지정할 때 사용한다. Default는 Entity명이다.
- @Column
- @Column(name="이름") 필드와 매핑할 테이블의 컬럼을 지정할 때 사용한다. Default는 객체의 필드명이다.
- @Column(nullable = false) 데이터의 null 값 허용 여부를 지정할 때 사용한다. Default는 true다
- @Column(unique = true) 데이터의 중복 값 허용 여부를 지정할 때 사용한다. Dafault는 false다
- @Column(length = 500) 데이터의 길이에 조건을 걸 때 사용한다. Default는 225다
- @Id
- 테이블의 기본 키를 지정할 때 사용한다.
- 영속성 컨텍스트에서 Entity를 구분하고 관리할 때 사용하는 식별자 역할을 한다.
- 식별자를 넣어주지 않고 저장하면 오류가 발생한다.
- @Id 옵션만 설정하면 기본 키 값을 개발자가 직접 확인하고 넣어줘야 한다.
- @GeneratedValue
- 이 옵션을 추가하면 기본 키 생성을 DB에 위임할 수 있다.
- @GeneratedValue(strategy = GenerationType.IDENTITY)처럼 사용할 수 있다.
영속성 컨텍스트란?
- Entity 객체를 효율적으로 쉽게 관리하기 위해 만들어진 공간이다.
- JPA는 영속성 컨텍스트에 Entity 객체를 저장하고 관리하면서 DB랑 소통한다.
- 조작하기 위해서는 EntityManager가 필요하고 EntityManager를 사용해서 Entity를 조회, 수정, 삭제할 수 있다.
- EntityManager를 생성하려면 EntityManagerFactory를 사용해서 생성할 수 있다.
- EntityManagerFactory는 DB 하나에 하나만 생성되어 Application이 동작하는 동안 사용된다.
- EntityManagerFactory사용하려면 빨간 네모칸 안에 있는 persistence.xml에 DB에 대한 정보를 담아 두면 사용가능 하다.
// 예시 코드
EntityManagerFactory emf = Persistence.createEntityManagerFactory("memo"); // 생성하기
EntityManager em = emf.createEntityManager(); // Manager생성하기
- 영속성 컨텍스트는 내부적으로 캐시 저장소를 가지고 있고 Map 자료 구조 형태로 되어 있다.
- Key는 식별자 값을 저장하고 Value는 Entity클래스의 객체를 저장한다.
- 영속성 컨텍스트에서 저장하는 Entity객체들이 1차 캐시로 저장소에 저장된다. 1차 캐시를 사용하면 DB조회 횟수도 줄이고 객체 동일성도 보장할 수 있다.
- flush() 메서드는 영속성 컨텍스트의 변경 내용들을 DB에 반영하는 역할을 한다.
JPA 트랜잭션
- DB를 안전하게 관리하기 위해 생겨난 개념이다.
- 여러 개의 SQL이 하나의 트랜잭션에 포함될 수 있는 것이 가장 큰 장점이라고 할 수 있다.
- 영속석 컨텍스트에 Entity객체를 저장해도 바로 DB에 반영되지 않는다. 마지막에 한 번에 요청해서 저장하는데 JPA에서도 마찬가지다.
- 이 개념을 적용하려면 EntityManager에서 EntityTransaction을 가져와서 적용할 수 있다.
// 예시 코드
EntityTransaction et = em.getTransaction(); // 호출하기
et.begin(); // 트랜잭션 시작하기
et.commit(); // 영구적으로 DB에 반영하는 하기
et.rollback(); // 오류 발생 시 모든 작업을 취소하고 이전 상태로 되돌리기
오늘까지 배운 내용을 이해한 대로 정리해 보았다.
확실히 강의 보고 코드치고 따라가기 바빴는데 정리하니 이해되는 부분이 많았다.
참고한 사이트