I have two projects. One is a Spring Boot service, and the other is a library which is making use of Spring AOP. I have created a custom annotation to be executed whenever a method is annotated with this custom annotation. As I want this annotation to be used in lots of services, it lives inside the library. My code looks something like this:
Service:
#MyCustomAnnotation
public void doSomething() {
log.info("Do something is invoked!");
}
#EnableAspectJAutoProxy
public class ApplicationConfig {
...
}
Library:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface MyCustomAnnotation {
...
}
#Aspect
public class ContinueTraceFromSpringKafkaEventAspect {
#Pointcut("#annotation(MyCustomAnnotation)")
public void executeMyCustomAnnotation() { }
#Before("executeMyCustomAnnotation()")
public void beforeAnnotation(JoinPoint joinPoint) {
log.info("Before annotation");
}
#After("executeMyCustomAnnotation()")
public void afterAnnotation(JoinPoint joinPoint) throws Throwable {
log.info("After annotation");
}
}
The annotation would successfully execute when the code lived inside the service but, ever since extracting it to a library (and having the library on the classpath of the service via Maven dependency), it doesn't execute - I suspect the pointcut expression needs amending.
Any ideas?
Related
I am trying to intercept JMS MessageListener onMessage() method using Spring AOP, but my advice is not getting called. I have created an annotation #LoggingInfo:
#Target (ElementType.METHOD)
#Retention (RetentionPolicy.RUNTIME)
public #interface LoggingInfo {
}
Aspect class : I have also tried with the commented ponitcut definition but still advice is not getting called.
#Aspect
#Component
public class LoggingAspect {
#Pointcut("#annotation(LoggingInfo)")
private void annotationPointCut() {
}
//#Pointcut ("execution(* *(..))”)
//#Pointcut ("execution( void *.onMessage (javax.jms.Message))")
#Pointcut("execution( void javax.jms.MessageListener.onMessage(javax.jms.Message))")
private void onMessagePointCut() {
}
#AfterReturning("onMessagePointCut() && annotationPointCut()")
public void loggingAdvice(JoinPoint jp ) {
System.out.println("logging advice method called successfully");
}
}
MessageReceiver.java
#Component
public class MessageReceiver implements MessageListener {
#Override
#LoggingInfo
public void onMessage(Message message) {
System.out.println("Jms message processed successfully");
}
}
All other configuration to setup the application are done properly and onMessage() is processing the incoming message successfully. Also #ComponentScan annotations is mention in application class to scan all the beans.
Is there anything can be done to achieve this using Spring AOP?
I would like to wrap all the repository calls in my service with an Around aspect for creating some metrics.
All of my JpaRepositories are annotated with org.springframework.stereotype.Repository, so I tried something like this:
#Configuration
#Aspect
public class RepositoryMetrics {
#Around("#annotation(org.springframework.stereotype.Repository)")
public void logQueryTime(ProceedingJoinPoint joinPoint) throws Throwable {
//Some logic here
joinPoint.proceed();
//Some logic here
}
}
But seems like the aspect method never runs. What do I miss?
Assuming you have the JpaRepository classes annotated as follows
#Repository
public interface JpaEmployeeRepository extends CrudRepository<JpaEmployee, Long> {
...
}
Following Aspect would intercept all method calls happening to that class
#Component
#Aspect
public class RepositoryAspect {
#Pointcut("#within(org.springframework.stereotype.Repository)")
public void repositoryAnnotationPointCut() {}
#Around("repositoryAnnotationPointCut()")
public void logQueryTime(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("logged for "+pjp.toLongString());
pjp.proceed();
}
}
Please note that a Configuration class be better left for configuration entries and you may create a separate class for Aspect and annotate the same with #Component as given in the example.
Make sure you have #ComponentScan to auto detect the Aspect and #EnableAspectJAutoProxy on the Configuration class. Something as follows
#Configuration
#EnableAspectJAutoProxy
#ComponentScan(basePackageClasses= {RepositoryAspect.class})
public class AppConfig {
...
}
Update
Following are the reasons , your code didn't work as expected
1.
Pointcut designator #annotation
#annotation: Limits matching to join points where the subject of the
join point (the method being executed in Spring AOP) has the given
annotation.
In this case method is not annotated.
2.
The Configuration class RepositoryMetrics is not annotated with #EnableAspectJAutoProxy . I assume Spring AOP was not enabled in any of the Configuration classes.
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() {
}
I'm trying to create a demo AOP application but it just does not work right.
I read through all tutorials and got it working with #RestController but as I tried it with a plain java spring driven application I just can't get it to work. Please review my files and tell me where my mistake lies in.
Application Class
#SpringBootApplication
#ComponentScan("com.xetra.experimental")
#EnableAspectJAutoProxy
public class AoptryoutnowebApplication {
public static void main(String[] args) {
SpringApplication.run(AoptryoutnowebApplication.class, args);
DefaultClassToAspectImpl defaultClassToAspectImpl = new DefaultClassToAspectImpl();
defaultClassToAspectImpl.doStuff();
}
}
ClassToAspect Interface
public interface ClassToAspect {
void doStuff();
}
ClassToAspect Implementation
#Component
public class DefaultClassToAspectImpl implements ClassToAspect {
#FooAnnotation
public void doStuff(){
System.out.println("DoStuff!");
}
}
Annotation for Pointcut
public #interface FooAnnotation {
}
Aspect Class
#Aspect
public class FooAspect {
#Pointcut("#annotation(FooAnnotation)")
public void methods(){
}
#Before("methods()")
public void doAspect(){
System.out.println("FooAspect before");
}
}
Try this:
replace #EnableAspectJAutoProxy with #EnableAspectJAutoProxy(proxyTargetClass = false)
change pointcut to
#Pointcut("execution (* your.package..*.*(..)) && #annotation(fooAnnotation))")
The problem is you are using a non Spring managed instance by doing new DefaultClassToAspectImpl(). Spring AOP only works for Spring managed beans, because by default Spring AOP is proxy based.
So instead of doing new DefaultClassToAspectImpl() you should be obtaining the instance from the ApplicationContext. When using Spring Boot the SpringApplication.run call returns an ApplicationContext. Here you can use one of the getBean methods to obtain the instance you want.
ApplicationContext ctx = SpringApplication.run(AoptryoutnowebApplication.class, args);
ClassToAspect bean = getBean(ClassToAspect.class);
bean.doStuff();
This way you get the Spring managed
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 -->