wasup
Spring) AOP( Aspect Oriented Programming ) / 관점지향 프로그래밍 본문
반응형
AOP
: 모든 메소드 호출 시간을 측정하고 싶을 때
: 회원 가입 시간, 회원 조회 시간을 측정하고 싶을 때
Aspect Oriented Programming : 관점지향 프로그래밍 : 공동관심사항과 핵심관심사항을 분리
시간 측정의 로직을 별도의 공통 로직으로 만든 결과
: 핵심 관심 사항을 깔끔하게 유지
: 변경이 필요한 경우 해당 로직만 변경 가능
: 원하는 적용 대상을 선택 가능
//패키지명 아래있는 클래스 모두
@Around("execution(* com.was.waspj..*(..))")
//서비스 아래있는 클래스 모두
@Around("execution(* com.was.waspj.service..*(..))")
Controller -> Service -> Repository
프록시 Controller -> 실제 Controller -> 프록시 Service -> 실제 Service -> 프록시 Repository -> 실제 Repository
* AOP 적용 전에는 컨트롤러가 서비스를 바로 의존하는 관계였다.
* AOP 적용 후에는 컨트롤러는 서비스를 의존하기 전에 가짜 서비스(프록시)를 만들어낸다
@Autowired
public MemberController(MemberService memberService) {
this.memberService = memberService;
System.out.println("memberService = " + memberService.getClass());
}
Service = class com.was.waspj.service.Service$$EnhancerBySpringCGLIB$$8639ea25
* 프록시가 끝나면 joinPoint.proceed(); 으로 다음 메소드를 실행한다.
Controller
package com.was.waspj.controller;
import com.was.waspj.domain.Member;
import com.was.waspj.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import java.util.List;
@Controller
public class MemberController {
//private final MemberService memberService = new MemberService();
//->MemberService를 가져다 써야하는데
//->다른 소스블럭에서 매번 가져다 쓰면 문제가 있음?
private MemberService memberService;
//필드 주입
//@Autowired private MemberService memberService;
//setter 주입 : 단점이라면 public으로 노출됨.
// @Autowired
// public void setMemberService(MemberService memberService) {
// this.memberService = memberService;
// }
//생성자 주입
@Autowired
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
@GetMapping("/members/new")
public String createForm(){
return "members/createMemberForm";
}
@PostMapping("/members/new")
public String create(MemberForm form){
Member member = new Member();
member.setName(form.getName());
//System.out.println("member : " + member.getName());
memberService.join(member);
return "redirect:/";
}
@GetMapping("/members")
public String list(Model model){
List<Member> members = memberService.findMembers();
model.addAttribute("members", members);
return "members/memberList";
}
}
Service
package com.was.waspj.service;
import com.was.waspj.domain.Member;
import com.was.waspj.repository.MemberRepository;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Optional;
@Transactional
public class MemberService {
private final MemberRepository memberRepository;
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
/*
* 회원가입
* */
public Long join(Member member){
//같은 이름이 있는 중복 회원은 안됨.
//ifPresent : result가 null이 아니고 어떤 값이 있는경우 동작함.
//값을 바로 꺼내고싶다면 .get을 사용하면 되지만 권장되지 않음.
//.orElseGet : 값이 있으면 꺼내고 없으면 어떤 메서드를 실행.
//Optional<Member> result = memberRepository.findByName(member.getName());
//Oprional로 꺼내는 것 보다 아래처럼
validateDuplicateMember(member);//중복 회원 검증
//통과하면
memberRepository.save(member);//가입
return member.getId();
}
private void validateDuplicateMember(Member member) {
memberRepository.findByName(member.getName())
.ifPresent(m ->{
throw new IllegalStateException("이미 존재하는 회원입니다.");
});
}
/*전체회원 조회*/
public List<Member> findMembers(){
return memberRepository.findAll();
}
/*회원id 반환*/
public Optional<Member> findOne(Long memberId){
return memberRepository.findById(memberId);
}
}
Repository
package com.was.waspj.repository;
import com.was.waspj.domain.Member;
import java.util.List;
import java.util.Optional;
public interface MemberRepository {
Member save(Member member);
Optional<Member> findById(Long id);
Optional<Member> findByName(String name);
//Optional : 자바8부터 생겼음.
//값이 없을 때 null을 Optional로 감싸서 반환하는 방법이 선호되고있음
List<Member> findAll();
}
package com.was.waspj.repository;
import com.was.waspj.domain.Member;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface SpringDataJpaMemberRepository extends JpaRepository<Member, Long>, MemberRepository{
@Override
Optional<Member> findByName(String name);
}
Aop
package com.was.waspj.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//->SpringConfig에 직접등록하는것이 더 좋음.
public class TimeTraceAop {
// 패키지명 아래있는 클래스 모두
@Around("execution(* com.was.waspj..*(..))")
public Object execute(ProceedingJoinPoint joinPoint) throws Throwable{
//@Around()
long start = System.currentTimeMillis();
System.out.println("시작 : " + joinPoint.toString());
try{
//.proceed(); -> 다음 메소드로 진행
return joinPoint.proceed();
}finally {
//로직이 끝날 때 그리고 예외 발생 유무와 상관 없이 System.currentTimeMillis();를 확인 -> finally
long finish = System.currentTimeMillis();
long timeMs = finish - start;
System.out.println("끝 : " + joinPoint.toString() + " " + timeMs + "ms");
}
}
}
SpringConfig
package com.was.waspj;
import com.was.waspj.aop.TimeTraceAop;
import com.was.waspj.repository.MemberRepository;
import com.was.waspj.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.sql.Time;
@Configuration
public class SpringConfig {
private final MemberRepository memberRepository;
//생성자가 하나인경우 @Autowired 생략가능
public SpringConfig(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
@Bean
public MemberService memberService(){
return new MemberService(memberRepository);
}
// @Bean
// public TimeTraceAop timeTraceAop(){
// return new TimeTraceAop();
// }
}
반응형
'IT > Java' 카테고리의 다른 글
Spring Legacy MiNi Project - STS / board view (0) | 2021.08.11 |
---|---|
Spring Legacy MiNi Project - STS / board java (0) | 2021.08.10 |
Spring Legacy MiNi Project - STS / member view (0) | 2021.08.09 |
Spring) JDBC / jdbcTemplate / JPA / spring data JPA (0) | 2021.08.08 |
JUnit) 단위테스트와 통합테스트 (0) | 2021.08.07 |
Comments