[Spring] 인프런 김영한 스프링 입문 후기

chael_lo·2022년 2월 15일
0

Spring

목록 보기
1/7

포트폴리오를 만들며 자바, 스프링 환경은 경험 하였으나, 숙련된? 개발자가 자바 스프링 개발 환경을 설명해주는 강의를 듣고 싶어서 인프런 김영한 스프링 입문편을 들었다.

인프런 스프링 입문 바로가기

개발 환경 구성

java 11, Spring Boot, Gradle
Thymeleaf
h2 DataBase

스프링 프로젝트를 만들기에 앞서 Spring Initializr에 접속하여 원하는 환경을 먼저 구성한 후 내려받아 사용하였다.

Spring Initializr

사이트에 접속하면 어떤 프로젝트를 만들건지에 따라 메타 데이터, 패키지 형태, 자바 버전, 디펜던시 등 구체적으로 설정이 가능하다.
클릭 몇번으로 만드니까 정말 편했다. ^ㅁ^

테스트 케이스, 테스트 코드

어떤 기능을 만들고, 그 기능이 잘 돌아가는지 테스트하기 위해서 테스트 케이스를 만들었다. 테스트용 클래스 이름은 어떠한 규칙이 있는 것은 아니지만 예시에선 테스트 할 클래스와 동일한 클래스 이름에서 뒤에 Test라고 붙인 클래스를 생성 해주었다.

예시) MemberService -> MemberServiceTest

특징

  • JUnit이라는 프레임워크를 사용해서 테스트를 실행한다.
    main 메서드를 통해서 실행하거나, 웹 애플리케이션의 컨트롤러를 통해서 해당 기능을 실행하게 되면 반복 실행이 어렵고, 시간이 오래 걸리는데 이러한 단점을 해결해준다.

  • 테스트 코드는 독립성을 가져야 한다.
    테스트 순서에 따라서 의존성을 가지게 되면 다음 테스트에 영향을 줄 수 있다.

  • @BeforeEach, @AfterEach
    테스트 메서드들이 각각 실행 되기 전, 실행 후 이 어노테이션 아래에 있는 메서드가 실행되면서 테스트를 도와준다.

  • 테스트 메서드들의 네이밍을 한글로 해도 상관 없다.

@BeforeEach
//테스트가 서로 영향이 없도록 항상 새로운 객체를 생성하며 의존관계도 새로 맺어준다.
public void beforeEach(){
   memberRepository = new MemoryMemberRepository();
   memberService = new MemberService(memberRepository);
}
@AfterEach
public void afterEach(){
   memberRepository.clearStore();
}

@Test
public void 회원가입() throws Exception {

}

스프링 빈과 의존 관계

컨트롤러, 서비스, 레포지토리를 만들고 사용하기 전 스프링 빈과 의존관계를 주입 해주어야 한다.

@Autowired

스프링이 연관된 객체를 스프링 컨테이너에서 찾아서 넣어준다.
이렇게 객체 의존관계를 외부에서 넣어주는 것은 의존성 주입, DI (Dependency Injection)라고 부른다.
생성자가 1개만 있으면 @Autowired 는 생략할 수 있다.

private final MemberService memberService;

@Autowired
public MemberController(MemberService memberService) {
   this.memberService = memberService;
}
      

스프링 빈을 등록하는 방법

  • 컴포넌트 스캔(실무에서 많이 사용)
    @Component 애노테이션이 있으면 스프링 빈으로 자동 등록되며,
    @Component를 포함하는 애노테이션도 자동 등록 된다.
    (@Controller, @Service ,@Repository)

  • 자동 의존관계 설정 자바 코드로 직접 스프링 빈 등록
    정형화 되지 않거나, 상황에 따라 구현 클래스를 변경해야 하면 설정을 통해 스프링 빈으로 등록한다.

@Configuration
public class SpringConfig {

  @Bean
  public MemberService memberService() {
    return new MemberService(memberRepository());
  }

  @Bean
  public MemberRepository memberRepository() {
    return new MemoryMemberRepository();
  }

}

h2 DataBase

로컬 개발에서 편하게 사용할 수 있는 h2 DataBase를 연동하여 사용하였는데 설치, 특징 세팅을 다른 포스팅에 정리해보았다.
h2 DataBase 바로가기

JPA

JPA는 기존의 반복 코드와 기본적인 SQL을 JPA가 직접 만들어서 실행해주어서 개발 생산성을 크게 높일 수 있다.
개발하면서 마이바티스로 SQL문을 하나하나 매핑해서 썼는데 JPA로 구현하는 것을 듣고 정말 놀라웠다. 공부를 해두면 편하게 개발할 것 같다.

