Spring Log for Rest Controller - java

I have a rest controller contains many methods
#RestController
#RequestMapping("v1/test")
public class TestRestController {
...... 100 methods (GET, POST, PATCH, etc)
}
How can I know which method is being accessed without using print in each method?
Are there any ways to do that?

While you can use AOP tactics noted in the other answers to log the methods, there are better approaches if all you want to do is log all of the requests and responses for the endpoints those methods implement. There are a couple ways this can be done: Use Spring's CommonRequestLoggingFilter or write your own HandlerInterceptor. Here is a nice article on the first two options.

Using Aspect Oriented Programming with Spring:
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
#Aspect
public class SpringAspect {
private static final Logger LOG = LoggerFactory.getLogger(SpringAspect.class);
#Before("execution(* sample.package.path.TestRestController.*(..))")
public void executedMethodsLogger(JoinPoint joinPoint) {
LOG.info("[ Executed method {} ]", joinPoint.toString());
}
}

You can use Spring AOP:
package com.example;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
#Aspect
public class ExampleAspect {
#Before("execution(* com.example.TestRestController(..)")
public void log(JoinPoint joinPoint) {
System.out.println("Executing :" + joinPoint.toString());
}
}

Related

Why the Pointcut expression is not working

If i keep #Pointcut("within(org.example.ShoppingCart.*)") in AuthenticationAspect.java then the authenticate method is NOT getting invoked BUT when i change to #Pointcut("within(org.example..*)") then it does get invoked.
Doesn't the 2nd PointCut below automatically include the first one?
#Pointcut("within(org.example.ShoppingCart.*)")
#Pointcut("within(org.example..*)")
i believe both of these should work.
Following is the code :
ShoppingCart.java
package org.example;
import org.springframework.stereotype.Component;
#Component
public class ShoppingCart {
public void checkout(String status)
{
System.out.println("Checkout method called");
}
}
AuthenticationAspect.java
package org.example;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
#Aspect
#Component
public class AuthenticationAspect {
#Pointcut("within(org.example.ShoppingCart.*)")
public void authenticationPointCut()
{
}
#Before("authenticationPointCut()")
public void authenticate()
{
System.out.println("Authentication is being performed");
}
}
Main.java
package org.example;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
ShoppingCart cart = context.getBean(ShoppingCart.class);
cart.checkout("CANCELLED");
}
}
BeanConfig.java
package org.example;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
#Configuration // Indicates this is a configuration class
#ComponentScan(basePackages = "org.example") // Indicates where to find the components/beans
#EnableAspectJAutoProxy // Enables the AspectJ features in project
public class BeanConfig {
}
i am learning spring aspect and unsure why the pointcut expression is not working .
Since the within pointcut designator limits matching to join points of certain types, the problem is your pointcut expression is matching types within ShoppingCart because of .* in the end. If you remove those characters it should work.
#Pointcut("within(org.example.ShoppingCart)")
public void authenticationPointCut(){}

AspectJ not executing the advice

I am trying to understand how AspectJ works so I built this very simple example. I can execute x() from a web browser but applaud() never gets executed. Why? How can I get it executed (apart from calling it inside x())? I am trying to do all this without creating an xml.
My environment is Java, Spring, AspectJ, IntelliJ and Windows 10.
package hello;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
#Aspect
#Configuration
#EnableAspectJAutoProxy
public class SomeClass {
#RequestMapping("/x")
#Pointcut("execution(* hello.SomeClass.x())")
public String x() {
System.out.println("in x");
return "<div><h1>Some content</h1></div>";
}
#After("hello.SomeClass.x()")
public void applaud() {
System.out.println("CLAPCLAPCLAPCLAPCLAP");
}
}

Capturing advice execution (advising advice) in AspectJ

