2011-05-10 1 views
6

나는 스프링 3에서 빌드 된 자바 애플리케이션을 가지고있다.이 프로젝트는 의존성 (dependency)으로서 다른 항아리를 가지고있다.Spring AOP가 런타임에 외부 항아리를 짜 내지 않는 이유는 무엇입니까?

이 종속성은 @org.aspectj.lang.annotation.Aspect 클래스 (예 : com.aspectprovider.aspects.MyAspect)를 포함합니다. 인터페이스 Foo을 구현하는 클래스에서 메소드를 짜기위한 조언은 @Before입니다. Foo 인터페이스는 "프로젝트"내부 또는 다른 항아리에있을 수 있습니다

@Before("execution(* com.project.Foo.save(..))") 

:처럼 뭔가. 이 예제에서는 중요하지 않습니다.

내 프로젝트에는 Foo을 구현하는 클래스가 포함되어 있습니다. 그것들은 내가 물론 길들이기를 원하는 수업들입니다. 나는 또한 빈으로 화면을 선언하고 일부 속성 주입

<aop:aspectj-autoproxy /> 

:

<bean id="myAspect" class="com.aspectprovider.aspects.MyAspect" 
    factory-method="aspectOf" > 
    <property name="someproperty" value="somevalue" /> 
</bean> 

트로프 로깅 내가 볼 수

내 Spring 애플리케이션 컨텍스트 구성 파일 (applicationContext.xml)

선을 포함 MyAspect이 인스턴스화되고 특성이 주입됩니다. 그러나 save 메소드는 인터셉트되지 않습니다. 이게 문제 야.

jar 파일에서 Spring이있는 응용 프로그램으로 aspect 클래스를 복사하면 작동합니다. 이러한 측면이 외부 항아리에 포함되어있을 때 save 메서드는 가로 챌 수 없습니다. 모든 단서?

편집 : 기본적으로 내 applicationContext.xml가 다음 줄

//in a JSF managed bean 
@Inject 
private Foo myFoo; //there's a implementation of Foo in a package that spring is looking at. So it is injected correctly. 

public String someAction() { 
    myFoo.save("something"); //the @Before advice is only called if the class containing the aspect is not in an external jar 
} 


//in a class with a main method 
void main(String[] ars) { 
    ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); 
    //right after the previous line, I can see in the log that MyAspect is instantiated. 
    Foo myFoo = ac.getBean(Foo.class); 
    myFoo.save("something"); //the @Before advice is only called if the class containing the aspect is not in an external jar 
} 

: 나는 푸의 저장 메소드를 호출하고 어떻게

<context:annotation-config /> 
<context:component-scan base-package="com.project" /> 
<context:component-scan base-package="com.aspectprovider.aspects" /> 
<aop:aspectj-autoproxy /> 
<bean id="myAspect" class="com.aspectprovider.aspects.MyAspect" factory-method="aspectOf" > 
    <property name="someproperty" value="somevalue" /> 
</bean> 

을 나는 같은 것을 넣을 필요가 있다고 생각하지 않습니다

<context:component-scan base-package="com.project"> 
    <context:include-filter type="aspectj" expression="com.aspectprovider.aspects.*" /> 
</context:component-scan> 
+0

당신은 J2EE의 environement 아래를 실행하고 있습니까? Weblogic websphere jboss 또는 심지어 바람둥이? –

+0

바람둥이입니다. 하지만 스프링 컨텍스트를 "손으로로드"콘솔을 통해 실행하는 경우 동일한 문제가 있습니다. – bluefoot

+0

어떻게'save' 메소드를 호출할까요? Spring이 코드를 제공한다는 참조를 통해 호출하지 않는다면 pointcut는 호출되지 않을 것입니다 *. 일반적인 실수는 'this'(명시 적 으로든 묵시적이든)를 통해 호출하는 것인데, 이는 wrapped 인스턴스에서 직접 호출되며 bean 자체에서는 직접 호출되지 않습니다. –

답변

0

나는 spring의 applicationContext xml config에서 애스펙트를 선언하고 애노테이션을 제거했다.

지금까지는 maven 용 aspectj 플러그인을 사용했지만 일식에서 클래스를 변경할 때마다 $ mvn compile (이클립스는 애스펙트를 알지 못하고 클래스가없는 클래스를 컴파일했기 때문에)을 실행해야했습니다. 그리고 그것은 누군가에게 MyAspect을 사용할 것이라고 말하는 것은 끔찍한 일입니다.

구성 파일을 만들고 문서화했습니다. MyAspect을 사용하려면이 구성 규칙을 스프링의 컨텍스트 구성으로 가져 오기 만하면됩니다.

+0

나는 당신과 같은 상황에 있습니다. 내 측면은 주석 기반이므로 문제가 될 수 있습니까? 그리고이 상황에서 로딩 타임을 할 필요가 없습니까? –

2

aspectJ LT W 대신 Spring AOP 프록시. 이를 위해이-INF META

<!DOCTYPE aspectj PUBLIC 
     "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd"> 
