Backend Development 5 min read

Why Private Controller Methods Fail Dependency Injection When Using AOP in Spring Boot

This article explains why a private method in a Spring Boot @RestController cannot have its @Autowired service injected when an AOP aspect is present, demonstrates the issue with code examples, and clarifies the underlying proxy mechanism that causes the null‑pointer error.

Architect's Guide
Architect's Guide
Architect's Guide
Why Private Controller Methods Fail Dependency Injection When Using AOP in Spring Boot

During a code‑review meeting the author assigned a task to investigate whether controller request methods in Spring Boot must be public and why a private method leads to a null service injection when AOP is applied.

First, a simple environment is set up with an interface TestService , its implementation TestServiceImpl , and a MainController that autowires the service. Two endpoints are defined: /testA (public) and /testB (private).

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 any AOP, both /testA and /testB return the expected string. After adding an AOP aspect that logs request details, the /testB endpoint throws a NullPointerException because the injected service is null .

@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) {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
        logger.info("*************URL : " + request.getRequestURL().toString());
        logger.info("*************HTTP_METHOD : " + request.getMethod());
        logger.info("*************IP : " + request.getRemoteAddr());
    }
}

The author tried changing the pointcut expression to include private methods (e.g., execution(private* com.spring.controller..*.*(..)) ), but the problem persisted.

Final conclusion: with Spring Boot 2.1.4 (which uses CGLIB for dynamic proxies), private methods cannot be proxied because the generated subclass resides in a different package and lacks access to the superclass's private members. Consequently, when an AOP aspect is present, a private controller method cannot have its @Autowired dependencies injected, leading to a null reference.

Therefore, in a Spring Boot application that employs AOP, controller request methods should be declared public (or at least non‑private) to ensure proper dependency injection.

JavaAOPSpring Bootdependency injectionControllerprivate-method
Architect's Guide
Written by

Architect's Guide

Dedicated to sharing programmer-architect skills—Java backend, system, microservice, and distributed architectures—to help you become a senior architect.

0 followers
Reader feedback

How this landed with the community

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