AOP using Spring Boot
I am using this Spring AOP code in my Spring Boot STS starter project. After debugging this for a while, I don't see any problem with the AspectJ syntax. Maven dependencies are generated by STS for the starter AOP project. Is there a glaring omission in this code as an annotation? Another issue could be related to the AOP starter project or the way I am trying to test the code in the method @PostConstruct
.
I installed AJDT, but it looks like STS should show AspectJ markers in the IDE on its own. Right? I don't see 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"));
}
}
source to share
There are 3 obvious things wrong and 1 not so obviously wrong.
- Your aspect is wrong and breaks the correct execution of the method. When using the surrounding aspect, you must always return
Object
and useProceedingJoinPoint
and callproceed()
. - You create new instances of the classes yourself, Spring, by default, uses the AOP proxy and will only proxy the beans it knows.
- In the method,
@PostConstruct
it is possible that proxies have not yet been created and that nothing is intercepted - You need to use class based proxy classes to include to add
spring.aop.proxy-target-class=true
to yourapplication.properties
. By default, JDK Dynamic Proxies are interface-based.
Fix aspect
In your current aspect it is not used ProceedingJoinPoint
and therefore the actual method is never called. Next to that, if you now have a method that returns a value, it will suddenly return null
. Since you are not calling proceed
on 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 class proxies
In application.properties
in src\main\resources
add the following property with valuetrue
spring.aop.proxy-target-class=true
source to share