Pointcut for methods with #Scheduled Spring annotation - java

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

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 {
}
}

The #AfterThrowing advice is not executed [duplicate]

I am new to Spring and AOP. I am trying this simple thing where I have created a custom annotation which when placed before any method should execute some code.
This is the annotation I created
// Declares a custom annotation that validates json
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface JsonSchemaAnnotation {
}
Next I created the Spring Aspect class which holds the logic
#Aspect
public class UpdateUIMetadataInterceptor {
#Pointcut("execution(public * com.fico.cardinal.cm.*.*(..))")
public void anyPublicMethod() {
System.out.println("Running");
}
#Before("anyPublicMethod() && #annotation(jsonSchemaAnnotation)")
public void validateJson(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("Running");
}
}
And this is my simple test class
public class ValidationTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring/configuration.xml");
String jsondata = "{\"id\": \"EXPENSE_REPORT\",\"properties\": {\"transactionType\": \"EXPENSE_REPORT\"},\"sections\": []} ]}";
ValidationTest test = new ValidationTest();
test.jsonValidationTest("dummy", jsondata);
((AbstractApplicationContext) context).close();
}
#JsonSchemaAnnotation
public void jsonValidationTest(String dummy, String jsondata) {
System.out.println("Success");
}
The problem is my spring aop never gets triggered. I have included a bean in my configuration.xml
<aop:aspectj-autoproxy>
<aop:include name="UpdateUIMetadataInterceptor" />
</aop:aspectj-autoproxy>
<bean id="updateUI" class="com.fico.cardinal.cm.interceptor.UpdateUIMetadataInterceptor" />
Can anyone point out what I am missing?
You have several problems with your code:
You should create your ValidationTest object as a bean managed by Spring and not using new
<aop:include name="UpdateUIMetadataInterceptor" /> should be <aop:include name="updateUI"/>; you can actually just stick with <aop:aspectj-autoproxy/> for simplicity here
ProceedingJoinPoint is not supported for before aspects, so remove it; you can use JoinPoint instead if you need access to arguments
JsonSchemaAnnotation jsonSchemaAnnotation parameter should be present for validateJson method of your aspect, as pointed out by frant.hartm
I think you need either fully qualified name or a parameter in the method:
FQN:
#Before("anyPublicMethod() && #annotation(your.package.JsonSchemaAnnotation)")
public void validateJson(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("Running");
}
Parameter:
#Before("anyPublicMethod() && #annotation(jsonSchemaAnnotation)")
public void validateJson(ProceedingJoinPoint pjp, JsonSchemaAnnotation jsonSchemaAnnotation ) throws Throwable {
System.out.println("Running");
}
Source: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html#aop-pointcuts
(and you also need to use the bean, as Dmitry Kuskov pointed out

Pointcut for getting all beans in #Configuration class

I use Spring Integration and have a flow described in some #Configuration annotated class (#Bean and #Autowired marked methods), f.e. CustomFlow.class.
If any element in flow throw exception I would like to intercept it with #AfterThrowing advice and do some actions (notification, write smth to DB, etc).
So the question is - how to write proper pointcut to get all beans in this case?
#Aspect
public class LoggingAspect {
#AfterThrowing(
pointcut = "execution(*(..))",
throwing= "error")
public void logAfterThrowing(JoinPoint joinPoint, Throwable error) {
//...
}
}
and then the configuration:
<aop:after-throwing method="logAfterThrowing" throwing="error" />

Targeting aspects based annotation on a class with Spring and AspectJ

How to make an aspect that targets all public methods that belong to a class that is marked with specific annotation? In following method1() and method2() should be processed by the aspect and method3() should not be processed by the aspect.
#SomeAnnotation(SomeParam.class)
public class FooServiceImpl extends FooService {
public void method1() { ... }
public void method2() { ... }
}
public class BarServiceImpl extends BarService {
public void method3() { ... }
}
If I put annotations on method level, this aspect will work and match the method calls.
#Around("#annotation(someAnnotation)")
public Object invokeService(ProceedingJoinPoint pjp, SomeAnnotation someAnnotation)
throws Throwable {
// need to have access to someAnnotation's parameters.
someAnnotation.value();
}
I am using Spring and proxy based aspects.
The following should work
#Pointcut("#target(someAnnotation)")
public void targetsSomeAnnotation(#SuppressWarnings("unused") SomeAnnotation someAnnotation) {/**/}
#Around("targetsSomeAnnotation(someAnnotation) && execution(* *(..))")
public Object aroundSomeAnnotationMethods(ProceedingJoinPoint joinPoint, SomeAnnotation someAnnotation) throws Throwable {
... your implementation..
}
This works in Spring Boot 2:
#Around("#within(xyz)")
public Object method(ProceedingJoinPoint joinPoint, SomeAnnotation xyz) throws Throwable {
System.out.println(xyz.value());
return joinPoint.proceed();
}
Note that based on the method argument type (SomeAnnotation xyz), Spring and AspectJ will know which annotation you are looking for, so the xyz does not have to be the name of your annotation.
Using #target and reading the type level annotation with reflection works.
#Around("#target(com.example.SomeAnnotation)")
public Object invokeService(ProceedingJoinPoint pjp) throws Throwable {

Categories

Resources