
๐ Target : ๊ฐ๋ฐ์๊ฐ ์ง์ ๋ง๋ ์ฝ๋
๐ Proxy : Target์ ๊ฐ์ธ๊ณ ์๋ ๊ฐ์ฒด
๐ aspect : logging, transaction๊ณผ ๊ฐ์ ๊ธฐ๋ฅ์์ฒด๋ฅผ ์๋ฏธ
๐ advice : ์ค์ฒด, ํก๋จ๊ด์ฌ์ฌ ์ฝ๋(aspect๋ฅผ ์ค์ ๋ก ๊ตฌํํ ์ฝ๋)
๐ AOP์์ ์ฃผ๋ก ์ฌ์ฉ๋๋ ์ด๋ ธํ ์ด์ ์ผ๋ก๋ @Before / @Around๊ฐ ์๋๋ฐ
๐ @Before๋ ๋ฉ์๋์ ์ด๋ฆ์ ์์๋ด๊ธฐ ์ํด์ ์ฌ์ฉํ๋ค.
๐ @Around๋ ๊ฑธ๋ฆฐ์๊ฐ์ ์์๋ด๊ธฐ ์ํด์ ์ฌ์ฉํ๋ค.
package org.zerock.w2.aop;
@Aspect
@Component
@Log4j2
public class LogAdvice {
@Before("execution(* org.zerock.w2.service.*.*(..))")
// execution ๋ด๋ถ ์ฝ๋๋ service ์๋์ ๋ชจ๋ ๋ฉ์๋๋ค์ ํด๋น logBefore ๋ฉ์๋๋ฅผ ๊ฑฐ์ณ๊ฐ๋ค.
public void logBefore(JoinPoint joinPoint) {
log.info("-------------------------");
log.info("-------------------------");
log.info(Arrays.toString(joinPoint.getArgs()));
log.info("-------------------------");
log.info("-------------------------");
}
@Around("execution(* org.zerock.w2.service.*.*(..))")
public Object logBefore(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object result = joinPoint.proceed();
long end = System.currentTimeMillis();
log.info("TIME: "+ (end-start));
return result;
}
}
๐ JoinPoint joinPoint๋ ํ์ฌ ์คํ ์ค์ธ ๋ฉ์๋์ ๋ํ ์ ๋ณด๋ฅผ ๋ด๊ณ ์๋ ๊ฐ์ฒด๋ก, ๋ฉ์๋์ด๋ฆ, ๋งค๊ฐ๋ณ์๋ฑ๊ณผ ๊ฐ์ ์ฌ๋ฌ ์ ๋ณด๋ฅผ ์ ์ ์๋ค.
๐ joinPoint.getArgs()๋ฅผ ํตํด ํ์ฌ ๋ฉ์๋์ ์ธ์๋ค์ ๋ฐฐ์ด ํํ๋ก ๊ฐ์ ธ์จ ํ, ์ด๋ฅผ Arrays.toString()์ผ๋ก ๋ฌธ์์ด๋ก ๋ณํํ์ฌ ๋ก๊ทธ์ ๊ธฐ๋กํ๋ค.
๐ joinPoint.proceed()๋ฅผ ํตํด ์ค์ ํ๊ฒ ๋ฉ์๋๋ฅผ ์คํํ์ฌ result์ ์ ์ฅ
๐ ์ค์ ๋ฉ์๋๊ฐ ์คํ๋จ์ ๋ฐ๋ผ ์์์๊ฐ๊ณผ ์ข
๋ฃ์๊ฐ์ ํ์
ํ์ฌ ๋ฉ์๋ ์คํ์๊ฐ์ ํ์
ํ ์ ์๋ค.
๐ ๋๊ฐ์ง์ ์ผ์ ์ฒ๋ฆฌํ๊ธฐ ์ํ ๊ธฐ๋ฅ / Service์์๋ ๋ฌด์กฐ๊ฑด ์ฌ์ฉํด์ผํ๊ณ , ์์ธ์ฒ๋ฆฌ๋ฅผ ์ํด ์ฌ์ฉํด์ค์ผํ๋ค.
๐ ์๋ฅผ๋ค์ด, db์ table_a (varchar(10)), table_b (varchar(2))๊ฐ ์์๋, service์ ์ปจํธ๋กค๋ฌ,mapper ๋ฅผ ์ด์ฉํด์ ๊ฐ ํ ์ด๋ธ์ ๋ฌธ์์ ๊ธธ์ด๊ฐ 5์ธ sql๋ฌธ์ insertํ๋ ค๊ณ ํ๋ค. aํ ์ด๋ธ์๋ ๊ธธ์ด๊ฐ ์ ํฉํ์ง๋ง, bํ ์ด๋ธ์๋ ๊ธธ์ด๊ฐ ์ ํฉํ์ง ๋ชปํ์ํ์ด๋ค. ์ด๋ ๊ทธ๋ฅ ํ์์ฌ์ฉํ๋ฏ์ด ์ฝ๋๋ฅผ ์์ฑํ๊ฒ ๋๋ฉด ์ค๋ฅ๊ฐ ๋ฐ์์ด ๋์ง๋ง ๊ฒฐ๊ณผ์ ์ผ๋ก aํ ์ด๋ธ์๋ insert๊ฐ ๋์ง๋ง bํ ์ด๋ธ์๋ insert๊ฐ ๋์ง์๋๋ค.
๐ ํ์ง๋ง, service ๋ถ๋ถ์ @Transactional ์ด๋
ธํ
์ด์
์ ์ฌ์ฉํ์ฌ ์ฝ๋๋ฅผ ์์ฑํ๊ฒ ๋๋ค๋ฉด aํ
์ด๋ธ์๋ insert๊ฐ ๋๊ณ bํ
์ด๋ธ์๋ insert๊ฐ ๋๋ ค๋ค ์คํจ๋ฅผ ํด์ aํ
์ด๋ธ์ insert๊ฐ์ด rollback๋์ด ๋ ํ
์ด๋ธ ๋ชจ๋ insert๋์ง ์๋๋ค.
2-1. root-context.xml ๋ด๋ถ์ transactionManager, tx:annotation ์ถ๊ฐ
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven></tx:annotation-driven>
2-2.

