Full AspectJ support in Spring - java

I'd like to weave an advice on a method that is NOT part of a Spring bean (Spring Boot 1.4.4.RELEASE) :
#Component
#Aspect
...
#Around("execution(public * com.netflix.appinfo.InstanceInfo.getId())")
I added aspectjrt and spring-instrument (??) dependencies
I added #EnableAspectJAutoProxy and #EnableLoadTimeWeaving(aspectjWeaving = AspectJWeaving.ENABLED) annotations
I added VM arguments:
-javaagent:d:\.m2\repository\org\springframework\spring-instrument\4.3.6.RELEASE\spring-instrument-4.3.6.RELEASE.jar
-javaagent:d:\.m2\repository\org\aspectj\aspectjweaver\1.8.9\aspectjweaver-1.8.9.jar
The bean is handled (postconstruct log) but the execution isn't intercepted.
Does anyone has a clue on something I could miss ? Thx in advance

Ok, here is the trick for those interested, a singleton pattern is handling access to a singleton for both LTW and Spring, so it can be injected with Spring dependencies after being weaved by LTW:
#Configuration
#Aspect
public class MyAspect {
#Value("${mycompany.property}")
private String myKey;
#Around("execution(public * com.mycompany.NotASpringean.getProperty())")
public String weave(ProceedingJoinPoint jp) throws Throwable {
String value = (String) jp.proceed();
// transform the value thx to injected myKey value
return value;
}
#Bean("post-construct-aspect")
public MyAspect init() {
return MyAspect.aspectOf(); // get existing instance via factory method
}
private static MyAspect instance = new MyAspect();
/** Singleton pattern used by LTW then Spring */
public static MyAspect aspectOf() {
return instance;
}
}

Try using the #Pointcut annotation too like this:
#Pointcut("execution(public * com.netflix.appinfo.InstanceInfo.getId())")
public void pointcut() {}
#Around("pointcut()")
public Object whatever(ProceedingJoinPoint joinPoint) throws {...}

Related

Log controller with AspectJ

I have a Spring boot application, and I want to log some info what happens when a Controller method id invoked.
For some reason, my Aspect is not working.
Here is my #Component class annotated with #Aspect:
#Pointcut("within(#org.springframework.stereotype.Controller *)")
public void controller() {
}
#Pointcut("execution(* *.*(..))")
protected void allMethod() {
}
#Before("controller()&& allMethod()")
public void logBefore(JoinPoint joinPoint) {
}
The logBefore method is not called, when any Controller method is called with REST.
Important: As you've stated you are using a Spring Boot setup, my assumption is that you've implemented the Spring AOP module instead of the "actual" AspectJ library. The difference is significant, as the implementation of AOP differs between them. Spring uses the AspectJ annotations to apply proxying, while AspectJ "weaves" the code into your application. In short, Spring AOP might be easier to implement, while AspectJ offers more fine-grained functionality (such as compile-time weaving). A comparison can be found here.
I have tried out the configuration from the code snippet you provided in your post. The advice was invoked after I added several annotations:
#SpringBootApplication
// Be sure to add EnableAspectJAutoProxy and set proxyTargetClass to true
#EnableAspectJAutoProxy(proxyTargetClass = true)
public class DemoApplication {
...
}
// Be sure to add #Aspect and #Component
#Component
#Aspect
public class DemoAop {
private static Logger logger = LoggerFactory.getLogger(DemoAop.class);
#Pointcut("within(#org.springframework.stereotype.Controller *)")
public void controller() {
}
#Pointcut("execution(* *.*(..))")
protected void allMethod() {
}
#Before("controller()&& allMethod()")
public void logBefore(JoinPoint joinPoint) {
logger.info("TEST");
}
}
At runtime your controller is annotated with #RestController but not #Controller.
Simply changing the Pointcut to RestController works:
#Pointcut("within(#org.springframework.web.bind.annotation.RestController *)")
public void controller() {
}

AOP Spring #AfterReturning not calling the aspects method properly

I have an annotation.
#Target(value = {ElementType.METHOD, ElementType.TYPE})
#Retention(value = RetentionPolicy.RUNTIME)
#Inherited
#Documented
public #interface MyCustomAnnotation{
}
My Aspect class is like that
#Component
#Aspect
public class MyCustomAsspect{
#AfterReturning(
pointcut="#annotation(MyCustomAnnotation)",
returning="retVal")
public void publishMessage(JoinPoint jp, Object retVal) throws Throwable {
}
}
My Service class is
#Service
public class ServiceClass{
#MyCustomAnnotation
public Object someMethod(){
return new Object();
}
}
Above are mentioned classes i am not sure why my aspect not working. I am new to Spring AOP . Please help me it shall be very thankful.
Issue is due to pointcut declaration. As spring documentation says
#annotation - limits matching to join points where the subject of the
join point (method being executed in Spring AOP) has the given
annotation
So I order to make this work
#Aspect
public class MyCustomAsspect{
#AfterReturning(
pointcut="execution(public * *(..)) and #annotation(MyCustomAnnotation)",
returning="retVal")
public void publishMessage(JoinPoint jp, Object retVal) throws Throwable {
}
}

Spring AOP: Advice not executing for method with custom annotation

