Aspectj 切入点表达式不适用于一种方法,而适用于单个 class 中的另一种方法
Aspectj Pointcut expression not working for one method and working for another method in single class
我已经在控制器中编写了以下代码。
对于此 controllerMethod 方法,aspectj Pointcut 表达式工作正常,但对于 executeService 方法,Aspect 不起作用。
@RequestMapping(value = "URL", method = RequestMethod.POST)
public ModelAndView controllerMethod(@ModelAttribute ModelAttribute reqModel, HttpServletRequest req, HttpServletResponse res) {
try {
response = executeService(param1, param2);
} catch (Exception e) {
}
}
private ResponseObject executeService(String param1, String param2){
//Code....
}
我写的方面如下。
@Before("execution(* com.*.*.Controller.executeService(..))")
public void logBefore(JoinPoint joinPoint) {
logger.info("Before aspect: " + joinPoint.getSignature().getName());
}
你能告诉我问题出在哪里吗?我需要在调用 executeService 方法之前执行方面。
需要@RequestMapping(value = "URL", method = RequestMethod.POST) 直接
executeService 然后它的工作。
因为AOP
不拦截内部调用,所以可以添加一个自控字段,通过self.method(...)
调用内部方法。
以下代码:
@Controller
public class ExampleController{
@Autowired
private ExampleController self;
@RequestMapping(value = "URL", method = RequestMethod.POST)
public ModelAndView controllerMethod(@ModelAttribute ModelAttribute reqModel, HttpServletRequest req, HttpServletResponse res) {
try {
response = self.executeService(param1, param2);
} catch (Exception e) {
}
}
public ResponseObject executeService(String param1, String param2){
//Code....
}
}
虽然我们的同事都给出了正确的答案,我总结一下。
在方面实现方面,spring 生成一个包装您的控制器的代理。代理的实现方式是它有特殊的钩子来调用 class 之前和之后的方面(或周围,完全改变流程)。
Spring 使用两种不同的代理生成策略:
- java.lang.Proxy 基于
- 基于 CGLIB
第一个通常更好、更快,但仅适用于接口。生成的代理是实现接口所有方法的“东西”。实现方法包含我之前讨论过的那些钩子,但由于这些方法只是接口中的方法,因此它们必须是 public
CGLIB - 速度较慢,但它也可以与 classes 一起使用(尽管有一些限制)。它的工作方式是子 class 父 class 并覆盖超级 class 提供的方法。这个新方法(我们称之为 foo)将调用所有挂钩,如果需要,代码中的某处将调用 super.foo()
.
现在,显然这不能真正用于私有方法,因为它不可能覆盖私有方法。
这就是为什么我的同事指出 private
在这里不起作用。
现在关于自我注射的东西:
当你在原始控制器的方法中并且你试图调用另一个方法(即使它 public),你不再使用代理,你很善良在代理后面并使用原始 class。所以这意味着您将无法利用“增强”方法。
这就是为什么会有自注入 - 你可以看到(例如使用调试器)自注入依赖实际上是对所有代理的依赖,这就是它开始工作的原因。
另一种解决方法是将方法重构为另一个 Spring bean,将此 bean 注入您的控制器,并为该 bean 提供定义。
我已经在控制器中编写了以下代码。
对于此 controllerMethod 方法,aspectj Pointcut 表达式工作正常,但对于 executeService 方法,Aspect 不起作用。
@RequestMapping(value = "URL", method = RequestMethod.POST)
public ModelAndView controllerMethod(@ModelAttribute ModelAttribute reqModel, HttpServletRequest req, HttpServletResponse res) {
try {
response = executeService(param1, param2);
} catch (Exception e) {
}
}
private ResponseObject executeService(String param1, String param2){
//Code....
}
我写的方面如下。
@Before("execution(* com.*.*.Controller.executeService(..))")
public void logBefore(JoinPoint joinPoint) {
logger.info("Before aspect: " + joinPoint.getSignature().getName());
}
你能告诉我问题出在哪里吗?我需要在调用 executeService 方法之前执行方面。
需要@RequestMapping(value = "URL", method = RequestMethod.POST) 直接 executeService 然后它的工作。
因为AOP
不拦截内部调用,所以可以添加一个自控字段,通过self.method(...)
调用内部方法。
以下代码:
@Controller
public class ExampleController{
@Autowired
private ExampleController self;
@RequestMapping(value = "URL", method = RequestMethod.POST)
public ModelAndView controllerMethod(@ModelAttribute ModelAttribute reqModel, HttpServletRequest req, HttpServletResponse res) {
try {
response = self.executeService(param1, param2);
} catch (Exception e) {
}
}
public ResponseObject executeService(String param1, String param2){
//Code....
}
}
虽然我们的同事都给出了正确的答案,我总结一下。
在方面实现方面,spring 生成一个包装您的控制器的代理。代理的实现方式是它有特殊的钩子来调用 class 之前和之后的方面(或周围,完全改变流程)。
Spring 使用两种不同的代理生成策略:
- java.lang.Proxy 基于
- 基于 CGLIB
第一个通常更好、更快,但仅适用于接口。生成的代理是实现接口所有方法的“东西”。实现方法包含我之前讨论过的那些钩子,但由于这些方法只是接口中的方法,因此它们必须是 public
CGLIB - 速度较慢,但它也可以与 classes 一起使用(尽管有一些限制)。它的工作方式是子 class 父 class 并覆盖超级 class 提供的方法。这个新方法(我们称之为 foo)将调用所有挂钩,如果需要,代码中的某处将调用 super.foo()
.
现在,显然这不能真正用于私有方法,因为它不可能覆盖私有方法。
这就是为什么我的同事指出 private
在这里不起作用。
现在关于自我注射的东西:
当你在原始控制器的方法中并且你试图调用另一个方法(即使它 public),你不再使用代理,你很善良在代理后面并使用原始 class。所以这意味着您将无法利用“增强”方法。
这就是为什么会有自注入 - 你可以看到(例如使用调试器)自注入依赖实际上是对所有代理的依赖,这就是它开始工作的原因。
另一种解决方法是将方法重构为另一个 Spring bean,将此 bean 注入您的控制器,并为该 bean 提供定义。