Spring-AOP 切入点不起作用?
Spring-AOP pointcut not working?
下面是我的代码片段:
ServiceImpl.java
@Service
public class ServiceImpl implements Service {
private Response worker(Audit send) throws ArgumentException {
System.out.println("STEP_1");
worker(send.getRequest(), send.getId());
}
private Response worker(Request request, String id) throws ArgumentException {
System.out.println("STEP_2");
try {
//throwing some exception
} catch (Exception e) {
System.out.println("STEP_3");
}
}
}
现在,我想要的是每当 NullPointerException
从方法 worker(Request request, String id)
中抛出时,如上所示,我想执行一些特定的任务。为此,我写了一个方面 class,如下所示:
MyAspect.java
@Aspect
@Component
public class MyAspect{
@Pointcut("com.xyz.myapp.ServiceImpl.worker() && args(request,..)")
private void someOperation(Request request) {}
@Before("someOperation(request)")
public void process(Request request) {
System.out.println("SUCCESS");
}
@AfterThrowing("com.xyz.myapp.ServiceImpl.worker() && args(request,..)")
public void doRecoveryActions() {
System.out.println("EXCEPTION_SUCCESS");
}
}
当前输出:
STEP_1
STEP_2
STEP_3
期望输出:
STEP_1
STEP_2
STEP_3
SUCCESS
EXCEPTION_SUCCESS
如您所见,MyAspect.java
未被触发,因此未打印值。
这可能是什么原因?
注:
我也试过将 worker 设为 public class,但没用。
还尝试更改方法的名称以消除任何也不起作用的重载问题。
到目前为止尝试了各种其他切入点表达式都是徒劳的。
在我的应用程序中,还有其他方面 class 工作得很好。
您犯了一个典型的 Spring AOP 初学者错误:您假设它适用于私有方法,但正如文档明确指出的那样,事实并非如此。 Spring AOP 基于动态代理,当通过 JDK 代理实现接口时,那些仅适用于 public 方法,当使用 CGLIB 代理时,它们还适用于受保护和包范围的方法。
如果你想从一个方面拦截它,你应该制作worker()
方法public。
P.S.: 成熟的 AspectJ 也适用于私有方法,但切换到另一个 AOP 框架在这里就太过分了。
更新:你的代码还有其他问题:
- 第一个
worker
方法,即使你做到了 public,也不会 return 任何东西。最后一条语句应该是 return worker(send.getRequest(), send.getId());
,而不仅仅是 worker(send.getRequest(), send.getId());
.
- 你的切入点
com.xyz.myapp.ServiceImpl.worker()
永远不会匹配,因为它有一个空参数列表,但你的方法有参数。 args()
在这里帮不了你。
- 你的切入点的语法也是错误的,因为它没有为方法指定 return 类型,甚至没有
*
。此外,方法名称本身是不够的,它应该包含在实际的切入点类型中,例如 execution()
。 IE。你想写这样的东西:
@Pointcut("execution(* com.xyz.myapp.ServiceImpl.worker(..)) && args(request, ..)")
private void someOperation(Request request) {}
要拦截抛出异常的方法,您可以使用此代码(仅在方法为 public 时有效):
@AfterThrowing(pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",throwing="ex")
public void doRecoveryActions(NullPointerException ex) {
// ...
}
来源:Spring AOP
下面是我的代码片段:
ServiceImpl.java
@Service
public class ServiceImpl implements Service {
private Response worker(Audit send) throws ArgumentException {
System.out.println("STEP_1");
worker(send.getRequest(), send.getId());
}
private Response worker(Request request, String id) throws ArgumentException {
System.out.println("STEP_2");
try {
//throwing some exception
} catch (Exception e) {
System.out.println("STEP_3");
}
}
}
现在,我想要的是每当 NullPointerException
从方法 worker(Request request, String id)
中抛出时,如上所示,我想执行一些特定的任务。为此,我写了一个方面 class,如下所示:
MyAspect.java
@Aspect
@Component
public class MyAspect{
@Pointcut("com.xyz.myapp.ServiceImpl.worker() && args(request,..)")
private void someOperation(Request request) {}
@Before("someOperation(request)")
public void process(Request request) {
System.out.println("SUCCESS");
}
@AfterThrowing("com.xyz.myapp.ServiceImpl.worker() && args(request,..)")
public void doRecoveryActions() {
System.out.println("EXCEPTION_SUCCESS");
}
}
当前输出:
STEP_1
STEP_2
STEP_3
期望输出:
STEP_1
STEP_2
STEP_3
SUCCESS
EXCEPTION_SUCCESS
如您所见,MyAspect.java
未被触发,因此未打印值。
这可能是什么原因?
注:
我也试过将 worker 设为 public class,但没用。
还尝试更改方法的名称以消除任何也不起作用的重载问题。
到目前为止尝试了各种其他切入点表达式都是徒劳的。
在我的应用程序中,还有其他方面 class 工作得很好。
您犯了一个典型的 Spring AOP 初学者错误:您假设它适用于私有方法,但正如文档明确指出的那样,事实并非如此。 Spring AOP 基于动态代理,当通过 JDK 代理实现接口时,那些仅适用于 public 方法,当使用 CGLIB 代理时,它们还适用于受保护和包范围的方法。
如果你想从一个方面拦截它,你应该制作worker()
方法public。
P.S.: 成熟的 AspectJ 也适用于私有方法,但切换到另一个 AOP 框架在这里就太过分了。
更新:你的代码还有其他问题:
- 第一个
worker
方法,即使你做到了 public,也不会 return 任何东西。最后一条语句应该是return worker(send.getRequest(), send.getId());
,而不仅仅是worker(send.getRequest(), send.getId());
. - 你的切入点
com.xyz.myapp.ServiceImpl.worker()
永远不会匹配,因为它有一个空参数列表,但你的方法有参数。args()
在这里帮不了你。 - 你的切入点的语法也是错误的,因为它没有为方法指定 return 类型,甚至没有
*
。此外,方法名称本身是不够的,它应该包含在实际的切入点类型中,例如execution()
。 IE。你想写这样的东西:
@Pointcut("execution(* com.xyz.myapp.ServiceImpl.worker(..)) && args(request, ..)")
private void someOperation(Request request) {}
要拦截抛出异常的方法,您可以使用此代码(仅在方法为 public 时有效):
@AfterThrowing(pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",throwing="ex")
public void doRecoveryActions(NullPointerException ex) {
// ...
}
来源:Spring AOP