I have created a custom annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface ValidateBeforeBuild {
}
And an aspect as:
#Aspect
#Component
public class AspectForBuildInBuilders {
private static final Logger LOGGER = LoggerFactory.getLogger(AspectForBuildInBuilders.class);
#Before("#annotation(validateBeforeBuild )")
public void validateBusinessModelAdvice(JoinPoint jp, ValidateBeforeBuild validateBeforeBuild ) throws Throwable {
LOGGER.info("Executing class: {}", jp);
}
}
I have a build() that is marked with above annotation. When I am trying to call the build(), I am not getting the log message from the validateBusinessModelAdvice(). I also have #EnableAspectJAutoProxy in one of the configuration classes. Am I missing something? Is there any more information required?
You defined your annotation as ValidateBeforeBuild and in your aspect you specified validateBeforeBuild (notice the upper V in your annotation)
Try changing
#Before("#annotation(validateBeforeBuild)")
for
#Before("#annotation(ValidateBeforeBuild)")

Injected bean becomes null after using AOP

I am using Spring4 along with Spring Boot.
Before I tired to use AOP, my Bean(CommandService),which is used in the controller, is auto injected well, but after I tired to use AOP to collect some debug message, the bean becomes null!
Here is my Application.java
#Configuration
#EnableAutoConfiguration
#ComponentScan({"hello","wodinow.weixin.jaskey"})
public class Application extends {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
LogUtil.info("Beans provided by Spring Boot:");
String[] beanNames = ctx.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String beanName : beanNames) {
LogUtil.info(beanName);
}
LogUtil.info("Application Boots completes!");
}
#Bean
public CommandService commandService(){
LogUtil.debug("CommandService.getInstance()"+ CommandService.getInstance()) ;//here indeed I could see spring executes this and returns a object when application boots
return CommandService.getInstance();//This returns a singleton instance
}
}
My controller that throws null pointer:
#Controller
public class CoreController {
#Autowired
CommandService commandService;//here the service is null after using aop
//...some request methods
}
The Aspect which I added just now:
//if I comment out these two annoations, the bean will be auto injected well
#Aspect
#Component
public class LogAspect {
#Pointcut("execution(* wodinow.weixin.jaskey..*.*(..))")
private void debug_log(){};
#Around("debug_log()")
public void debug(ProceedingJoinPoint joinPoint) throws Throwable{
LogUtil.debug("enter "+joinPoint.getSignature());
try{
joinPoint.proceed();
LogUtil.debug("returns from "+joinPoint.getSignature());
}
catch(Throwable t){
LogUtil.error(t.getMessage()+"occurs in "+joinPoint.getSignature(),t);
throw t;
}
}
}
I am new to Spring, can anybody help me with this?
Your #ComponentScan is trying to resolve and autowire your dependencies into CoreController. When it tries to resolve the dependency it finds the #Bean in your Application class. It then tries to resolve this dependency by calling Application.commandService(). When this method is called, it sees the matching #Pointcut and invokes your advice method. Since your #Advice is not returning anything, the callers will also see that nothing was returned, and it will say that that resolution of that dependency returned null.
The fix here is just to change your #Around advice to return the value of your invocation.
#Around("debug_log()")
public Object debug(ProceedingJoinPoint joinPoint) throws Throwable{
LogUtil.debug("enter "+joinPoint.getSignature());
try{
// return the invocation
return joinPoint.proceed();
}
catch(Throwable t){
LogUtil.debug(t.getMessage()+"occurs in "+joinPoint.getSignature(),t);
throw t;
}
}
You are used
joinPoint.proceed();
without return just add return to be
return joinPoint.proceed();

Pointcut for methods with #Scheduled Spring annotation

I want to have a AspectJ pointcut for methods annotated with #Scheduled. Tried different approaches but nothing worked.
1.)
#Pointcut("execution(#org.springframework.scheduling.annotation.Scheduled * * (..))")
public void scheduledJobs() {}
#Around("scheduledJobs()")
public Object profileScheduledJobs(ProceedingJoinPoint joinPoint) throws Throwable {
LOG.info("testing")
}
2.)
#Pointcut("within(#org.springframework.scheduling.annotation.Scheduled *)")
public void scheduledJobs() {}
#Pointcut("execution(public * *(..))")
public void publicMethod() {}
#Around("scheduledJobs() && publicMethod()")
public Object profileScheduledJobs(ProceedingJoinPoint joinPoint) throws Throwable {
LOG.info("testing")
}
Can anyone suggest any other way to have around/before advice on #Scheduled annotated methods?
The pointcut that you are looking for can be specified as below:
#Aspect
public class SomeClass {
#Around("#annotation(org.springframework.scheduling.annotation.Scheduled)")
public void doIt(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("before");
pjp.proceed();
System.out.println("After");
}
}
I am not sure whether that's all you require or not. So I'm going to post the other parts of the solution as well.
First of all, notice the #Aspect annotation on the class. It is required for the methods in this class to be applied as advice.
Also, you need to make sure that the class that has the #Scheduled method is detectable via scanning. You can do so by annotation that class with #Component annotation. For ex:
#Component
public class OtherClass {
#Scheduled(fixedDelay = 5000)
public void doSomething() {
System.out.println("Scheduled Execution");
}
}
Now, for this to work, the required parts in your spring configuration would be as follows:
<context:component-scan base-package="com.example.mvc" />
<aop:aspectj-autoproxy /> <!-- For #Aspect to work -->
<task:annotation-driven /> <!-- For #Scheduled to work -->

Categories

Resources