Controller 中的请求方法,private 和 public有什么区别?别用错了!

作者:hinotoyk
链接:https://juejin.cn/post/6910215219822362632

背景:某日在公司中撸代码的时候,在一个常用的controller中添加一个方法,测试时突然报错说注入的service为null,捣鼓一阵发现后是方法修饰符写成private,修改成public后搞定。为什么会产生这个问题呢?就自己测试一下是哪里发生了问题

首先简单模拟一下环境

Spring Boot 基础就不介绍了,推荐看这个实战项目:

https://github.com/javastacks/spring-boot-best-practice

public interface TestService {
    String getTestString();
}


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

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

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

}

/testA是pulibc,/testB是pirvate,测试结果均能返回"hinotoyk"字符串

测试和公司环境还有一个不太同的就是公司项目中有Aop切面处理访问日志的,还要添加一个Aop

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

添加了一个 Aop 后测试:

/testA返回"hinotoyk"字符串

/testB访问报错,service注入失败,为null

为什么使用Aop会导致private修饰的方法注入失败,查询了许多资料后发现一位老哥的SpringAOP导致@Autowired依赖注入失败中说到org.springframework.aop.support.AopUtils中的代码使用的是Method[] methods = clazz.getMethods(),即是只能拿到public方法。但是我使用的版本2.1.4.RELEASE中已经使用Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);这就有点迷惑了

会不会是切点注解中的修饰符匹配不到呢?将切点中的修饰符从public修改成private

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

测试结果:

/testA返回"hinotoyk"字符串

/testB访问报错,service注入失败,为null

还是不行(就挺秃然的)

目前结论

  1. 方法中没有用@Autowired或者@Resource注入的对象。有无Aop,任意修饰符都可以正常访问并且返回结果
  2. 方法中使用了@Autowired或者@Resource注入的对象
    没有Aop切面的情况下,public,protected,private都能正常的映射
    在有Aop切面的情况下,public,protected可以正常映射,但是使用private会报空指针异常,注入对象为null

近期热文推荐:

1.1,000+ 道 Java面试题及答案整理(2022最新版)

2.劲爆!Java 协程要来了。。。

3.Spring Boot 2.x 教程,太全了!

4.别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!

5.《Java开发手册(嵩山版)》最新发布,速速下载!

觉得不错,别忘了随手点赞+转发哦!

热门相关:帝国远征   仙城之王   仙城之王   帝国远征   仙城之王