[Spring] AOP2

Posted by 신희준 on October 11, 2017


2017 - 10 - 11 (수)

  • AOP

  • 기본사항 정리


    1 .. AOP


    web application 상의 AOP 실습



    AOP(Aspect Oriented Programming)은 관점지향 프로그래밍이라고도 하며 이를 사용함으로써 공통적인 부분과 핵심적인 부분을 분리하여 유지보수성을 높이고 코드중복을 최소화한다.

    dispatcher-servlet.xml 에 다음코드를 추가한다.

    <aop:config>
    		<aop:aspect ref="profiler">
    			<aop:pointcut id="publicMethod" expression="execution(public * com.study.controller..*(..))" />
    			<aop:around pointcut-ref="publicMethod" method="trace" />
    		</aop:aspect>
    	</aop:config>
    


    ▶ aspect : aspect는 공통적인 부분을 가지는 bean 객체형태이다.

    ▶ pointcut : aspect bean객체 내에있는 공통적인 메소드를 언제 실행할 것인가에 대한 조건이다.

    ▶ aop:around : 모든 시점에 적용가능

    ▶ execution 명시자

    <!--execution 기본형식-->
    execution(수식어패턴 ? 리턴타입 패턴 패키지패턴 ? 이름 패턴 (파라미터 패턴))
    <!--이름패턴은 클래스이름의 패턴이라고 생각하면 된다-->
    


    <aop:pointcut id="publicMethod" expression="execution(public * com.study.controller..*(..))" />
    <!--수식어 패턴은 생략가능// *은 모든값을 의미함 //..은 0개 이상이라는 의미 -->
    


    즉, 위에 execution은 수식어 패턴은 public으로 반환타입은 무엇이든지 가능하며 com.study.controller패키지 및 하위 패키지에 있는 메서드를 호출하라는 말이다.
    (..)는 매개변수 즉, 파라미터가 0개 이상인 메서드를 말한다.


    AOP 테스트를 예제 : 실행시간 출력하는 프로그램

    public class ControllerWrapper{
    	public Object trace(ProceedingJointPoint joinPoint) throws Throwable{
    		String signatureString = jointPoint.getSignature().toString();
    		System.out.println(signatureString +"시작");
    		long start = System.currentTimeMillis();
    		try{
    			Object result = joinPoint.proceed();
    			return result;
    		}finally{
    			long finish = System.currentTimeMillis();
    			System.out.println(signatureString +"종료");
    			System.out.println(signatureString +"실행 시간 :" +(finish-start)+"ms");
    		}
    	}
    }
    

    dispatcher-servlet에 ControllerWrapper클래스로 오는 요청을 매핑하기위한 bean을 생성한다.

    <bean id="profiler" class="com.study.common.aop.ControllerWrapper" />
    



    aop:aspect 는 profiler를 참조한다.
    즉, com.study.controller패키지 및 하위 패키지로오는 모든 요청은 profiler id를 가진 ControllerWrapper클래스에 trace(ProceedingJointPoint joinPoint)메소드를 실행한다.
    aop:around 의 경우에 ProceedingJointPoint 타입의 파라미터를 필수적으로 첫번째 파라미터로 선언해야한다. (규칙)
    getSignature() 는 메서드의 설명을 반환한다.


    애너테이션을 사용해서 AOP 구현하기


    위의 방법 외에 ComponentScan 애너테이션을 사용하면 xml에 더이상 bean을 추가할 필요가 없어서 xml이 더 가볍게 사용할 수 있다.



    dispatcher-servlet.xml에서 aop태그 및 bean태그를 모두 제거한다. component-scan을 위해 다음 코드를 xml에 추가한다. 결국 xml설정을 계속 해주지 않아도 애너테이션으로 쉽게 코딩이 가능하다.


    	<context:component-scan base-package="com.study"/>
    <!--com.study에 있는 모든 bean에 적용-->
    	<aop:aspectj-autoproxy/>
    <!--위 태그를 사용하면 @Aspect 애너테이션이 적용된 빈을 Aspect로 사용할 수 있게 된다.-->
    


    component-scan은 xml에 bean을 등록하지 않아도 각 bean클래스에 @Component를 통해 자동으로 bean을 등록해준다.


    @Aspect // ControllerWrapper bean을 Aspect로 사용한다.
    @Component // Component-scan을 통해 bean을 자동 등록한다.
    public class ControllerWrapper {
    //Pointcut 은  Aspect로 지정된 bean 내부의 공통 메서드가 언제 실행될지 joinPoint를 지정해주기 위해 사용된다. profileTarget() 메서드는 Pointcut annotation을 위해 만든 껍데기만 있는 메서드이다.
    	@Pointcut("execution(public * com.study.controller..*(..))")
    	public void profileTarget() {}
    
    	@Around("profileTarget()&&args(model,req,res)")
    //Around 애너테이션은 메서드 수행 전후에 수행된다.
    	public Object trace(ProceedingJoinPoint joinPoint, Model model, HttpServletRequest req, HttpServletResponse res) throws Throwable {
    			Object result = joinPoint.proceed();
    //jointPoint.proceed()를 통해 포인트컷을 실행한다.
    			return result;
    			//return "";  //AOP의 흐름을 이해하기 까지는 ""을 반환해도 상관없음.
    	}
    }
    


    1 . 전체적인 정리를 해보면 만약 index.jsp에서 서버로 어떠한 요청이 들어왔을 때

    2 . 요청은 component-scan을 통해 @Component 애너테이션을 가진 bean을 자동으로 xml에 등록해줄 것이다.

    3 . 해당 bean에는 execution을 통해 com.study.controller패키지 또는 하위 패키지의 모든 클래스, 메소드들을 호출한다.

    4 . 즉 ControllerWrapper를 통해 다른 컨트롤러의 메소드들이 매핑되고 trace method안에서 proceed()를 통해 포인트 컷이 실행되면 결합하한다.

    5 . 들어오는 요청을 매핑하여 요청에 맞는 메서드를 실행해준다.