build.gradle 설정

내부에 jdbc 관련 라이브러리를 포함한다.

implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

application.properties 설정

#JPA가 생성하는 SQL을 출력
spring.jpa.show-sql=true

#테이블을 자동으로 생성: none, create
spring.jpa.hibernate.ddl-auto=none

JPA 엔티티 매핑

@Entity 매핑을 해주고, getter, setter를 적어준다.

@Entity
public class Member {

@Id @GeneratedValue(strategy = GenerationType.IDENTITY)

 private Long id;
 private String name;
 
 //getter, setter
}

JPA 회원 리포지토리

JPA는 객체 상태를 영속성 상태라고 하는 기준에 의거하여 Hibernate가 객체를 관리한다. 무슨 말인지 모르겠기 때문에 일단 넘어가고 더 찾아봐야겠다.

public class JpaMemberRepository implements MemberRepository {

  //EntityManager를 추가해준다.
  private final EntityManager em;

  public JpaMemberRepository(EntityManager em) {
        this.em = em;
  }

  public Member save(Member member) {
        em.persist(member);
        return member;
  }  

}

서비스 계층에 트랜잭션 추가

JPA를 통한 모든 데이터 변경은 트랜잭션 안에서 실행해야 한다.
스프링은 클래스의 메서드를 실행할 때 트랜잭션을 시작하고, 메서드가 정상 종료되면 트랜잭션을 커밋한다. 런타임 예외가 발생하면 롤백한다.

import org.springframework.transaction.annotation.Transactional

//서비스는 비지니스에 의존적 설계
@Transactional
public class MemberService {

}

스프링 설정 변경

스프링 데이터 JPA 회원 리포지토리를 사용하도록 스프링 설정 변경한다.

@Configuration
public class SpringConfig {

  private final EntityManager em;
  
  public SpringConfig(DataSource dataSource, EntityManager em) {
       this.dataSource = dataSource;
       this.em = em;
  }

  @Bean
  public MemberRepository memberRepository() {         
       return new JpaMemberRepository(em);
  }
}

AOP(Aspect Oriented Programming)

공통 관심 사항과 핵심 기술 사항을 분리하여 구현할 때 적용한다.
AOP를 적용하면 핵심 사항, 공통 사항끼리 유지할 수 있으며 변경이 필요하면 이 로직만 변경하면 된다.

예시) 시간 측정 AOP: 시간을 측정하는 로직을 모든 메서드에 추가하기.

AOP 적용 전

service에서 모든 메서드에 시간 측정 로직을 개별적으로 추가하였다.

//공통 로직 내용
long start = System.currentTimeMillis();
	try{
    	//구현해야 하는 서비스
		validateDuplicateMember(member); //중복 회원 검증
		memberRepository.save(member);
		return member.getId();
	}finally {
   		//공통 로직 내용
		long finish = System.currentTimeMillis();
        long timeMs = finish - start;
		System.out.println("join = " + timeMs + "ms");
}

AOP 적용 후

공통 관심 사항을 적용할 범위(패키지나 서비스 등등)를 적는다.

//hello hellospring 아래에 있는 모든 로직 체크
@Around(("execution(* hello.hellospring..*(..))"))

공통 관심 사항을 적는다.

public Object execute(ProceedingJoinPoint joinPoint) throws Throwable{
        long start = System.currentTimeMillis();
        System.out.println("START: " + joinPoint.toString());
        try{
            return joinPoint.proceed();
        }finally{
            long finish = System.currentTimeMillis();
            long timeMs = finish - start;
            System.out.println("END:"+joinPoint.toString() +" " + timeMs + "ms");
         }
 }

실행화면
hello hellospring 아래에 있는 모든 메서드가 실행되었다.

마치며

수업 내용을 들으며 Controller, Service, Repository, Config 등 각각의 역할을 뚜렷하게 분리하여 개발하는 환경을 보아서 좋았고, 깊지도 너무 얕지도 않게 입문 수업이 구성되어 있어서 문법이나 JPA, AOP, 테스트 코드 등 더 깊게 들어갔을 때 얼마나 개발이 편리해질까 기대되었다.
아주 알찬 수업이었다. 김영한 개발자님 사랑합닏,,ㄷ..
아무튼 이어서 더 들어봐야겠다. ^_^

인프런 스프링 입문 바로가기

profile
천천히 꾸준히

0개의 댓글