如何在 Spring 引导中对私有/受保护的 RequestMapping 执行 AOP

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

我想在下面的 @RequestMapping 方法调用上执行 AOP,注意 hello() 方法是 NOT public.

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

这里是主要的class,我添加了@Aspect,@EnableAspectJAutoProxy注解

@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();
    }
}

在pom.xml我只是添加下面的依赖:

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

结果是,如果hello()方法是public,AOP就可以正常工作,但是如果和上面的例子一样,没有public声明,AOP就不会工作全部。但是 EnableAspectJAutoProxy 是不是会使用 CGLIB 并且可以拦截受保护/私有方法调用?

根据documentationSpring的Proxy based AOP只能拦截public方法

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.

在决定使用 AspectJ 编织之前,我建议您阅读文档中的 appropriate section 以帮助您做出决定。

备选

根据您希望达到的效果,您也可以考虑使用Filters

过滤器拦截每个请求并有权添加/删除headers、验证、记录等;通常执行通用/应用程序范围的操作。

要添加一个,只需声明一个 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 */
        }
    }
}