[스프링 입문] 스프링 예제 프로젝트 PetClinic 3

21587 단어 SpringSpring

스프링 AOP

Aspect Oriented Programming

다양한 AOP

  • 구현 방법 3가지
    • 컴파일
      • A.java —-AOP—-> A.class (제공 : AspectJ)
      • : 자바코드에는 없지만 컴파일을 한 코드에는 있는 것처럼 컴파일 해주는!
    • 바이트코드 조작
      • A.java → A.class ——AOP(위치 : 클래스 로더)——> 메모리 (제공 : AspectJ)
    • 프록시 패턴

프록시 패턴

  • 기존 코드 건드리지 않고 새 기능 추가하기

  • 프록시 패턴

  • Main에서의 클래스

    • main\java\org...\proxy\Store

      package org.springframework.samples.petclinic.proxy;
      
      public class Store {
      
      	Payment payment;
      
      	public Store(Payment payment) {
      		this.payment = payment;
      	}
      
      	public void buySomething(){
      		payment.pay(100);
      	}
      }
    • main\java\org...\proxy\Cash

      package org.springframework.samples.petclinic.proxy;
      
      public class Cash implements Payment{
      	@Override
      	public void pay(int amount) {
      		System.out.println(amount + " 현금 결제");
      	}
      }
    • main\java\org...\proxy\Payment

      package org.springframework.samples.petclinic.proxy;
      
      public interface Payment {
      	void pay(int amount);
      }
    • main\java\org...\proxy\CashPerf

      package org.springframework.samples.petclinic.proxy;
      
      import org.springframework.util.StopWatch;
      
      public class CashPerf implements Payment {
      
      	Payment cash = new Cash();
      
      	@Override
      	public void pay(int amount) {
      		StopWatch stopWatch = new StopWatch();
      		stopWatch.start();
      
      		cash.pay(amount);
      
      		stopWatch.stop();
      		System.out.println(stopWatch.prettyPrint());
      	}
      } //일종의 프록시
  • Test 확인

    • test\java\org...\proxy\StoreTest

      package org.springframework.samples.petclinic.proxy;
      
      import org.junit.jupiter.api.Test;
      
      import static org.junit.jupiter.api.Assertions.*;
      
      class StoreTest {
      
      	@Test
      	public void testPay(){
      		//Payment cashPerf = new Cash(); //(1)
      		Payment cashPerf = new CashPerf(); **//(2)**
      		Store store = new Store(cashPerf);
      		store.buySomething(100);
      	}
      }
    • (1)

    • (2) - 프록시 클래스를 사용하도록 함.

  • 원래는 Cash가 Bean으로 등록이 되어야 하는데 내가 만들고 싶은 CashPerf(proxy)가 자동으로 생겨서 Cash 대신에 등록이 되고 Client가 CashPerf를 대신 쓰게 되는 일이 Spring 내부에서 발생한다.

  • 스프링 AOP 기반의 @Transactional이 위와 같은 일을 한다.

스프링 @AOP 실습

  • @LogExecutionTime 설정(어디에 적용할지)

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface LogExecutionTime {
    
    }
    //위치 : java\org..\owner\LogExecutionTime
    • @Target: 어디에 쓸 수 있는지.
    • @Retension : @정보를 언제까지 유지할 것인가.
  • java\org..\owner\LogAspect : 스프링 AOP(프록시 패턴 기반)

    Proxy 패턴(스프링 AOP)

    @Component
    @Aspect
    public class LogAspect {
    
    	Logger logger = LoggerFactory.getLogger(LogAspect.class);
    
    	**@Around("@annotation(LogExecutionTime)")**
    	public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
    		StopWatch stopWatch = new StopWatch();
    		stopWatch.start();
    		
    		Object proceed = joinPoint.proceed();
    		
    		stopWatch.stop();
    		logger.info(stopWatch.prettyPrint());
    		
    		return proceed;
    
    	}
    }
    • joinPoint 파라미터 = @LogExecutionTime이 붙은 메소드(타겟)
    • @Around("@annotaion(LogExecutionTime)") : LogExecutionTime이라는 @ 주변에 적용하겠다.
      • @Around 외에도 @After, @Before등.
      • @annotation외에도 @Bean, Method들이 진행되는 시점 등.
  • java\org..\owner\OwnerController에서 성능(시간)을 측정할 메소드 위에 @LogExecutionTime을 추가하자.

    Target(타겟)

    @GetMapping("/owners/new")
    	@LogExecutionTime
    	public String initCreationForm(Map<String, Object> model) {
    		Owner owner = new Owner();
    		model.put("owner", owner);
    		return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
    	}
    
    	@PostMapping("/owners/new")
    	@LogExecutionTime
    	public String processCreationForm(@Valid Owner owner, BindingResult result) {
    		if (result.hasErrors()) {
    			return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
    		}
    		else {
    			this.owners.save(owner);
    			return "redirect:/owners/" + owner.getId();
    		}
    	}
    
    	@GetMapping("/owners/find")
    	@LogExecutionTime
    	public String initFindForm(Map<String, Object> model) {
    		model.put("owner", new Owner());
    		return "owners/findOwners";
    	}
    • 앱을 실행하고 @LogExecutionTime이 명시된 메소드들이 실행될 때 각 메소드들이 실행되는 시간, 즉 성능을 Runtime으로 표시한다.

좋은 웹페이지 즐겨찾기