Reputation: 34413
I'm trying to weave in code before the call of start();
This is the TestClass I want to advice:
package com.test;
public class TestClass {
public static void main(String[] args) {
new TestClass().start();
}
private void start() {
System.out.println("Test started");
}
}
This is the aspect including the advice:
package com.test;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LogAspect {
@Before("call(void com.test.TestClass.start())")
public void logBefore(JoinPoint joinPoint) {
System.out.println("logBefore() is running");
}
}
This is my spring.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">
<aop:aspectj-autoproxy/>
<context:annotation-config/>
<context:component-scan base-package="com.test"/>
I have also tried to name the beans explicitly in the XML like this:
<aop:aspectj-autoproxy/>
<bean id="test" class="com.test.TestClass" />
<bean id="aspect" class="com.test.LogAspect" />
This is my project setup (I'm using the Spring Tool Suite version 3.1.0):
The result is that TestClass.start is called just fine, but the advice is not applied.
What do I have to change so the advice is applied?
Thanks.
Edit: I finally got it to work:
After editing my code according to your suggestions I had a look at this tutorial. This led me to let my TestClass implement an interface. And that fixed the problem.
Here is my final setup:
The TestClass including its interface:
package com.test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
interface TestClass {
void start();
}
public class TestClassImpl implements TestClass {
public static void main(String[] args) {
ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(
"Spring-Config.xml");
TestClass t1 = (TestClass) appContext.getBean("myTest");
t1.start();
}
@Override
public void start() {
System.out.println("test");
}
}
The aspect:
package com.test;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class LogAspect {
@Before("execution(void com.test.TestClass.start(..))")
public void logBefore(JoinPoint joinPoint) {
System.out.println("logging before "
+ joinPoint.getSignature().getName());
}
}
And the Spring-Config.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">
<aop:aspectj-autoproxy/>
<bean id="myTest" class="com.test.TestClassImpl" />
<bean id="logAspect" class="com.test.LogAspect" />
</beans>
Thanks for your help.
Upvotes: 3
Views: 4499
Reputation: 159864
A call
AspectJ pointcut applys when the method is called from another class. As you're calling this directly yourself you should use an execution pointcut, so change:
@Before("call(void com.test.TestClass.start())")
to
@Before("execution(void com.test.TestClass.start())")
Also let the Spring
create the bean instead of creating one directly yourself.
Aside: Note, you can keep your Spring
XML files separate from your source files in src/resources
and they will be picked up by ClassPathXmlApplicationContext
.
Upvotes: 2