Search code examples
springspring-bootaopaspectj

How to do AOP on private / protected RequestMapping in Spring Boot


I want to do AOP on below @RequestMapping method call, notice the hello() method is NOT public.

@RestController
class HelloController {
    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    String hello() {
        return "Hello";
    }
}

Here is the main class, I have added @Aspect, @EnableAspectJAutoProxy annotation.

@Aspect
@EnableAspectJAutoProxy(proxyTargetClass = true)
@SpringBootApplication
public class FooServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(FooServiceApplication.class, args);
    }

    @Around("@annotation(requestMapping)")
    public Object around(ProceedingJoinPoint pjp, RequestMapping requestMapping) throws Throwable {
        return pjp.proceed();
    }
}

in pom.xml I just add below dependency:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>

The result is that if hello() method is public, the AOP will just works fine, but if the same as the example above without public declaration, the AOP will not work at all. But isn't EnableAspectJAutoProxy will use CGLIB and can intercept protected / private method calls?


Solution

  • According to the documentation Spring's Proxy based AOP can only intercept public 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.

    Before making a decision to use AspectJ weaving, I'd suggest you go through the appropriate section in the documentation to help you with the decision.

    Alternative

    Depending on what you wish to achieve, you may also consider using Filters.

    A filter intercepts every request and has the power to add / remove headers, authenticate, log etc.; usually executes generic / applicationwide operations.

    To add one simply declare a class

    import org.springframework.web.filter.GenericFilterBean;
    
    import javax.servlet.FilterChain;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import java.io.IOException;
    
    public class SomeFilter extends GenericFilterBean {
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            /*execute your logic*/
            if (/* request may proceed*/) {
                chain.doFilter(request,response);
            } else {
                /* write response */
            }
        }
    }