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.
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.
Architect's Guide
Dedicated to sharing programmer-architect skills—Java backend, system, microservice, and distributed architectures—to help you become a senior architect.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.