Spring AOP 使用代理来拦截和修改方法调用。因此,要对 Spring bean 方法应用 AOP,这些方法必须具有适当的可见性,以便代理可以访问它们。
方法可见性要求
Spring AOP 对被代理方法的可见性有以下要求:
- 对于 JDK 动态代理,方法必须是 public,因为动态代理只能代理 public 方法。
- 对于 CGLIB 代理,方法可以是任何可见性,包括 public、protected、default(包)和 private。
为什么需要这些可见性要求?
这些可见性要求是由于 Spring AOP 使用不同的技术来创建代理:
- JDK 动态代理:JDK 动态代理创建代理对象,其中包含目标对象方法的增强版本。由于代理对象必须能够调用目标对象的方法,因此目标对象的方法必须是 public。
- CGLIB 代理:CGLIB 代理创建目标类的子类,其中覆盖目标对象的方法并插入自定义逻辑。由于子类可以访问父类的方法,因此 CGLIB 代理可以代理任何可见性的方法,包括 private 方法。
例外情况:
在某些情况下,即使方法不是 public,也可以使用 Spring AOP 对其进行代理:
- 接口方法:接口方法始终是 public 的,因此可以使用 JDK 动态代理对其实现进行代理,即使实现方法不是 public。
- final 方法:虽然 JDK 动态代理无法代理 final 方法,但 CGLIB 代理可以,因为 CGLIB 创建子类并覆盖方法。
建议的最佳实践
为了确保 Spring AOP 能够成功代理方法,建议将被代理方法声明为 public。这将确保无论使用哪种代理类型,都可以对方法进行代理。
示例
以下示例演示了如何使用不同可见性的方法以及如何使用 Spring AOP 对它们进行代理:
// public 方法
public void publicMethod() {
// do something
}
// protected 方法
protected void protectedMethod() {
// do something
}
// default(包)方法
void defaultMethod() {
// do something
}
// private 方法
private void privateMethod() {
// do something
}
使用 JDK 动态代理:
// 只能代理 public 方法
MyBean bean = new MyBean();
AdvisedSupport advised = new AdvisedSupport();
advised.setTargetSource(new TargetSource(bean));
advised.addAdvice(new MyAdvice());
ProxyFactory factory = new ProxyFactory(advised);
MyBean proxy = (MyBean) factory.getProxy();
proxy.publicMethod(); // 可以调用
使用 CGLIB 代理:
// 可以代理任何可见性的方法
MyBean bean = new MyBean();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(MyBean.class);
enhancer.setCallback(new MyMethodInterceptor());
MyBean proxy = (MyBean) enhancer.create();
proxy.publicMethod(); // 可以调用
proxy.protectedMethod(); // 可以调用
proxy.defaultMethod(); // 可以调用
proxy.privateMethod(); // 可以调用
总结
Spring AOP 对要代理的方法的可见性有要求。对于 JDK 动态代理,方法必须是 public。对于 CGLIB 代理,方法可以是任何可见性。为了确保 Spring AOP 能够成功代理方法,建议将被代理方法声明为 public。