2021. 8. 20. 08:00ใBack-End ์์ ์ค/Spring Framework
์๋ ํ์ธ์? ์ฃผ๋ํ๋ ์ ๋๋ค.
์ค๋์ AOP์ ๋ํด ๊ณต๋ถ ํด ๋ณด๋๋ก ํ ๊ฒ์ด์์.
๋ฐ๋ก ์์ ํด ๋ณด๊ฒ ์ต๋๋ค!
์ฝ๋์ ๊ด๋ จํ ๋ด์ฉ์ ์ฃผ๋ํ๋์ Github์์ ํ์ธ ํ์ค ์ ์์ต๋๋ค!
๐ ๋ชฉ์ฐจ
01.[Spring Boot] thymeleaf์ Spring Boot
02.[Spring Boot] Spring Web ๊ฐ๋ฐ ๊ธฐ์ด
03.[Spring Boot] ํ์ ๊ด๋ฆฌ ์์ - Backend
04.[Spring Boot] Service ๊ฐ๋ฐ ๋ฐ Test Case ์์ฑ
05.[Spring Boot] Spring Bean๊ณผ ์์กด๊ด๊ณ
06.[Spring Boot] Java Code๋ก ์ง์ Spring Bean ๋ฑ๋ก
07.[Spring Boot] ๋ฑ๋ก, ๋ชฉ๋ก ๋ณด๊ธฐ ๊ตฌํํ๊ธฐ
08.[Spring Boot] ๊ธฐ์กด ์ฝ๋ ์ ์๋๊ณ , ์ค์ ์ผ๋ก ๊ตฌํ Class ๋ณ๊ฒฝ
09.[Spring Boot] ํตํฉ Test
10.[Spring Boot] JPA
11.[Spring Boot] Spring Data JPA
12.[Spring Boot] AOP
๐ AOP; Aspect Oriented Programming(๊ด์ ์งํฅ ํ๋ก๊ทธ๋๋ฐ)
AOP๋ ์ด๋ค Logic์ ๊ธฐ์ค์ผ๋ก ํต์ฌ์ ์ธ ๊ธฐ๋ฅ๊ณผ ๋ถ๊ฐ์ ์ธ ๊ธฐ๋ฅ์ ๋๋์ด์ ๊ทธ ๊ด์ ์ ๊ธฐ์ค์ผ๋ก ๊ฐ๊ฐ ๋ชจ๋ํ ํ๋ ๊ฒ์ด์์.
๋ชจ๋ํ๋ผ๋ ๊ฒ์ ์ด๋ค ๊ณตํต๋ Logic์ด๋, ๊ธฐ๋ฅ์ ํ๋์ ๋จ์๋ก ๋ฌถ๋ ๊ฒ์ ๋งํ๋ต๋๋ค!
๋ง์ฝ ์ฐ๋ฆฌ๊ฐ ๊ตฌํํ Service, Repository ๋ฑ์ ๊ฐ Method ๋์ ์๊ฐ์ ์๊ณ ์ถ๋ค๋ฉด ์ด๋ป๊ฒ ํด์ผ ํ ๊น์?
๊ฐ๊ฐ Method์ ์๊ฐ์ ์ธก์ ํ๋ Coding์ ํด์ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ๋ ์๊ฒ ์ง๋ง, ์ด๊ฒ์ AOP๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ํ ๋ฒ๋ง ์์ฑํ๋ฉด ๋๋๊ฒ ๋๋ ๊ฒ์ด์์.
๋จผ์ ๊ฐ๊ฐ Method์ ์๊ฐ์ ์ธก์ ํ๋ Code๋ฅผ ๋ด๋ณผ๊ฒ์!
MemberService.java
package hello.hellospring.service;
import hello.hellospring.domain.Member;
import hello.hellospring.repository.MemberRepository;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Optional;
// ์ปดํฌ๋ํธ ์ค์บ ๋ฐฉ์์ Service
//@Service
@Transactional
public class MemberService { // Service ์ชฝ์ ๋น์ฆ๋์ค ์ฉ์ด์ ๋ง๊ฒ ์ด๋ฆ ๋ฑ์ ์ ์ด์ผ ํ๋ค.
// ์๋ ๋ด์ฉ์์ repository ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ , Service Test์์ ๋ new๋ฅผ ํตํด Repository๋ฅผ ์์ฑํด์ ํ
์คํธํ๋ฉด ์๋ก ๋ค๋ฅธ ๊ฐ์ฒด๋ฅผ ์ด์ฉํ๊ฒ ๋๋ค.
// private final MemoryMemberRepository memberRepository = new MemoryMemberRepository();
// ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์ ์๋์ ๊ฐ์ด ์์ฑ์๋ฅผ ํตํด ์ธ๋ถ์์ ์ ๊ทผํ ์ ์๋๋ก ํด ์ค๋ค.
private final MemberRepository memberRepository;
// @Service๊ฐ ์๋ Service๊ฐ ๊ฐ์ฒด๊ฐ ์์ฑ๋ ๋, @Autowired๊ฐ ๋ถ์ ์์ฑ์๋ ์คํ๋ง์ด ์ปจํ
์ด๋์์ ๋น์ผ๋ก ๊ด๋ฆฌํ ๋, ์์ฑ์๋ฅผ ํธ์ถํ๋๋ฐ, ์ด ๋ MemberService๋ฅผ ๋ฃ์ด์ค๋ค.
// @Autowired
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
} // ์์ฑ์ ๋
// ํ์ ๊ฐ์
public Long join(Member member) {
long start = System.currentTimeMillis(); // Method ํธ์ถ์ ์์ ์๊ฐ์ ์ธก์ ํ๊ธฐ ์ํ ๋ณ์ ์ ์ธ
// ๊ฐ์ ์ด๋ฆ์ด ์๋ ์ค๋ณต ํ์ ๊ฐ์
๋ฐฉ์ง
// Optional<Member> result = memberRepository.findByName(member.getName());
//
// result.ifPresent(memeber -> { // ifPresent๋ ํด๋น ๊ฐ์ด Null์ด ์๋๊ณ , ์ด๋ค ๊ฐ์ด ์์ผ๋ฉด ๋์ (Option๋ก ๊ฐ์ธ๋ฉด ์ฌ์ฉ ๊ฐ๋ฅ)
// throw new IllegalStateException("์ด๋ฏธ ์กด์ฌํ๋ ํ์ ์
๋๋ค.");
// });
// ์์ ์ฝ๋ ๋ณด๋ค ๋ ์ข์ ์ฝ๋
// memberRepository.findByName(member.getName()).ifPresent(member1 -> {
// throw new IllegalStateException("์ด๋ฏธ ์กด์ฌํ๋ ํ์ ์
๋๋ค.")
// });
// ์์ ์ฝ๋๋ฅผ Method ํ ํ๋ ๊ฒ์ด ์ข๋ค.
// ํด๋น ์ฝ๋๋ฅผ ๋ชจ๋ ์ ํํ๊ณ , Command + Option + M์ ๋๋ฌ์ค๋ค.
try {
validateDuplicationMember(member); // ์ค๋ณต ํ์ ๊ฒ์ฆ
memberRepository.save(member);
return member.getId();
} finally {
long finish = System.currentTimeMillis();
long timeMs = finish - start;
System.out.println("join Method ๋์ ์๊ฐ์ " + timeMs + "ms ์
๋๋ค.");
}
} // join() ๋
private void validateDuplicationMember(Member member) {
// ์์ ์ฝ๋ ๋ณด๋ค ๋ ์ข์ ์ฝ๋
memberRepository.findByName(member.getName()).ifPresent(member1 -> {
throw new IllegalStateException("์ด๋ฏธ ์กด์ฌํ๋ ํ์ ์
๋๋ค.");
});
} // validateDuplicationMember() ๋
public List<Member> findMembers() {
long start = System.currentTimeMillis();
try {
return memberRepository.findAll();
} finally {
long finish = System.currentTimeMillis();
long timeMs = finish - start;
System.out.println("findMembers Method ๋์ ์๊ฐ์ " + timeMs + "ms ์
๋๋ค.");
} // try ๋ฌธ ๋
} // findMembers() ๋
public Optional<Member> findOne(Long memberId) {
return memberRepository.findById(memberId);
} // findOne() ๋
} // Class ๋
์ฃผ๋ํ๋์ join(), findMembers()์ ๋์ ์์ ์๊ฐ๊ณผ ๋๋๋ ์๊ฐ์ ๋ํ Coding์ ํ ๊ฒ์ด์์.
System.currentTimeMillis()๋ ๊ทธ Method๊ฐ ํธ์ถ๋ ์๊ฐ์ ์ฐ๋ Method์ด๋ฉฐ, ๋จ์๋ ms์ธ ๊ฒ์ด์์!
์์์ ๋ณด๋ฏ์ด ๊ฐ Method์ ์ด๋ฐ Logic์ ์ถ๊ฐํ๋ค๋ฉด ๋ช ๊ฐ ์๋๋ Method๋ผ๋ฉด ํด ๋ณผ๋ง ํ์ง๋ง, ๊ทธ๊ฒ ๋ช ๋ง๊ฐ์ ๋ ๋๋ค๋ฉด ์ด๋ป๊ฒ ๋ ๊น์? ์๋ง ํผ๋ฅผ ํ ํ๊ฒ ๋ ๊ฒ์ด์์.
์ด๋ ๊ฒ ํ๋ฉด ๋ฌธ์ ์ ์ ์๋์ ๊ฐ์ต๋๋ค.
- ํ์๊ฐ์ , ํ์ ์กฐํ์ ์๊ฐ์ ์ธก์ ํ๋ ๊ธฐ๋ฅ์ ํต์ฌ ๊ด์ฌ ์ฌํญ์ด ์๋
- ์๊ฐ์ ์ธก์ ํ๋ Logic์ ๊ณตํต ๊ด์ฌ ์ฌํญ
- ์๊ฐ์ ์ธก์ ํ๋ Logic๊ณผ ํต์ฌ ๋น์ฆ๋์ค Logic์ด ์์ฌ ์ ์ง๋ณด์๊ฐ ์ด๋ ต๋ค.
- ์๊ฐ์ ์ธก์ ํ๋ Logic์ ๋ณ๋์ ๊ณตํต Logic์ผ๋ก ๋ง๋ค๊ธฐ ๋งค์ฐ ์ด๋ ต๋ค.
- ์๊ฐ์ ์ธก์ ํ๋ Logic ๋ณ๊ฒฝ ์ ๋ชจ๋ Logic์ ์ฐพ์๊ฐ๋ฉด์ ๋ณ๊ฒฝํด์ผ ํ๋ค.
์ด๋ฅผ ์ํด AOP๋ผ๋ ๊ธฐ๋ฅ์ ํตํด ํด๊ฒฐ์ ํ ์ ์๋ต๋๋ค!
๊ฒฐ๊ตญ AOP๋ ๊ณตํต ๊ด์ฌ์ฌํญ (Cross-cutting Concern)๊ณผ ํต์ฌ ๊ด์ฌ ์ฌํญ (Core Concern)์ ๋ถ๋ฆฌ ์ํค๋ ๊ฒ์ ๋๋ค.
TimeTraceAop.java
package hello.hellospring.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component // ์ด๋ ๊ฒ ํด์ Bean์ ๋ฑ๋กํ๋ ๋ฐฉ๋ฒ์ด ์๊ณ , SpringConfig์ @Bean์ ์ฌ์ฉํ์ฌ ๋ฑ๋กํ๋ ๋ฐฉ๋ฒ์ด ์๋ค.
public class TimeTraceAop { // MemberService Method ๋์ ์๊ฐ์ ์์๋ณด๊ธฐ ์ํ AOP
@Around("execution(* hello.hellospring..*(..))") // hello.hellospring ๋ฐ์ ๋ชจ๋ ๋ด์ฉ์ ์๋ Method ๋ชจ๋ ์ ์ฉ
public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
System.out.println("START : " + joinPoint.toString() + " ์ Method ๋์ ์๊ฐ Test๊ฐ ์์ํฉ๋๋ค!");
try {
// Object proceed = joinPoint.proceed();// ๋ค์ Method๋ก ์งํ
// return proceed;
// ์์ Code Inline์ผ๋ก ํฉ์น ๋ชจ์ต
return joinPoint.proceed();
} finally {
long finish = System.currentTimeMillis();
long timeMs = finish - start;
System.out.println("END : " +joinPoint.toString() + " ์ Method ๋์ ์๊ฐ์ " + timeMs + "ms ์
๋๋ค!");
} // try ๋ฌธ ๋
} // excute() ๋
} // Class ๋
์์ ๊ฐ์ด AOP๋ฅผ ์ฌ์ฉํ๊ฒ ๋๋ฉด ์ด๋ค ๋ถ๋ถ์ด ์ข์์ง๊น์?
- ํ์๊ฐ์ , ํ์ ์กฐํ ๋ฑ ํต์ฌ ๊ด์ฌ์ฌํญ๊ณผ ์๊ฐ ์ธก์ ๊ณตํต ๊ด์ฌ ์ฌํญ์ด ๋ถ๋ฆฌ๋๋ค.
- ์๊ฐ์ ์ธก์ ํ๋ Logic์ ๋ณ๋ ๊ณตํต Logic์ผ๋ก ๊ตฌ์ฑํ ์ ์๋ค.
- ํต์ฌ ๊ด์ฌ ์ฌํญ์ ๊น๋ํ๊ฒ ์ ์งํ ์ ์๋ค.
- ๋ณ๊ฒฝ์ด ํ์ํ ๋ ์ด Logic๋ง ๋ณ๊ฒฝํ๋ฉด ๋๋ค.
- ์ํ๋ ์ ์ฉ ๋์์ ๋ง์๋๋ก ์ ํํ ์ ์๋ค.
@Aspect : ๋ถ๊ฐ์ ๊ธฐ๋ฅ์ ๋ํ ๋ด์ฉ๋ค์ ๋ชจ๋ํ ํ ๋ ์ฌ์ฉํ๋ Annotion ๊ณตํต์ผ๋ก ์ ์ฉํ ๊ธฐ๋ฅ์ ๊ตฌํํ ๊ฒฝ์ฐ ์ฌ์ฉ
์ฆ, ํด๋น Class๊ฐ ๋ถ๊ฐ ๊ธฐ๋ฅ์ ๋ํ Class์์ ์๋ ค์ฃผ๋ Annotion
@Component : AOP๋ฅผ Spring Bean์ ๋ฑ๋กํ๊ธฐ ์ํด ๋ช
์ (@Aspect๋ฅผ ๋ช
์ ํ๋ค๊ณ ํ์ฌ ์๋์ผ๋ก
Spring Bean์ ๋ฑ๋ก๋์ง ์๊ธฐ ๋๋ฌธ์ ๋ฐ๋ก Bean ๋ฑ๋ก์ ์ํด ์ฌ์ฉ)
SpringConfig์ @Bean์ ์ฌ์ฉํ์ฌ ๋ฑ๋กํ๋ ๋ฐฉ๋ฒ๋ ์กด์ฌ
@Bean
public TimeTraceAop timeTraceAop() { // aop/TimeTraceAop๋ฅผ Bean์ผ๋ก ๋ง๋ค๊ธฐ ์ํ Method
return new TimeTraceAop();
} // timeTraceAop() ๋
@Around : ๋์ Entity Method ์คํ ์ , ํ ๋๋ ์์ธ ๋ฐ์ ์์ ์ ๊ณตํต ๊ธฐ๋ฅ์ ์คํ
์ด๊ฒ์ Advice์ ํ ์ข
๋ฅ๋ก ํต์ฌ ๊ด์ฌ์ฌ์ ์คํจ ์ฌ๋ถ์ ์๊ด์์ด ์คํ๋๋๋ก ํ๋ Advice
- execution(์ ๊ทผ ์ ์ด์, ๋ฐํํ Package๋ฅผ ํฌํจํ Class Path Method Parameter)
@Around("execution(* hello.hellospring..*(..))") // hello.hellospring ๋ฐ์ ๋ชจ๋ ๋ด์ฉ์ ์๋ Method ๋ชจ๋ ์ ์ฉ
์ฒซ๋ฒ์งธ์ ๋ช
์๋ *์ ์ ๊ทผ์ ์ด์์ ๋ฐํํ ๋ชจ๋๋ฅผ ์๊ดํ์ง ์๊ณ , ์ ์ฉํ๊ฒ ๋ค๋ ์๋ฏธ.
hello๋ Project Directory ์ค java ๋ฐ์ ์๋ Package์ด๊ณ , ๊ทธ ๋ค์์ hellospring์ด๋ค.
์ฆ, hello ๋ฐ์ ์๋ ๋ชจ๋ ๋ด์ฉ์ ์๋ ๋ช
์๋ ๊ธฐ๋ฅ์ ์คํํ๊ฒ ๋ค๋ ์๋ฏธ์ด๊ณ ,
(..) ์ด๊ฒ์ ์๋ฏธ๋ Method Parameter๊ฐ ๋ช ๊ฐ๊ฐ ์กด์ฌํ๋์ง ์๊ด ์์ด ์คํํ๊ฒ ๋ค๋ ์๋ฏธ
๐ Spring AOP ๋์ ๋ฐฉ์
๐ AOP ์ ์ฉ ์ Class ๊ฐ ์์กด ๊ด๊ณ
AOP ์ ์ฉ ์ ์๋ MemberController๊ฐ MemberService๋ฅผ ์์กดํ๊ณ ์์ด Controller๊ฐ Service๋ฅผ ํธ์ถํ๋ ๊ด๊ณ ์์ต๋๋ค!
๐ AOP ์ ์ฉ ํ Class ๊ฐ ์์กด ๊ด๊ณ
Spring์ AOP๋ฅผ ๋ฐ๊ฒฌํ๊ฒ ๋๋ฉด ๊ฐ์ง Service๋ฅผ ๋ง๋ค๊ฒ ๋๋ ๊ฒ์ด์์. ์ด๊ฒ์ Proxy๋ผ๊ณ ๋ถ๋ฅธ๋ต๋๋ค!
์ฆ, Spring์ด ์ฌ๋ผ์ค๋ฉด์ Container์ Bean์ ๋ฑ๋กํ ๋, ์ง์ง Spring Bean์ด ์๋ Proxy Spring Bean์ ์์ ์ธ์๋๊ฒ ๋ฉ๋๋ค.
๊ทธ๋ฐ ๋ค ๊ฐ์ง Proxy์ ์์ ์ด ๋๋๋ฉด joinPoint.proceed()๋ฅผ ํ๋ฉด์ ์ด๊ฒ์ ๊ฒ ์์ ์ ํ ๋ค ์ง์ง Spring Bean์ ํธ์ถํ๋ ํํ๋ก ๋์ํ๊ฒ ๋๋ต๋๋ค!
๊ทธ๋์ Controller๊ฐ ํธ์ถํ๋ ๊ฒ์ Proxy ๊ธฐ์ ๋ก ๋ง๋ค์ด์ง ๊ฐ์ง Service๋ฅผ ํธ์ถํ๋ ๊ฒ์ด์์.
๐ AOP ์ ์ฉ ์ ์ ์ฒด ๊ตฌ์ฑ
๐ AOP ์ ์ฉ ํ ์ ์ฒด ๊ตฌ์ฑ
๐ ์ค์ Proxy ์ฃผ์ ์ฌ๋ถ Console ํตํด ํ์ธ
ํ์๋ ๊ณณ์ ๋ณด๋ฉด MemberService๋ก ๋๋๋ ๊ฒ์ด ์๋๋ผ EnhancerBy ๋ญ๋ผ๊ณ ๋ง ์ ํ์ ๋์ค๋ ๊ฒ์ด์์.
CGLIB๋ผ๊ณ , CGLibrary๋ฅผ ์ฌ์ฉํ์ฌ ํด๋น Service๋ฅผ ๋ณต์ ํ์ฌ ์กฐ์ํ๋ ๊ธฐ์ ์ธ ๊ฒ์ด์์.
์ด๋ฐ ๊ธฐ์ ์ ์ฌ์ฉํ์ฌ Proxy ๊ธฐ์ ์ ์ฌ์ฉํ๊ฒ ๋๋ต๋๋ค!
์ฃผ๋ํ๋์ ๊ธ์ด ๋ง์์ ๋์ จ๋์? ๊ตฌ๋ ๊ณผ ๊ณต๊ฐ! ๊ทธ๋ฆฌ๊ณ , ๋๊ธ์ ์ฃผ๋ํ๋์๊ฒ ๋ง์ ํ์ด ๋ฉ๋๋ค
'Back-End ์์ ์ค > Spring Framework' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[๋์ ๊ธฐ์ !] ํ ์คํธ ์ฝ๋ (0) | 2021.08.24 |
---|---|
[๋์ ๊ธฐ์ !] Web Layer (0) | 2021.08.23 |
[Spring Boot] Spring Data JPA (0) | 2021.08.19 |
[Spring Boot] JPA (0) | 2021.08.18 |
[Spring Boot] ํตํฉ Test (0) | 2021.08.17 |