AOP using Spring Boot

16k views Asked by At

I am using this Spring AOP code in my Spring Boot starter project in STS. After debugging this for some time I don't see any problem with the AspectJ syntax. The Maven dependencies are generated by STS for a AOP starter project. Is there a glaring omission in this code like an annotation ? The other problem could be with the AOP starter project or with the way I try to test the code in a @PostConstruct method.

I installed AJDT but it appears STS should show AspectJ markers in the IDE on its own. Right ? I don't see the markers. What other AspectJ debugging options are included in STS ? -Xlint is what I used in Eclipse/AJDT.

StateHandler.java

public class StateHandler<EVENTTYPE extends EventType> {


private State<EVENTTYPE> state;

private Event<EVENTTYPE> event;

public StateHandler(State<EVENTTYPE> state, Event<EVENTTYPE> event) {
    this.state = state;
    this.event = event;
}


public void handle( Event<EVENTTYPE> event ){

    state = state.handle( event );

}

public State<EVENTTYPE> getState() {
    return state;
}

}

DeviceLogger .java

    @Aspect
    @Component
    public class DeviceLogger {

    private static Logger logger = Logger.getLogger("Device");


        @Around("execution(* com.devicemachine.StateHandler.*(..))")
        public void log() {
            logger.info( "Logger" );
        }
}

LoggerApplication.java

@SpringBootApplication
public class LoggerApplication {

    private static Logger logger = Logger.getLogger("Device");


    public static void main(String[] args) {

        SpringApplication.run(LoggerApplication.class, args);

    }

    @PostConstruct
    public void log(){
        DeviceState s = DeviceState.BLOCKED;
        StateHandler<DeviceEvent> sh = new StateHandler<DeviceEvent>( s,
                                            Event.block(DeviceEvent.BLOCKED, "AuditMessage") );
        sh.handle(Event.block(DeviceEvent.UNBLOCKED, "AuditMessage"));
    }
}
1

There are 1 answers

6
M. Deinum On BEST ANSWER

There are 3 obvious things wrong and 1 not so obvious wrong.

  1. Your aspect is wrong and breaks proper method execution. When using an around aspect you must always return Object and use a ProceedingJoinPoint and call proceed() on that.
  2. You are creating new instances of classes yourself, Spring, by default, uses proxy based AOP and will only proxy beans it knows.
  3. In a @PostConstruct method it might be that proxies aren't created yet and that nothing is being intercepted
  4. You need to use class based proxies for that to be enabled add spring.aop.proxy-target-class=true to your application.properties. By default JDK Dynamic Proxies are used which are interface based.

Fix Aspect

Your current aspect doesn't use a ProceedingJoinPoint and as such never does the actual method call. Next to that if you now would have a method that returns a value it would all of a sudden return null. As you aren't calling proceed on the ProceedingJoinPoint.

@Around("execution(* com.devicemachine.StateHandler.*(..))")
public Object log(ProceedingJoinPoint pjp) throws Throwable {
    logger.info( "Logger" );
    return pjp.proceed();
}

Create a bean to fix proxying and @PostConstruct

@SpringBootApplication
public class LoggerApplication {

    private static Logger logger = Logger.getLogger("Device");

    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(LoggerApplication.class, args);
        StateHandler<DeviceEvent> sh = context.getBean(StateHandler<DeviceEvent>.class);
        sh.handle(Event.block(DeviceEvent.UNBLOCKED, "AuditMessage"));
    }

    @Bean
    public StateHandler<DeviceEvent> auditMessageStateHandler() {
        return new StateHandler<DeviceEvent>(DeviceState.BLOCKED, Event.block(DeviceEvent.BLOCKED, "AuditMessage") );
    }

}

Add property to enable class proxies

In your application.properties in src\main\resources add the following property with a value of true

spring.aop.proxy-target-class=true