Matthias Braun
Matthias Braun

Reputation: 34413

Spring @AspectJ: Advice not applied

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):

Project setup

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:

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

Answers (1)

Reimeus
Reimeus

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

Related Questions