I have a simple example of an aspectj implementation in a spring boot app and I'm trying to get each different method working.
If I use the following
#Before("execution(* com.example.test.controllers.ProductController.deleteProduct(..))")
public void specificInterception() {
System.out.println("pointcut interception working");
}
This works fine, and I can see a console output of the println
However, if I use
#Pointcut("execution(* com.example.test.controllers.ProductController.deleteProduct(..))")
public void specificInterception() {
System.out.println("pointcut interception working");
}
It fails to trigger. Why is this not working?
A method annotated with #Pointcut on its own doesn't do anything. It only allows you re-use the same expression multiple times rather than having to redeclare it. I'm not even sure if the method body of such a method will be invoked.
In your case, you can use your pointcut like this:
#Pointcut("execution(* com.example.test.controllers.ProductController.deleteProduct(..))")
public void specificPointcut() {}
#Before("specificPointcut()")
public void specificInterception() {
System.out.println("pointcut interception working");
}
Related
Quarkus 2.8.0.Final introduced QuarkusTransaction. What is the difference between
#ApplicationScoped
public class MyClass {
#Inject
TransactionManager tm;
public void doSomething() throws Exception {
tm.begin();
// ...
tm.commit();
}
}
and
#ApplicationScoped
public class MyClass {
public void doSomething() {
QuarkusTransaction.begin();
// ...
QuarkusTransaction.commit();
}
}
?
I am using the TransactionManager in a lot of my tests, and when I replaced it with QuarkusTransaction, I am getting different error messages when something fails:
When using the TransactionManager, I am getting
javax.transaction.NotSupportedException: BaseTransaction.checkTransactionState - ARJUNA016051: thread is already associated with a transaction!
When using QuarkusTransaction, I am getting
javax.enterprise.context.ContextNotActiveException
The Quarkus documentation does not really explain why QuarkusTransaction was introcuded 🤔
QuarkusTransaction was introduced with this Pull Request and the idea is to provide an easier to use Transactions API.
As can be seen in this test, it's meant to be used when a request scope is active
Guess I have these methods:
#Service
public class Service1 {
private #Autowired Service2 service2;
public void method1() {
this.service2.method2();
}
}
#Service2
public class Service2 {
public void method2() {
// Do something
}
}
I'd like to know how to capture Service2.method2() call, when it's called from Service1.method1()).
Any ideas?
You can either use AspectJ from within Spring instead of Spring AOP vis compile-time or load-time weaving and then a pointcut like
execution(* my.package.Service2.method2()) &&
cflow(execution(* my.package.Service2.method2()))
or, similar to what #Damith said, use either of
Thread.currentThread().getStackTrace(),
new Exception().getStackTrace() or
the Java 9 StackWalker API
in order to navigate the call stack manually and find the information you are looking for. My suggestion is to use AspectJ, not just because of its elegance but also because of its efficiency.
I'm trying to output a log message whenever the function someFunction() gets invoked.
This is my Aspect:
#Aspect
#Component
public class MyAspect {
private static final Logger LOGGER = Logger.getLogger(MyAspect.class.getName());
#Pointcut("execution(com.practice.AOP.someFunction())")
public void outputLogMessage() {
LOGGER.info("someFunction has been invoked");
}
}
The method i'm trying to intercept, someFunction(), is in the com.practice.AOP class. When I invoke it (shown below), my Advice (the log message) doesn't output, nor do I get an error. What am I doing wrong? Is Pointcut even the way to go?
#SpringBootApplication
public class AOP {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
someFunction();
}
public static void someFunction() {
//should invoke the log message
}
}
Spring AOP only works on Spring beans, and only on public instance methods of those spring beans invoked from the outside (i.e. this.publicMethod() style invocations will not work, as they are not going through the proxies that Spring AOP creates to advise your spring beans.
If that is not enough for you, for instance if you need to advise not just spring beans but non-spring managed code as well, or static methods like in your example, you will need to switch to native AspectJ support, either by compile time weaving, or by load time weaving.
For spring boot application.
I have my aspect listen on my private or public method inside my scheduled method.
But it doesn't work. However, the aspect can listen on my scheduled method.
Here is an example on my github.
https://github.com/benweizhu/spring-boot-aspect-scheduled
Does any know the answer or why? or how to resolve it?
Thanks
Aspects will not work on calling other methods within the same class as it cannot be proxied.
It means that self-invocation is not going to result in the advice associated with a method invocation getting a chance to execute.
Okay, so what is to be done about this? The best approach (the term best is used loosely here) is to refactor your code such that the self-invocation does not happen
note on proxying private methods :
Due to the proxy-based nature of Spring’s AOP framework, protected methods are by definition not intercepted, neither for JDK proxies (where this isn’t applicable) nor for CGLIB proxies (where this is technically possible but not recommendable for AOP purposes). As a consequence, any given pointcut will be matched against public methods only!
If your interception needs include protected/private methods or even constructors, consider the use of Spring-driven native AspectJ weaving instead of Spring’s proxy-based AOP framework. This constitutes a different mode of AOP usage with different characteristics, so be sure to make yourself familiar with weaving first before making a decision.
refer : How can I log private methods via Spring AOP?
change the code as below:
#Component
public class Test{
public void reportInPrivateMethod() {
System.out.println("private method");
}
public void reportInPublicMethod() {
System.out.println("public method");
}
}
Now invoke this method :
#Component
public class ScheduledTasks {
#Autowired
private Test test;
private static final Logger log = LoggerFactory.getLogger(ScheduledTasks.class);
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
#Scheduled(fixedRate = 5000)
public void reportCurrentTime() {
test.reportInPrivateMethod();
test.reportInPublicMethod();
log.info("The time is now {}", dateFormat.format(new Date()));
}
}
Modify the aspects as per the changes :
#Aspect
#Component
public class Monitor {
#AfterReturning("execution(* com.zeph.aop.ScheduledTasks.reportCurrentTime())")
public void logServiceAccess(JoinPoint joinPoint) {
System.out.println("Completed: " + joinPoint);
}
#AfterReturning("execution(* com.zeph.aop.Test.reportInPrivateMethod())")
public void logServiceAccessPrivateMethod() {
System.out.println("Completed PRIVATE :");
}
#AfterReturning("execution(* com.zeph.aop.Test.reportInPublicMethod())")
public void logServiceAccessPublicMethod() {
System.out.println("Completed PUBLIC: ");
}
}
I have a Class, call it X, in this class I have successfully advised a method call it method(){} from an Annotated Spring.
So, here it is:
public class X {
public void method(){...}
public void method2(){...}
}
Here is my aspect, shortened of course:
#Aspect
public class MyAspect{
#Pointcut("execution(* X.method(..))")
public void methodJP(){}
#Pointcut("execution(* X.method2(..))")
public void method2JP(){}
#Around("methodJP()")
public void doMethodJP(ProceedingJoinPoint pjp) throws Exception {
pjp.proceed(); //Amongst other things!!!
}
#After("method2JP()")
public void doMethod2JP(JoinPoint jp) throws Exception {
//Do some stuff here
}
}
Now... both join points work well, however, I within my X.method, I also call the method that is advised by method2JP()... and of course, my method2JP does not get triggered.
Is there any way I can get this to work?
Thanks.
Since Spring AOP works by proxying classes, for the advice to be invoked, you must call the method through the proxy or wrapper supplied by the bean factory.
If you don't want to break out into multiple classes, you can have the method retrieve a the proxied version of "itself" from the beanfactory. Something like this
#Service
public class MyService {
#Autowired
ApplicationContext context;
public void method1() {
context.getBean(MyService.class).method2();
}
public void method2() {
}
}
This will guarantee that the invocation of method2 from method1 will apply any aspects on the method2 pointcut.
methodJP() should be declared in another class. In the regular scenario the aspects are not triggered when you invoke a method from within the same object.