Spring In Action 1장 ~ 4장 소스 코드

do402.zip
do408.ppt
AJN에서 진행하고 있는 Spring In Action 스터디에서 사용할 소스코드 입니다. 발표 준비하면서 책에 나와있는 코드들을 돌려 본 코드 입니다.

1. @Configure 실패
2. AspectJ와의 연동 실패

두 개 모두 로드타임위빙 인가를 사용해야 하는데, 그 것을 어떻게 해야하는지 해메고 있어서 예제 코드 실습에 실패했습니다. 그 밖에 모든 코드는 책을 보시면서 따라해 보시거나 제가 만들어 둔 Test 코드를 실행하시면 모두 동작하는 것을 확인하실 수 있습니다.

Spring이 제공하는 AutoProxyCreator

classic Spring Aspect를 사용할 때 Target 하나 마다 일일히 ProxyFactoryBean을 만들어 주는 일은 완전 노가다 입니다. 이 노가다를 줄여주기 위해 Spring에서 제공하는 녀석들이 바로 AutoProxyCreator 입니다.

Spring이 제공하고 있는 AutoProxyCreator들을 살펴보겠습니다.
사용자 삽입 이미지위와 같은 상속 구조를 가지고 있습니다.

interceptorNames 속성에 Proxy를 생성할 Target이 되는 bean의 이름들을 설정하여 여러 Proxy를 만들 수 있도록 하는 클래스입니다.
BeanNameAutoProxyCreator 사용 예

@Aspect 애노테이션이 붙어있는 클래스에 정의되어 있는 Adivce가 적용될 Pointcut을 가지고 있는 클래스들의 Proxy를 생성하는 클래스입니다. 이 클래스를 bean으로 등록해둬도 되지만 aop 네임스페이스를 사용하고 있다면 <aop:aspectj-autoproxy />만 추가하면 됩니다.

현재 BeanFactory에 등록되어 있는 Advisor들을 사용하여 그들의 대상이 되는 Target 들을 파악하여 Proxy를 만들어줍니다. 이 녀석 역시 그냥 bean으로 등록해두기만 하면 됩니다.

Auto-proxy creator that considers infrastructure Advisor beans only, ignoring any application-defined Advisors. 라고 써있는데.. 흠 Infra Advisor는 Spring에서 제공하는 인터셉터(DebugInterceptor, PerformanceMonitorInterceptor)를 말하는 것 같습니다. 이 녀석들이 적용될 Target의 Proxy만 만들는 것 같습니다. 흠.. 아마도 디버깅이나 테스트 용도로 사용하겠군요.

Spring 2.5에 추가되는 bean() joinpoint

참조 : http://blog.interface21.com/main/2007/09/24/the-new-bean-pointcut/

Classic Spring AOP를 사용할 때 여러 Target에 대해 각각의 proxyFactoryBean을 정의하는 것은 매우 귀찮은 일이고 XML도 방대해 지기 때문에 AutoProxyCreator를 사용했었습니다.

그 중에서도 BeanNameAutoProxyCreator는 XML에 등록되어 있는 bean 이름을 설정해 주면 해당 bean의 Proxy를 만들어 주는 편리한 API였지만, 단점은 aop 네임스페이스 기반 이나 @AspectJ 애노테이션 기반과 같이 사용할 수 없다는 것이였습니다.

Spring 2.5에서는 bean() 이라는 joinpoint 표현식을 제공하여 다음과 같이 다수의 target bean을 편리하게 지칭할 수 있게 됩니다.
사용자 삽입 이미지

