Spring boot

[김영한 스프링 입문] 주요 이론 정리

코앤미 2023. 1. 10. 21:09

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8

 

[무료] 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술 - 인프런 | 강의

스프링 입문자가 예제를 만들어가면서 스프링 웹 애플리케이션 개발 전반을 빠르게 학습할 수 있습니다., - 강의 소개 | 인프런...

www.inflearn.com

김영한님의 스프링 입문 강의 속 내용 중 이론적인 포인트를 위주로 몇가지 내용을 추가하여 작성하였습니다.

 

 

 MVC 

기본적인 MVC 구조. return으로 위치(html)잡고 model에 데이터를 담아 뷰 리졸버에 전달. -> html

 

@RespondeBody 

뷰 리졸버를 사용하지 않고, HTTP의 Body에 내용을 직접 반환 -> Jason 타입으로 객체가 변환된다.

 

 

 

@Autowired

생성자에 @Autowired를 붙이면 스프링이 연관된 객체를 스프링 컨테이너에서 찾아서 주입한다. ( 생성자 주입, DI)

*단, 스프링 빈에 등록 되있어야만 가능하다.

위의 예시에서는 @Controller를 통해 MemberController class가 Controller임을 빈에 명시하고, 스프링이 자동으로

해당 클래스를 빈에 등록하는 컴포넌트 스캔방식으로 등록된 것.

 

빈 등록 방식

- 컴포넌트 스캔: 어노테이션을 통한 자동 등록

- 자바 코드로 직접 스프링 빈 등록

 

1) 컴포넌트스캔

- @Compenent 애노테이션을 붙이면, 스프링 빈에 자동 등록된다.

 

@Compenent

-@Service, @Controller,@Repository 를 포함한다.

@Controller: 해당 클래스가 컨트롤러 계층임을 암시 + 스프링 빈 등록 과 같은 느낌

 

2) @Configuration으로 직접 빈 등록

 

@Configuration   //빈 등록하는 configuration임을 어노테이션으로 명시
public class SpringConfig {
	@Bean  //빈 객체 등록
    public MemberService memberService(){
    	return new MemberService(memberRepository());
    }
}

따로 Configuration을 위한 class를 만들어서 빈을 등록한다.

 

 

DB접근 방식

Jdbc-> JPA -> Spring Data JPA

 

 Jdbc (사용할 일이 거의 없다, 참고만) 

 

 

 

 

JPA: (Java Persistence API)

why? 

ORM (Object Relational Mapping): POJO 클래스를 Relational 데이터베이스에 mapping하는 기술. 

즉 순수 자바 클래스 <> Relational DB 사이의 징검다리 같은 역할이다.

(그래서 Object Relational Middleware로도 불린다)

JDBC만을 사용한다면

 

1) DB 접근을 위한 쿼리 작성

2) DB에서 데이터 가져오기

3) 해당 데이터를 POJO 클래스에 넣기

 

위 작업들을 모두 프로그래머가 수행해야한다.  

이를 편하게 해주는 것이 JPA

이러한 내부 작업들은 JPA가 수행하고, 프로그래머는 그 결과로 생성된 POJO 클래스를 곧바로 이용할 수 있게 하는 것.

 

@Entity
@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
@ToString(exclude="writer") //해당 클래스의 모든 멤버 변수를 출력한다. >> Member객체인 Writer에 Lazy적용했기에 제외한다.

public class Board extends BaseEntity{  //Member의 Email값 (P.K) 를 F.K 로 참조한다.
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) // 고유한 키 자동 생성
    private  Long bno;

    private  String title;

    private String content;

    @ManyToOne(fetch=FetchType.LAZY)
    private Member writer;  

    public void changeTitle(String title){
        this.title=title;

    }

    public void changeContent(String content){
        this.content=content;
    }

}

위 예시를 참고하자.

 

그리고 "Board"라는 클래스는 여러 인스턴스를 형성할 수 있다. 

ex: title="BatMan" 인 Board 인스턴스, title="SuperMan"인 Board 인스턴스.

 

JPA는 객체 지향적인 코드와 Relational DB 사이에 다음과 같은 중간다리를 형성해준다.

 

