Why Private Controller Methods Fail with Spring AOP: The Hidden CGLIB Limitation

This article explains why private controller methods in Spring Boot fail when AOP logging is enabled, revealing that CGLIB proxies cannot intercept private methods, which leads to null service injection, and provides code examples and a final conclusion.

Java Backend Technology
Java Backend Technology
Java Backend Technology
Why Private Controller Methods Fail with Spring AOP: The Hidden CGLIB Limitation

Background: In a code review the author asked whether controller request methods can be private or protected instead of public.

An example environment is simulated with a service interface, its implementation, and a RestController containing a public endpoint /testA and a private endpoint /testB. Both return the string "业余草".

public interface TestService {
    String getTestString();
}

@Service("testService")
public class TestServiceImpl implements TestService {
    @Override
    public String getTestString() {
        return "业余草";
    }
}

@RestController
public class MainController {
    @Autowired
    private TestService service;

    @RequestMapping("/testA")
    public String testA() {
        return service.getTestString();
    }

    @RequestMapping("/testB")
    private String testB() {
        return service.getTestString();
    }
}

Without AOP, both /testA and /testB return the expected string. Adding an AOP logging aspect changes the behavior.

@Aspect
@Component
public class WebLogAspect {
    private final Logger logger = LoggerFactory.getLogger(WebLogAspect.class);

    @Pointcut("execution(public * com.spring.controller..*.*(..))")
    public void controllerLog(){}

    @Before("controllerLog()")
    public void logBeforeController(JoinPoint joinPoint) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        logger.info("*************URL : " + request.getRequestURL().toString());
        logger.info("*************HTTP_METHOD : " + request.getMethod());
        logger.info("*************IP : " + request.getRemoteAddr());
    }
}

After adding the aspect, /testA still works, but /testB throws a NullPointerException because the injected service is null.

Changing the pointcut to include private methods ( execution(private* com.spring.controller..*.*(..))) does not solve the problem; the private method still fails.

Conclusion: When AOP is active, Spring Boot 2.1.4 uses CGLIB proxies, which create a subclass of the target class. Private methods are not inherited by the subclass if it resides in a different package, so CGLIB cannot proxy them, leading to null injection.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

BackendaopSpring Bootcglibprivate methods
Java Backend Technology
Written by

Java Backend Technology

Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.