김영한님의 스프링 입문 강의 속 내용 중 이론적인 포인트를 위주로 몇가지 내용을 추가하여 작성하였습니다.
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 적용 후 전체 흐름
'Spring boot' 카테고리의 다른 글
Spring security란? (0) | 2023.01.25 |
---|---|
자바 Stream 정리 [Stream, Map, Filtering, Sorted, Collect] (0) | 2023.01.15 |
[toyProject] 게시물 사이트 Part 3 (0) | 2023.01.10 |
[toyProject] 게시물 사이트 Part 2 (0) | 2023.01.10 |
[toyProject] 게시물 사이트 Part 1 (0) | 2023.01.10 |