<aspectj> 
    <weaver> 
     <!-- only weave classes in this package --> 
     <include within="org.springbyexample.aspectjLoadTimeWeaving.*" /> 
    </weaver> 
    <aspects> 
     <!-- use only this aspect for weaving --> 
     <aspect name="org.springbyexample.aspectjLoadTimeWeaving.PerformanceAdvice" /> 
    </aspects> 
</aspectj> 

당신에 aop.xml를 추가 그리고 이것은 설정의 스프링 부분이다 :

자세한 내용은 여기를 참조하십시오 : http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop.html#aop-aj-ltw

+0

고마워,하지만 이미 LTW에 대해 알고 있고, 내가 토론 할 시간이 아니라고 생각하는 몇 가지 이유 때문에 피하려고 노력하고있다. 런타임 직물은 지금까지 완벽하게 작동했습니다. 문제는 내가 다른 항아리로 측면을 분리했을 때 시작되었다. – bluefoot

+0

+1 때문에 결국 XML로 끝났습니다. 내 대답에 더 많은 정보. – bluefoot

0

에서 액션 북에있는 AspectJ : @AspectJ 또는 XML 기반 구문을 사용하여 선언 된 프록시 기반 AOP와 함께 사용되는 aspect는 스프링 빈이며 aspectOf() 접근 방식을 사용해서는 안됩니다인스턴스화에.

는 일반적으로 그것을 선언하고 그것을 밖으로 작동하는지 확인 :

<bean id="myAspect" class="com.project.MyAspect"> 
    <property name="someproperty" value="somevalue" /> 
</bean> 
+0

글쎄, 실제로'factory-method'를 사용하지 않으면'MyAspect'가 두 번 인스턴스화됩니다. 처음으로' '때문이라고 생각합니다.한 가지 또는 다른 것은 MyAspect가 외부 항아리에없는 경우에만 작동합니다. – bluefoot

3

를 클래스가 난 단지 그것이 클래스 로딩 문제가 될 것이라고 생각할 수있는 응용 프로그램과 봄에 포장되어 때 완벽하게 잘 작동 고려.

앱에 번들로 제공되면 AOP가 모니터해야하는 모든 클래스를 스캔 할 때 제대로 작동하면 모든 올바른 항아리가있는 올바른 클래스 로더를 참조하게됩니다. 하지만 이제이를 제거하고 JAR 파일로 설정하면 다른 모든 제 3 자 항아리가있는 클래스 로더에서 스캔됩니다.

나는 그것을 밖으로 매핑하는 방법을 100 % 확실하지 오전하지만이 같은 수 : 그 aspect.jar 스캔은 자사의 클래스 로더에 해당되는 경우

Bootstrap Classloader <- Third Party Classloader <- Application Class Loader (with all your classes) 
           \       \ 
           aspectj.jar    spring.jar 

다음은 '볼 수 없습니다 모든 수업 '. 이를 확인하는 한 가지 방법은 앱의 힙 덤프를 가져 오는 것입니다. Eclipse MAT에 대해 실행하고 클래스 로더 탐색기를 확인한 다음 애스펙트 클래스를 찾으십시오. 응용 프로그램과 동일한 클래스 로더 아래에 있지 않으면 tomcat이 제 3 자 라이브러리에 응용 프로그램 클래스를 알리는 방법을 살펴보아야합니다.

+0

그래서 제 3 자 jar (aspect와 함께 포함)를 프로젝트 클래스와 다른 클래스 로더에로드한다고 말하고 있습니다. 그리고 aspectj는 "main"classloader 만 짜집니까? 그게 다야? – bluefoot

+1

내가 의심하는 바입니다. 써드 파티 라이브러리 세트 내의 메소드 이름을 찾고 AOP 인터셉트 메소드 호출을 통해이를 테스트 할 수있다. 그게 효과가 있다면 당신은 점점 더 가까워지고 있습니다. –

+0

좋은 +1 (+1). 실제로 클래스 로더 문제 일 수 있습니다. 나는 Foo의 구현 중 하나를 MyAspect의 jar로 옮겼다. 그런 다음이 구현의 save() 메소드가 질문에 설명 된 방식으로 호출되었을 때 차단되었다. 자, 이제 우리는 그것에 대해 확신 할 수있는 것이 있습니까? – bluefoot

6

동일한 문제가 있습니다. 나는이 문제를 maven으로 해결했다. aspectj-maven-plugin 및 옵션 weaveDependency

http://mojo.codehaus.org/aspectj-maven-plugin/weaveJars.html

+1

그게 내가하고 있었던거야. ([내 대답] (http://stackoverflow.com/questions/5956490/why-spring-aop-is-not-weaving-external-jars-at-runtime/6238001#6238001)) ,하지만 여전히 수동으로 또는 일부 외부 도구를 사용하여 컴파일해야했습니다. 나는로드 타임을 짜기 위해서 였고, 컴파일 시간에 짜 맞추기 위해서였습니다. – bluefoot

+0

+1 나를 위해 일했습니다. – Ritesh