Pointcut Join points selected in
bean(accountRepository) The bean named “accountRepository”
!bean(accountRepository) Any bean except the “accountRepository” bean
bean(*) Any bean
bean(account*) Any bean with name starting in “account”
bean(*Repository) Any bean with name ending in “Repository”
bean(accounting/showaccount) The bean named accounting/showaccount (designating, say, a controller handling that URL)
bean(accounting/*) Any bean whose name starts with “accounting/” (designating, say, any controller handling accounting-related URLs)
bean(accounting/*/edit) Any bean whose name starts with “accounting/” and ends with “/edit”
(designating, say, any controller handling the edit operation
functionality related to accounting)
bean(*dataSource) || bean(*DataSource) Any bean whose name ends with either “dataSource” or “DataSource”
bean(service:name=monitoring) The bean named “service:name=monitoring”

왜 Spring MVC 컨트롤러에 AOP가 적용되지 않을까?

왜그럴까요? 저도 궁금해서 관련 아티클도 읽고 소스코드도 좀 해봤는데요; 아직도 조금 긴가민가 합니다.

AOP / AJAX Enabled Controllers in Spring MVC

위 글을 참조하였습니다.

Controller
인터페이스를 직접 구현하여 컨트롤러를 만들면 handleRequest() 메소드에 AOP를 적용할 수 있습니다. 하지만 자주
사용하는 MultiActionController, SimpleFormController에는 AOP가 적용되지 않습니다.

왜냐면, AbstractController에서 Controller 인터페이스를 구현하고, handleRequest 메소드를 final 메소드로 구현했습니다. 그래서 AOP가 적용되지 않는다고 합니다.


냐면, MultiActionController, SimpleFormController 들의 프록시 객체를 만들 때, 인터페이스
기반으로 Proxy를 만들지 않고 CGlib 라이브러리를 사용해서 하위클래스를 생성하여 Proxy를 만들려고 하는데 final
메소드를 가지고 있기 때문에 그것마저도 못하기 때문인듯 합니다.

사용자 삽입 이미지위와 같은 상속구조에서 SampleController의 handleRequest() 메소드에 BeforeAdvice를 적용하는 Aspect를 다음과 같이 정의했습니다.

@Aspect
public class SampleAspect {

    @Pointcut(“execution(* finalClassProxying.SampleController.handleRequest())”)
    public void samplePointcut(){}

    @Before(“samplePointcut()”)
    public void sampleAdvice(){
        System.out.println(“과연 될까?”);
    }

}

테스트를 해보면 적용이 되지 않는 것을 확인할 수 있습니다.

public class FinalClassProxingTest {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext(“finalClassProxying/applicationContext.xml”);
        SampleController controller = (SampleController) context.getBean(“sampleController”);
        controller.handleRequest();
    }
}

흠냐… 로그 메시지에서 final 메소드라서 Proxy객체를 만들 수 없다는 메시지가 보고 싶었는데 보지를 못했습니다… 그래서 위에 제가 생각한 것이 맞는 건인지 아리까리 합니다.

AOP 관련 질문 :: Before Advice의 객체를 Target 클래스로 넘겨주고 싶다.

메일을 받았습니다.

XML을 사용하는 초간단 예제에 대한 질문인데요.
만약에 before메서드에서 생성한 객체를 target클래스에 넘겨야할땐 어떻게 해야되는지요.
방법이 있나요?”


답변은 다음과 같이 해드렸습니다.

before메서드에서 생성한 객체를 target클래스에 넘겨야할땐”가 구체적으로 어떤 경우인지를 설명해주시면 더 좋겠습니다.


단은 Before Advice에서 target이 되는 클래스의 대상 메소드로 값을 넘기려면, Target이 되는 클래스에서
Before Advice를 가지고 있는 Aspect를 알아야 합니다. 그 말은 Aspect에 종속성이 생기게 된다는 것입니다.

제 생각에는 그런 경우가 발생한다면, Before Adivce보다는 Around Adivce를 사용하는 것을
추천하고 싶습니다. Around Advice를 사용하시면 대상이 되는 메소드에 넘겨줄 인자 들이나, 메소드의 반환 값등을
마음대로 바꿀 수 있으며, 심지어 대상이 되는 메소드를 실행하지 않을 수도 있습니다.

제 답변이 도움이 되셨으면 좋겠습니다.”