๐ select๋ฌธ์์๋ readOnly = ture๋ฅผ ์ฌ์ฉํ์ฌ ์ฑ๋ฅ์ ์ต์ ํ ์ํฌ์์๋ค. (์ฝ๊ธฐ์ ์ฉ์ผ๋ก ๋ณ๊ฒฝํ๋๊ฒ์ด๋ฏ๋ก)
3-1. gradle ์ถ๊ฐ
implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.2'
3-2. ReplyController
package org.zerock.w2.controller;
import lombok.extern.log4j.Log4j2;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.zerock.w2.vo.ReplyVO;
@RestController // ์๋์ผ๋ก json์ผ๋ก ๋ณํ
@RequestMapping("/reply")
@Log4j2
public class ReplyController {
@PostMapping(value = "")
public ResponseEntity<ReplyVO> register( // ReplyVO๋ฅผ JSONํ์์ผ๋ก ๋ฐ๊ณ
@RequestBody ReplyVO replyVO) {
// requestBody๋ฅผ ํตํด JSONํ์์ ๋ฐ์ดํฐ๋ฅผ ReplyVO ๊ฐ์ฒด๋ก ๋ณํ
log.info("Reply vo: "+ replyVO);
// 200 ok ๋ฅผ ๋ํ๋ด๋
return ResponseEntity.ok(replyVO);
}
}
3-3. JSON์ ๋จ์
๐ ๊ท๊ฒฉํ๋ ๋ฐ์ดํฐ๋ฅผ ๋ง๋ค ์ ์๋ค.
๐ PK
๐ ๋
ผ๋ฆฌ์ ์๋ฏธ : ์๋ณ๊ฐ, ์ ๋ํฌ
๐ ๋ฌผ๋ฆฌ์ ์๋ฏธ : ์ธ๋ฑ์ค (์๋)
๐ FK
๐ ๊ฒ์๊ธ - ๋๊ธ ํ
์ด๋ธ์ ๊ด๊ณ์์, 1๋ฒ ๊ฒ์๊ธ์ ๋ํ ์ฌ๋ฌ ๋๊ธ์ด ์์๋, 1๋ฒ ๊ฒ์๊ธ์ด ์์ด์ง๊ฒ ๋๋ฉด ํด๋น ๋๊ธ๋ค์ ์๋ฏธ๊ฐ ์์ด์ง๋ฏ๋ก ๋ฐ์ดํฐ๋ฅผ ๊น๋ํ๊ฒ ์ ์งํ๊ธฐ ์ํด FK๋ฅผ ์ฌ์ฉํ๋ค.
alter table tbl_reply
add constraint fk_board_reply foreign key (bno)
references tbl_board(bno)
;
๐ ๊ฒ์๊ธ์ pk์ธ bno๋ฅผ ๋๊ธ ํ ์ด๋ธ์์ fk๋ก ์ฌ์ฉํ๊ฒ ๋ค๋ ์๋ฏธ