클래스의 title, content같은 값들 == Relational DB의 "Attribute"

ex: Board라는 "클래스" 는 title,bno,writer 등 여러 정보를 지니고 있다.

 

클래스의 각 instance  == Relational DB의 "Tuple"

ex:  "Board"라는 클래스는 여러 인스턴스를 형성할 수 있다.

ex: title="BatMan" 인 Board 인스턴스, title="SuperMan"인 Board 인스턴스.

각 인스턴스는 title, content,... 등등의 값을 한개씩 보유.

 

클래스 -> Relational DB의 "Table" 

ex: Board 클래스의 각 인스턴스(튜플) 들은  bno,title, content, writer (어트리뷰트) 등 데이터를 가진다.

 

이를 통해 우리는 번거로운 작업 없이, 순쉽게 Java와 Relational DB 사이를 오갈 수 있는 것이다.

 

 

스프링 데이터 JPA

save(Entity), deletebyId 등 기본적인 CRUD 혹은FindById( id ) 와 같은 자주 쓰이는 내용들을 

JpaRepository 인터페이스를 상속받는 것으로 모두 사용할 수 있게 해준다.

 

public interface BoardRepository extends JpaRepository<Board,Long> { 엔티티, PK 타입> (findbyID의 파라미터 타입을 정의한다)

    @Query("select b,w from Board b left join b.writer w where b.bno=:bno")
    Object getBoardWithWriter(@Param("bno") Long bno); 해당 함수로 위의 쿼리문 트리거.

이렇게 JpaRepository<En,type> 만 extend  해주면, FindById( Long id ) 와 같은 기본적인 메소드를 정의 없이 사용할 수 있다. 

 

만약 기본적인 형태에서 원하는 쿼리를 찾을 수 없을 시, 위 와같이 @Query 어노테이션을 통해서 JPQL로

쿼리를 정의해주면 된다.

 

만약 다양한 타입의 엔티티(클래스) 가 뒤섞인 복잡한 동적 쿼리와 같은 경우, Querydsl을 사용해서 처리해주어야한다.

 

 

 

 

AOP

why? 

- 모든 메소드의 호출 시간을 측정할 때

- 공통 관심 사항 vs 핵심 관심 사항

- 회원 가입 시간, 학원 조회 시간을 측정하고 싶다면?

 

- 회원가입, 회원 조회 시간을 측정하는 기능은 주요한 기능, "핵심 관심 사항" 이 아닌 "공통 관심 사항" 이다.

- 시간을 측정하는 로직이 핵심 비즈니스 로직과 섞인다면 유지보수가 어려워진다.

- 시간 측정 로직을 변경하려면 모든 로직을 찾아가서 일일이 변경해야 한다.

 

위와 같은 이유들로 각 계층에서 처리하고, 공통으로 처리하는 것은 매우 어렵다.

 

 

AOP 적용

 

아래는 핵심 로직에서 분리하여, 따로 공통된 시간 측정 로직을 생성한 것이다.

@Around 어노테이션을 붙이면, 스프링 프레임워크에서 AOP를 구현한 것으로 인식하고, AOP 구현을 위한

proxy 생성들의 작업을 자동으로 해준다.

 

@Before ( "${pattern}" )

지정한 패턴에 해당하는 메소드가 실행되기 전에, interceptor와 같이 동작하는 것을 의미.

해당 어노테이션이 붙은 메소드의 반환 값은 void여야한다.

 

@After ( "${pattern}" )

지정한 패턴이 실행된 후 동작한다.

이 어노테이션이 붙은 메소드의 반환 값은 Object여야한다.

 

@Around ( "${pattern}" )

지정한 패턴이 실행되기 전, 후 모두에서 동작한다.

이 어노테이션이 붙은 메소드의 반환 값은 Object여야한다.

 

즉 위의 코드는 hello.helloSpring. 의 하위의 모든 요소가 실행되기 전, 실행된 후에 해당 로직을 수행하는 AOP 를 작성한 것이다. 

 

 

 

 

AOP 적용 전 의존 관계

AOP 적용 후 의존 관계

 

AOP 적용 전 전체 흐름

AOP 적용 후 전체 흐름