由于想记录 Controller 前后的处理情况,为什么不用 filter 处理是因为项目中有作业等其他请求,并不想做太多记录。
/**
* 记录controller方法前所有的日志
*
* @param joinPoint 不能为空
*/
@Before("execution(* com.xxx.controller..*.*(..))")
public void pointBeforeMethodInvoke(JoinPoint joinPoint) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
StringBuilder sb = new StringBuilder("---------- Starting : ");
sb.append(joinPoint.getSignature().getDeclaringTypeName());
sb.append(".");
sb.append(joinPoint.getSignature().getName());
sb.append(logAllParamsInfo(joinPoint));
sb.append("TAG_UUID:");
sb.append(RequestContext.getContext().getId());
sb.append(", Token:");
sb.append(request.getParameter("token"));
sb.append(" --------");
info(sb::toString);
RequestContext.getContext().setBeginTime(System.currentTimeMillis());
}
然后我们的包结构如下:(xx 是把关键字隐去了)
可以看到我的切面是切的 controller 以及它下面的子包 api 和相关的类。
public class StatisticsController {
private static final Logger logger = LoggerFactory.getLogger(StatisticsController.class);
@Autowired
private IStatisticsService statisticsService;
@Autowired
private IKnowledgeService knowledgeService;
@PostConstruct
private void init() {
StatisticsController statisticsController = this;
statisticsController.knowledgeService = this.knowledgeService;
}
然后在 init 方法中 debug, 发现在 Spring 启动的时候,statisticsService 和 knowledgeService 注入正常,但是在请求 Controller 的时候,2 个 Service 还是 null。
与AspectJ相比,Spring AOP是一种基于代理的“AOP lite”方法。它仅适用于Spring组件,仅适用于公共,非静态方法。这在Spring AOP文档中也有解释,如下所示:
由于Spring的AOP框架基于代理的特性,受保护的方法根据定义不会被拦截,既不用于JDK代理(这不适用),也不用于CGLIB代理(这在技术上可行,但不建议用于AOP)。因此,任何给定的切入点都只能与公共方法匹配!如果您的拦截需要包括受保护/私有方法甚至构造函数,请考虑使用Spring驱动的本机AspectJ编织而不是Spring的基于代理的AOP框架。这构成了具有不同特征的不同AOP使用模式,因此在做出决定之前一定要先熟悉编织。
说白了 就是 aop底层是代理, jdk是代理接口,私有方法必然不会存在在接口里,所以就不会被拦截到; cglib是子类,private的方法照样不会出现在子类里,也不能被拦截。
不是类内部直接调用方法,而是通过维护一个自身实例的代理 所以 execution(public * com.xxx.controller...(..))) 只会切 public 的方法,不写也一样,public 是默认切的方法,如果写了protected,他就什么事情都不做,连protected的方法也不拦截。 如果想要实现拦截private方法的 可以使用 原生 AspectJ 编译期/运行期织入。
而我们上面的空指针问题,其实就是 切面已经代理了 Controller 下的类,但是又没有被切到,造成了注入的失败。