aopaspectjspring-aspects

Spring AOP not picking up AOP annotations


I have one project using AOP - a sample program - which works. I created a project implementing AOP in (as far as I can see...) the same way which doesn't work.

pom.xml

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>6.0.11</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

AppConfig.java

@Configuration
@ComponentScan(basePackages = {
        "com.phil.cardgame.aspects",
        "com.phil.cardgame.service"
})
@EnableAspectJAutoProxy()
public class AppConfig {
}

EventAspect.java

@Aspect
@Component
public class EventAspect {
    @Autowired
    EventRepository eventRepository;

    //@Around("execute(* com.phil.cardgame.service.GameService.createGame())")
    //@Around("execute(* com.phil.cardgame.service.*.*(..))")
    @Around("invalid text")
    public long registerCreateGame(ProceedingJoinPoint joinPoint) throws Throwable{
        String action = joinPoint.getSignature().toString();
        long gameId = (long) joinPoint.proceed();
        eventRepository.addEvent(action,gameId,null);
        System.out.println(">>> got here");
        return gameId;
    }

In the EventAspect.java you can see the commented @Around advices I tried. The last one (invalid) produces no error. If I try the same in the working project I get an error: "Pointcut is not well-formed". So it looks like my EventAspect is not being inspected as an Aspect.

I've checked many other similar questions and I still can't see what I'm doing wrong - any ideas?


Solution

  • I cloned your project. Your aspect works. Despite being unrelated to your problem, just for fun let us

    package com.phil.cardgame.aspects;
    
    import com.phil.cardgame.model.Deck;
    import com.phil.cardgame.repository.EventRepository;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.AfterReturning;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    @Aspect
    @Component
    public class EventAspect {
      @Autowired
      EventRepository eventRepository;
    
      @Pointcut("within(com.phil.cardgame.service.GameService)")
      public void inGameService() {}
    
      @AfterReturning(value = "inGameService() && execution(* createGame())", returning = "gameId")
      public void registerCreateGame(JoinPoint joinPoint, Long gameId) {
        addEvent(joinPoint, gameId, null);
      }
    
      @AfterReturning("inGameService() && execution(* *(..)) && args(gameId, playerId)")
      public void registerPlayerAction(JoinPoint joinPoint, long gameId, String playerId) {
        addEvent(joinPoint, gameId, playerId);
      }
    
      @AfterReturning("inGameService() && execution(* *(..)) && args(gameId, deck)")
      public void registerDeckAction(JoinPoint joinPoint, long gameId, Deck deck) {
        addEvent(joinPoint, gameId, null);
      }
    
      @AfterReturning("inGameService() && execution(* *(..)) && args(gameId)")
      public void registerGameAction(JoinPoint joinPoint, long gameId) {
        addEvent(joinPoint, gameId, null);
      }
    
      private void addEvent(JoinPoint joinPoint, long gameId, String playerId) {
        System.out.println(joinPoint);
        eventRepository.addEvent(joinPoint.getSignature().toString(), gameId, playerId);
      }
    }
    

    Now, change the main program like this:

    package com.phil.cardgame;
    
    import com.phil.cardgame.service.GameService;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.ConfigurableApplicationContext;
    
    @SpringBootApplication
    public class CardgameApplication {
      public static void main(String[] args) {
        try (ConfigurableApplicationContext context = SpringApplication.run(CardgameApplication.class, args)) {
          GameService gameService = context.getBean(GameService.class);
          gameService.createGame();
          gameService.addDeckToGame(1, gameService.createDeck());
          gameService.addPlayerToGame(1, "jane");
          gameService.findGame(1);
        }
      }
    }
    

    The console log will show:

    execution(Long com.phil.cardgame.service.GameService.createGame())
    execution(void com.phil.cardgame.service.GameService.addDeckToGame(long,Deck))
    execution(Player com.phil.cardgame.service.GameService.addPlayerToGame(long,String))
    execution(Game com.phil.cardgame.service.GameService.findGame(long))
    

    To me, it looks like everything is working just fine.


    Update: In Spring Boot, your invalid pointcut syntax for something like @Around(crepe) is silently ignored, but if you wish to see the "Pointcut is not well-formed" log output, you can set

    logging.level.org.springframework.aop=debug
    

    in application.properties. Then, on the console you will see something like (stripped off timestamp):

    DEBUG 20508 --- [cardgame] [           main] o.s.a.aspectj.AspectJExpressionPointcut  : Pointcut parser rejected expression [crepe]: java.lang.IllegalArgumentException: Pointcut is not well-formed: expecting '(' at character position 0
    crepe
    ^