I'm trying to capture the execution of an advice using annotation in Maven, but it says that advice has not been applied. Here is the code:
package testMaven8;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
#Aspect
public class aspecter {
public static int a;
public void setA(int a) {
this.a = a;
}
public int getA() {
return a;
}
#Before("execution(* testMaven8.das.qwe(..))")
public void testBefore2(){
System.out.println("yoo2");
setA(102);
System.out.println(a);
}
#Before("execution (* testMaven8.aspecter.testBefore2(..))")
public void advice1(){
System.out.println("advicing advice testBefore2");
}
}
Is there something wrong with the code? I'm trying to avoid the usage of Aspect class if it's possible. Any help is appreciated.
Thanks
Advice execution is something special in AspectJ, not a normal method execution. Thus, if you want to capture advice execution you also need a special pointcut with the surprising name - adviceexecution() ;-)
Here is some sample code:
Driver application:
package de.scrum_master.app;
public class Application {
public static void main(String[] args) {
new Application().doSomething();
}
public void doSomething() {
System.out.println("Doing something");
}
}
Aspect capturing method executions:
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
#Aspect
public class MethodInterceptor {
#Before("execution(!static * *(..))")
public void interceptMethod(JoinPoint thisJoinPoint) {
System.out.println(thisJoinPoint);
}
}
Aspect capturing advice executions:
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
#Aspect
public class AdviceInterceptor {
#Before("!within(AdviceInterceptor) && adviceexecution()")
public void interceptAdvice(JoinPoint thisJoinPoint) {
System.out.println(thisJoinPoint);
}
}
Please do not try to pack the advice execution interceptor into the same aspect as another advice because you can easily end up in an endless recursion if you cannot exclude the adviceexecution() pointcut from capturing itself via !within(AdviceInterceptor).
Console log:
adviceexecution(void de.scrum_master.aspect.MethodInterceptor.interceptMethod(JoinPoint))
execution(void de.scrum_master.app.Application.doSomething())
Doing something

AOP for all methods in a package

I am using AOP for the first time.
I have written the below AOP code which works fine when i use it to intercept a particular method.
Can somebody guide me - how I can set it up to intercept all methods in a certain package (com.test.model)?
Basically how to setup appcontext.xml.
Also, do i need to do something like below to call before calling each method?
AopClass aoptest = (AopClass) _applicationContext.getBean("AopClass");
aoptest.addCustomerAround("dummy");
Can somebody help?
Please let me if some more explanation is needed.
Below is my code:
Interface:
package com.test.model;
import org.springframework.beans.factory.annotation.Autowired;
public interface AopInterface {
#Autowired
void addCustomerAround(String name);
}
Class:
package com.test.model;
import com.test.model.AopInterface;
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Autowired;
#Component
public class AopClass implements AopInterface {
public void addCustomerAround(String name){
System.out.println("addCustomerAround() is running, args : " + name);
}
}
AOP:
package com.test.model;
import java.util.Arrays;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
#Aspect
public class TestAdvice{
#Around("execution(* com.test.model.AopInterface.addCustomerAround(..))")
public void testAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("testAdvice() is running!");
}
}
appcontext:
<!-- Aspect -->
<aop:aspectj-autoproxy />
<bean id="AopClass" class="com.test.model.AopClass" />
<bean id="TestAdvice" class="com.test.model.TestAdvice" />
Just put:
#Around("execution(* com.test.model..*.*(..))")
The format of an execution expression is:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
where only ret-type-pattern, name-pattern and param-pattern are required, so at least we need an expression like:
execution(ret-type-pattern name-pattern(param-pattern))
ret-type-pattern matches the return type, * for any
name-pattern matches the method name, you can use * as wildcard and .. to indicate sub-package
param-pattern matches the method parameters, (..) for any number of parameters
You can find more information here: 10. Aspect Oriented Programming with Spring, there are some useful examples.

Spring Boot AOP not working for AfterThrow

package test.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.velocity.VelocityAutoConfiguration;
import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
#Component
#Aspect
class LoggingMonitor {
#AfterThrowing(
pointcut = "execution(* test.aop..foo(..))",
throwing = "error")
public void logAfterThrowing(JoinPoint joinPoint, Throwable error) {
System.out.println(joinPoint);
}
}
#Service
class MyBean {
void foo() {
throw new RuntimeException("run error");
}
}
#SpringBootApplication
public class App {
#Autowired
MyBean myBean;
#Bean
CommandLineRunner runner() {
return r -> {
System.out.println("Run");
myBean.foo();
};
}
public static void main(String[] args) {
SpringApplication.run(App.class);
}
}
I don't understand why the code above not working, but when I changed my pointcut to "* org.springframework.boot.CommandLineRunner.run(..)", it works.
Spring AOP works on public methods only. Make your method public, or revert to AspectJ.
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.
Source

Categories